From ab601665d17cf697ef79b5e00b88d21ca4860b81 Mon Sep 17 00:00:00 2001 From: Colin Nelson Date: Mon, 24 Sep 2018 09:54:25 -0700 Subject: [PATCH 01/91] Reduced cartservice Docker Image size (#46) Reduces docker image size for cartservice from ~2.36 GB to ~157 MB Fixes Issue #36 ![image-size](https://user-images.githubusercontent.com/7820716/45908973-37a31e00-bdb4-11e8-92d3-d84acfb1c10f.png) --- src/cartservice/Dockerfile | 33 +++++++++++++++++++++--------- src/cartservice/cartservice.csproj | 2 +- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/cartservice/Dockerfile b/src/cartservice/Dockerfile index 738aaf8..ae28b24 100644 --- a/src/cartservice/Dockerfile +++ b/src/cartservice/Dockerfile @@ -1,7 +1,6 @@ -# cartservice_probe -FROM golang:1.10 as builder +FROM golang:1.10 as probe RUN wget -qO/go/bin/dep https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 && \ - chmod +x /go/bin/dep + chmod +x /go/bin/dep ENV PROJECT github.com/GoogleCloudPlatform/microservices-demo/src/cartservice/probe WORKDIR /go/src/$PROJECT COPY probe/Gopkg.* ./ @@ -9,14 +8,28 @@ RUN dep ensure --vendor-only -v COPY ./probe ./ RUN go build -o /cartservice_probe . -# cartservice -FROM gcr.io/google-appengine/aspnetcore:2.1.0 -COPY --from=builder /cartservice_probe /cartservice_probe -RUN apt-get update && apt-get install net-tools telnet +FROM microsoft/dotnet:2.1-sdk-alpine as builder WORKDIR /app COPY . . RUN dotnet restore && \ dotnet build && \ - dotnet publish -WORKDIR /app/bin/Debug/netcoreapp2.0 -ENTRYPOINT ["dotnet", "cartservice.dll", "start"] + dotnet publish -c release -r linux-musl-x64 -o /cartservice + +# cartservice +FROM alpine:3.8 +# Add the probe +COPY --from=probe /cartservice_probe /cartservice_probe +# Dependencies for runtime +# busybox-extras => telnet +RUN apk add --no-cache \ + busybox-extras \ + libc6-compat \ + libunwind \ + libuuid \ + libgcc \ + libstdc++ \ + libintl \ + icu +WORKDIR /app +COPY --from=builder /cartservice . +ENTRYPOINT ["./cartservice", "start"] \ No newline at end of file diff --git a/src/cartservice/cartservice.csproj b/src/cartservice/cartservice.csproj index 2df2e2c..91a1c61 100644 --- a/src/cartservice/cartservice.csproj +++ b/src/cartservice/cartservice.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.0 + netcoreapp2.1 From 6460427bee57cd44b8a7bca10356ec20d940937d Mon Sep 17 00:00:00 2001 From: Yoshi Yamaguchi Date: Wed, 26 Sep 2018 08:43:17 +0900 Subject: [PATCH 02/91] Change log format to JSON and log destination to stdout (#48) * log: change log format to JSON payload for better log in Stackdriver change the log format in Go written service from text payload to JSON payload using 3rd party logging library (logrus). https://cloud.google.com/logging/docs/structured-logging https://github.com/sirupsen/logrus/blob/33a1e118e113c7d1dd24a80f80670864cd598519/json_formatter.go#L40-L49 Effected services are frontend, productcatalogservice, checkoutservice, and shippinservice. Also change target container registry and locust scenario for testing. * revert kubernetes manifests to point to the original container registry URLs * revert skaffold.yaml to point to the original registry * loadgenerator: revert locust settings --- src/checkoutservice/Gopkg.lock | 16 +++++++++ src/checkoutservice/Gopkg.toml | 4 +++ src/checkoutservice/main.go | 53 ++++++++++++++++++---------- src/frontend/main.go | 10 +++++- src/productcatalogservice/Gopkg.lock | 16 +++++++++ src/productcatalogservice/Gopkg.toml | 4 +++ src/productcatalogservice/server.go | 40 +++++++++++++-------- src/shippingservice/Gopkg.lock | 16 +++++++++ src/shippingservice/Gopkg.toml | 4 +++ src/shippingservice/main.go | 48 ++++++++++++++++--------- src/shippingservice/quote.go | 2 +- 11 files changed, 163 insertions(+), 50 deletions(-) diff --git a/src/checkoutservice/Gopkg.lock b/src/checkoutservice/Gopkg.lock index 036480d..364e527 100644 --- a/src/checkoutservice/Gopkg.lock +++ b/src/checkoutservice/Gopkg.lock @@ -56,6 +56,14 @@ revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f" version = "v2.0.0" +[[projects]] + digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc" + name = "github.com/sirupsen/logrus" + packages = ["."] + pruneopts = "UT" + revision = "3e01752db0189b9157070a0e1668a620f9a85da2" + version = "v1.0.6" + [[projects]] name = "go.opencensus.io" packages = [ @@ -77,6 +85,14 @@ revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89" version = "v0.16.0" +[[projects]] + branch = "master" + digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8" + name = "golang.org/x/crypto" + packages = ["ssh/terminal"] + pruneopts = "UT" + revision = "0e37d006457bf46f9e6692014ba72ef82c33022c" + [[projects]] branch = "master" name = "golang.org/x/net" diff --git a/src/checkoutservice/Gopkg.toml b/src/checkoutservice/Gopkg.toml index 0599867..8566b97 100644 --- a/src/checkoutservice/Gopkg.toml +++ b/src/checkoutservice/Gopkg.toml @@ -41,6 +41,10 @@ name = "github.com/google/uuid" version = "1.0.0" +[[constraint]] + name = "github.com/sirupsen/logrus" + version = "1.0.6" + [[constraint]] name = "go.opencensus.io" version = "0.16.0" diff --git a/src/checkoutservice/main.go b/src/checkoutservice/main.go index 116e051..cbc408f 100644 --- a/src/checkoutservice/main.go +++ b/src/checkoutservice/main.go @@ -17,7 +17,6 @@ package main import ( "context" "fmt" - "log" "net" "os" "time" @@ -25,6 +24,7 @@ import ( "cloud.google.com/go/profiler" "contrib.go.opencensus.io/exporter/stackdriver" "github.com/google/uuid" + "github.com/sirupsen/logrus" "go.opencensus.io/plugin/ocgrpc" "go.opencensus.io/stats/view" "go.opencensus.io/trace" @@ -42,6 +42,22 @@ const ( usdCurrency = "USD" ) +var log *logrus.Logger + +func init() { + log = logrus.New() + log.Level = logrus.DebugLevel + log.Formatter = &logrus.JSONFormatter{ + FieldMap: logrus.FieldMap{ + logrus.FieldKeyTime: "timestamp", + logrus.FieldKeyLevel: "severity", + logrus.FieldKeyMsg: "message", + }, + TimestampFormat: time.RFC3339Nano, + } + log.Out = os.Stdout +} + type checkoutService struct { productCatalogSvcAddr string cartSvcAddr string @@ -68,7 +84,7 @@ func main() { mustMapEnv(&svc.emailSvcAddr, "EMAIL_SERVICE_ADDR") mustMapEnv(&svc.paymentSvcAddr, "PAYMENT_SERVICE_ADDR") - log.Printf("service config: %+v", svc) + log.Infof("service config: %+v", svc) lis, err := net.Listen("tcp", fmt.Sprintf(":%s", port)) if err != nil { @@ -77,16 +93,17 @@ func main() { srv := grpc.NewServer(grpc.StatsHandler(&ocgrpc.ServerHandler{})) pb.RegisterCheckoutServiceServer(srv, svc) healthpb.RegisterHealthServer(srv, svc) - log.Printf("starting to listen on tcp: %q", lis.Addr().String()) - log.Fatal(srv.Serve(lis)) + log.Infof("starting to listen on tcp: %q", lis.Addr().String()) + err = srv.Serve(lis) + log.Fatal(err) } func initStats(exporter *stackdriver.Exporter) { view.RegisterExporter(exporter) if err := view.Register(ocgrpc.DefaultServerViews...); err != nil { - log.Printf("Error registering default server views") + log.Warn("Error registering default server views") } else { - log.Printf("Registered default server views") + log.Info("Registered default server views") } } @@ -96,21 +113,21 @@ func initTracing() { for i := 1; i <= 3; i++ { exporter, err := stackdriver.NewExporter(stackdriver.Options{}) if err != nil { - log.Printf("info: failed to initialize stackdriver exporter: %+v", err) + log.Infof("failed to initialize stackdriver exporter: %+v", err) } else { trace.RegisterExporter(exporter) trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) - log.Print("registered stackdriver tracing") + log.Info("registered stackdriver tracing") // Register the views to collect server stats. initStats(exporter) return } d := time.Second * 10 * time.Duration(i) - log.Printf("sleeping %v to retry initializing stackdriver exporter", d) + log.Infof("sleeping %v to retry initializing stackdriver exporter", d) time.Sleep(d) } - log.Printf("warning: could not initialize stackdriver exporter after retrying, giving up") + log.Warn("could not initialize stackdriver exporter after retrying, giving up") } func initProfiling(service, version string) { @@ -123,16 +140,16 @@ func initProfiling(service, version string) { // ProjectID must be set if not running on GCP. // ProjectID: "my-project", }); err != nil { - log.Printf("warn: failed to start profiler: %+v", err) + log.Warnf("failed to start profiler: %+v", err) } else { - log.Print("started stackdriver profiler") + log.Info("started stackdriver profiler") return } d := time.Second * 10 * time.Duration(i) - log.Printf("sleeping %v to retry initializing stackdriver profiler", d) + log.Infof("sleeping %v to retry initializing stackdriver profiler", d) time.Sleep(d) } - log.Printf("warning: could not initialize stackdriver profiler after retrying, giving up") + log.Warn("could not initialize stackdriver profiler after retrying, giving up") } func mustMapEnv(target *string, envKey string) { @@ -148,7 +165,7 @@ func (cs *checkoutService) Check(ctx context.Context, req *healthpb.HealthCheckR } func (cs *checkoutService) PlaceOrder(ctx context.Context, req *pb.PlaceOrderRequest) (*pb.PlaceOrderResponse, error) { - log.Printf("[PlaceOrder] user_id=%q user_currency=%q", req.UserId, req.UserCurrency) + log.Infof("[PlaceOrder] user_id=%q user_currency=%q", req.UserId, req.UserCurrency) orderID, err := uuid.NewUUID() if err != nil { @@ -172,7 +189,7 @@ func (cs *checkoutService) PlaceOrder(ctx context.Context, req *pb.PlaceOrderReq if err != nil { return nil, status.Errorf(codes.Internal, "failed to charge card: %+v", err) } - log.Printf("payment went through (transaction_id: %s)", txID) + log.Infof("payment went through (transaction_id: %s)", txID) shippingTrackingID, err := cs.shipOrder(ctx, req.Address, prep.cartItems) if err != nil { @@ -190,9 +207,9 @@ func (cs *checkoutService) PlaceOrder(ctx context.Context, req *pb.PlaceOrderReq } if err := cs.sendOrderConfirmation(ctx, req.Email, orderResult); err != nil { - log.Printf("failed to send order confirmation to %q: %+v", req.Email, err) + log.Warnf("failed to send order confirmation to %q: %+v", req.Email, err) } else { - log.Printf("order confirmation email sent to %q", req.Email) + log.Infof("order confirmation email sent to %q", req.Email) } resp := &pb.PlaceOrderResponse{Order: orderResult} return resp, nil diff --git a/src/frontend/main.go b/src/frontend/main.go index e70dac3..8939def 100644 --- a/src/frontend/main.go +++ b/src/frontend/main.go @@ -83,7 +83,15 @@ func main() { ctx := context.Background() log := logrus.New() log.Level = logrus.DebugLevel - log.Formatter = &logrus.TextFormatter{} + log.Formatter = &logrus.JSONFormatter{ + FieldMap: logrus.FieldMap{ + logrus.FieldKeyTime: "timestamp", + logrus.FieldKeyLevel: "severity", + logrus.FieldKeyMsg: "message", + }, + TimestampFormat: time.RFC3339Nano, + } + log.Out = os.Stdout go initProfiling(log, "frontend", "1.0.0") go initTracing(log) diff --git a/src/productcatalogservice/Gopkg.lock b/src/productcatalogservice/Gopkg.lock index b9a3bbd..e1c01e0 100644 --- a/src/productcatalogservice/Gopkg.lock +++ b/src/productcatalogservice/Gopkg.lock @@ -62,6 +62,14 @@ revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f" version = "v2.0.0" +[[projects]] + digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc" + name = "github.com/sirupsen/logrus" + packages = ["."] + pruneopts = "UT" + revision = "3e01752db0189b9157070a0e1668a620f9a85da2" + version = "v1.0.6" + [[projects]] name = "go.opencensus.io" packages = [ @@ -83,6 +91,14 @@ revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89" version = "v0.16.0" +[[projects]] + branch = "master" + digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8" + name = "golang.org/x/crypto" + packages = ["ssh/terminal"] + pruneopts = "UT" + revision = "0e37d006457bf46f9e6692014ba72ef82c33022c" + [[projects]] branch = "master" name = "golang.org/x/net" diff --git a/src/productcatalogservice/Gopkg.toml b/src/productcatalogservice/Gopkg.toml index a9b34ec..473b4b8 100644 --- a/src/productcatalogservice/Gopkg.toml +++ b/src/productcatalogservice/Gopkg.toml @@ -41,6 +41,10 @@ name = "github.com/google/go-cmp" version = "0.2.0" +[[constraint]] + name = "github.com/sirupsen/logrus" + version = "1.0.6" + [[constraint]] name = "go.opencensus.io" version = "0.16.0" diff --git a/src/productcatalogservice/server.go b/src/productcatalogservice/server.go index 6599877..0b8efef 100644 --- a/src/productcatalogservice/server.go +++ b/src/productcatalogservice/server.go @@ -20,8 +20,8 @@ import ( "flag" "fmt" "io/ioutil" - "log" "net" + "os" "strings" "time" @@ -31,6 +31,7 @@ import ( "cloud.google.com/go/profiler" "contrib.go.opencensus.io/exporter/stackdriver" "github.com/golang/protobuf/jsonpb" + "github.com/sirupsen/logrus" "go.opencensus.io/plugin/ocgrpc" "go.opencensus.io/stats/view" "go.opencensus.io/trace" @@ -41,6 +42,7 @@ import ( var ( catalogJSON []byte + log *logrus.Logger port = flag.Int("port", 3550, "port to listen at") ) @@ -51,7 +53,17 @@ func init() { log.Fatalf("failed to open product catalog json file: %v", err) } catalogJSON = c - log.Printf("successfully parsed product catalog json") + log = logrus.New() + log.Formatter = &logrus.JSONFormatter{ + FieldMap: logrus.FieldMap{ + logrus.FieldKeyTime: "timestamp", + logrus.FieldKeyLevel: "severity", + logrus.FieldKeyMsg: "message", + }, + TimestampFormat: time.RFC3339Nano, + } + log.Out = os.Stdout + log.Info("successfully parsed product catalog json") } func main() { @@ -59,7 +71,7 @@ func main() { go initProfiling("productcatalogservice", "1.0.0") flag.Parse() - log.Printf("starting grpc server at :%d", *port) + log.Infof("starting grpc server at :%d", *port) run(*port) select {} } @@ -80,9 +92,9 @@ func run(port int) string { func initStats(exporter *stackdriver.Exporter) { view.RegisterExporter(exporter) if err := view.Register(ocgrpc.DefaultServerViews...); err != nil { - log.Printf("Error registering default server views") + log.Info("Error registering default server views") } else { - log.Printf("Registered default server views") + log.Info("Registered default server views") } } @@ -92,21 +104,21 @@ func initTracing() { for i := 1; i <= 3; i++ { exporter, err := stackdriver.NewExporter(stackdriver.Options{}) if err != nil { - log.Printf("info: failed to initialize stackdriver exporter: %+v", err) + log.Warnf("failed to initialize stackdriver exporter: %+v", err) } else { trace.RegisterExporter(exporter) trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) - log.Print("registered stackdriver tracing") + log.Info("registered stackdriver tracing") // Register the views to collect server stats. initStats(exporter) return } d := time.Second * 10 * time.Duration(i) - log.Printf("sleeping %v to retry initializing stackdriver exporter", d) + log.Infof("sleeping %v to retry initializing stackdriver exporter", d) time.Sleep(d) } - log.Printf("warning: could not initialize stackdriver exporter after retrying, giving up") + log.Warn("could not initialize stackdriver exporter after retrying, giving up") } func initProfiling(service, version string) { @@ -119,16 +131,16 @@ func initProfiling(service, version string) { // ProjectID must be set if not running on GCP. // ProjectID: "my-project", }); err != nil { - log.Printf("warn: failed to start profiler: %+v", err) + log.Warnf("failed to start profiler: %+v", err) } else { - log.Print("started stackdriver profiler") + log.Info("started stackdriver profiler") return } d := time.Second * 10 * time.Duration(i) - log.Printf("sleeping %v to retry initializing stackdriver profiler", d) + log.Infof("sleeping %v to retry initializing stackdriver profiler", d) time.Sleep(d) } - log.Printf("warning: could not initialize stackdriver profiler after retrying, giving up") + log.Warn("could not initialize stackdriver profiler after retrying, giving up") } type productCatalog struct{} @@ -137,7 +149,7 @@ func parseCatalog() []*pb.Product { var cat pb.ListProductsResponse if err := jsonpb.Unmarshal(bytes.NewReader(catalogJSON), &cat); err != nil { - log.Printf("warning: failed to parse the catalog JSON: %v", err) + log.Warnf("failed to parse the catalog JSON: %v", err) return nil } return cat.Products diff --git a/src/shippingservice/Gopkg.lock b/src/shippingservice/Gopkg.lock index 998e4eb..9250ec1 100644 --- a/src/shippingservice/Gopkg.lock +++ b/src/shippingservice/Gopkg.lock @@ -50,6 +50,14 @@ revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f" version = "v2.0.0" +[[projects]] + digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc" + name = "github.com/sirupsen/logrus" + packages = ["."] + pruneopts = "UT" + revision = "3e01752db0189b9157070a0e1668a620f9a85da2" + version = "v1.0.6" + [[projects]] name = "go.opencensus.io" packages = [ @@ -71,6 +79,14 @@ revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89" version = "v0.16.0" +[[projects]] + branch = "master" + digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8" + name = "golang.org/x/crypto" + packages = ["ssh/terminal"] + pruneopts = "UT" + revision = "0e37d006457bf46f9e6692014ba72ef82c33022c" + [[projects]] branch = "master" name = "golang.org/x/net" diff --git a/src/shippingservice/Gopkg.toml b/src/shippingservice/Gopkg.toml index eafb618..90a3ce9 100644 --- a/src/shippingservice/Gopkg.toml +++ b/src/shippingservice/Gopkg.toml @@ -37,6 +37,10 @@ name = "github.com/golang/protobuf" version = "1.2.0" +[[constraint]] + name = "github.com/sirupsen/logrus" + version = "1.0.6" + [[constraint]] name = "go.opencensus.io" version = "0.16.0" diff --git a/src/shippingservice/main.go b/src/shippingservice/main.go index f82787a..35f7ed4 100644 --- a/src/shippingservice/main.go +++ b/src/shippingservice/main.go @@ -16,13 +16,13 @@ package main import ( "fmt" - "log" "net" "os" "time" "cloud.google.com/go/profiler" "contrib.go.opencensus.io/exporter/stackdriver" + "github.com/sirupsen/logrus" "go.opencensus.io/plugin/ocgrpc" "go.opencensus.io/stats/view" "go.opencensus.io/trace" @@ -38,6 +38,22 @@ const ( defaultPort = "50051" ) +var log *logrus.Logger + +func init() { + log = logrus.New() + log.Level = logrus.DebugLevel + log.Formatter = &logrus.JSONFormatter{ + FieldMap: logrus.FieldMap{ + logrus.FieldKeyTime: "timestamp", + logrus.FieldKeyLevel: "severity", + logrus.FieldKeyMsg: "message", + }, + TimestampFormat: time.RFC3339Nano, + } + log.Out = os.Stdout +} + func main() { go initTracing() go initProfiling("shippingservice", "1.0.0") @@ -56,7 +72,7 @@ func main() { svc := &server{} pb.RegisterShippingServiceServer(srv, svc) healthpb.RegisterHealthServer(srv, svc) - log.Printf("Shipping Service listening on port %s", port) + log.Infof("Shipping Service listening on port %s", port) // Register reflection service on gRPC server. reflection.Register(srv) @@ -75,8 +91,8 @@ func (s *server) Check(ctx context.Context, req *healthpb.HealthCheckRequest) (* // GetQuote produces a shipping quote (cost) in USD. func (s *server) GetQuote(ctx context.Context, in *pb.GetQuoteRequest) (*pb.GetQuoteResponse, error) { - log.Printf("[GetQuote] received request") - defer log.Printf("[GetQuote] completed request") + log.Info("[GetQuote] received request") + defer log.Info("[GetQuote] completed request") // 1. Our quote system requires the total number of items to be shipped. count := 0 @@ -100,8 +116,8 @@ func (s *server) GetQuote(ctx context.Context, in *pb.GetQuoteRequest) (*pb.GetQ // ShipOrder mocks that the requested items will be shipped. // It supplies a tracking ID for notional lookup of shipment delivery status. func (s *server) ShipOrder(ctx context.Context, in *pb.ShipOrderRequest) (*pb.ShipOrderResponse, error) { - log.Printf("[ShipOrder] received request") - defer log.Printf("[ShipOrder] completed request") + log.Info("[ShipOrder] received request") + defer log.Info("[ShipOrder] completed request") // 1. Create a Tracking ID baseAddress := fmt.Sprintf("%s, %s, %s", in.Address.StreetAddress, in.Address.City, in.Address.State) id := CreateTrackingId(baseAddress) @@ -115,9 +131,9 @@ func (s *server) ShipOrder(ctx context.Context, in *pb.ShipOrderRequest) (*pb.Sh func initStats(exporter *stackdriver.Exporter) { view.RegisterExporter(exporter) if err := view.Register(ocgrpc.DefaultServerViews...); err != nil { - log.Printf("Error registering default server views") + log.Warn("Error registering default server views") } else { - log.Printf("Registered default server views") + log.Info("Registered default server views") } } @@ -127,21 +143,21 @@ func initTracing() { for i := 1; i <= 3; i++ { exporter, err := stackdriver.NewExporter(stackdriver.Options{}) if err != nil { - log.Printf("info: failed to initialize stackdriver exporter: %+v", err) + log.Warnf("failed to initialize stackdriver exporter: %+v", err) } else { trace.RegisterExporter(exporter) trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) - log.Print("registered stackdriver tracing") + log.Info("registered stackdriver tracing") // Register the views to collect server stats. initStats(exporter) return } d := time.Second * 10 * time.Duration(i) - log.Printf("sleeping %v to retry initializing stackdriver exporter", d) + log.Infof("sleeping %v to retry initializing stackdriver exporter", d) time.Sleep(d) } - log.Printf("warning: could not initialize stackdriver exporter after retrying, giving up") + log.Warn("could not initialize stackdriver exporter after retrying, giving up") } func initProfiling(service, version string) { @@ -154,14 +170,14 @@ func initProfiling(service, version string) { // ProjectID must be set if not running on GCP. // ProjectID: "my-project", }); err != nil { - log.Printf("warn: failed to start profiler: %+v", err) + log.Warnf("failed to start profiler: %+v", err) } else { - log.Print("started stackdriver profiler") + log.Info("started stackdriver profiler") return } d := time.Second * 10 * time.Duration(i) - log.Printf("sleeping %v to retry initializing stackdriver profiler", d) + log.Infof("sleeping %v to retry initializing stackdriver profiler", d) time.Sleep(d) } - log.Printf("warning: could not initialize stackdriver profiler after retrying, giving up") + log.Warn("could not initialize stackdriver profiler after retrying, giving up") } diff --git a/src/shippingservice/quote.go b/src/shippingservice/quote.go index 09c040a..3732098 100644 --- a/src/shippingservice/quote.go +++ b/src/shippingservice/quote.go @@ -50,6 +50,6 @@ func quoteByCountFloat(count int) float64 { return 0 } count64 := float64(count) - var p float64 = 1 + (count64 * 0.2) + var p = 1 + (count64 * 0.2) return count64 + math.Pow(3, p) } From 29242504491623edd1e6089c104c6fbce24646f7 Mon Sep 17 00:00:00 2001 From: Colin Nelson Date: Tue, 25 Sep 2018 16:43:39 -0700 Subject: [PATCH 03/91] emailservice Image Optimization (#51) Reduce docker image for emailservice to ~240 MB (down from ~ 1.31 GB) Main application (`email_server.py`) now runs as python 2.7. Before we had both Python 2.7 and Python 3 installed in the image. Switched to using `python:2.7-alpine3.8` as the base image, and used multi-stage dockerfiles to keep dependencies minimal. Fixes #49 From my shell: ``` $ docker build -t emailservice:dev . && docker run -it emailservice:dev Sending build context to Docker daemon 97.28kB Step 1/17 : FROM python:2.7-alpine3.8 as base ---> b2bc7255b42c Step 2/17 : FROM base as builder ---> b2bc7255b42c Step 3/17 : RUN apk add --update --no-cache gcc linux-headers make musl-dev python-dev g++ cairo-dev cairo openssl-dev gobject-introspection-dev ---> Using cache ---> 6daf3d9fe49a Step 4/17 : ENV GRPC_PYTHON_VERSION 1.15.0 ---> Using cache ---> 3e33d97d9580 Step 5/17 : RUN python -m pip install --upgrade pip ---> Using cache ---> e8fa3879c282 Step 6/17 : RUN pip install grpcio==${GRPC_PYTHON_VERSION} grpcio-tools==${GRPC_PYTHON_VERSION} ---> Using cache ---> c6fba7743eed Step 7/17 : COPY requirements.txt . ---> Using cache ---> 1f6b0a444980 Step 8/17 : RUN pip install -r requirements.txt ---> Using cache ---> 8cc0a7af6aa8 Step 9/17 : FROM base as final ---> b2bc7255b42c Step 10/17 : RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && chmod +x /bin/grpc_health_probe ---> Using cache ---> e954a0384081 Step 11/17 : ENV PYTHONUNBUFFERED=0 ---> Using cache ---> 64ece3d72a66 Step 12/17 : WORKDIR /email_server ---> Using cache ---> 27b34dc14492 Step 13/17 : COPY --from=builder /usr/local/lib/python2.7/ /usr/local/lib/python2.7/ ---> Using cache ---> 60035ec8dfd4 Step 14/17 : RUN apk add --no-cache libstdc++ ---> Using cache ---> 920be90c126e Step 15/17 : COPY . . ---> Using cache ---> 9541bed2d7a0 Step 16/17 : EXPOSE 8080 ---> Using cache ---> 48fbeaa852b9 Step 17/17 : ENTRYPOINT [ "python", "email_server.py" ] ---> Using cache ---> ff317770992d Successfully built ff317770992d Successfully tagged emailservice:dev starting the email service in dummy mode. listening on port: 8080 ``` --- src/emailservice/Dockerfile | 46 +++++++++++++++++++++---------- src/emailservice/requirements.txt | 40 +++++++++++++++++---------- 2 files changed, 57 insertions(+), 29 deletions(-) diff --git a/src/emailservice/Dockerfile b/src/emailservice/Dockerfile index 8395949..5a1bb22 100644 --- a/src/emailservice/Dockerfile +++ b/src/emailservice/Dockerfile @@ -1,27 +1,45 @@ +FROM python:3-alpine as base +FROM base as builder -# Use the grpc.io provided Python image as the base image -FROM grpc/python:1.0 +# gRPC and app deps +RUN apk add --update --no-cache \ + gcc \ + linux-headers \ + make \ + musl-dev \ + python-dev \ + g++ \ + # App Deps + cairo-dev \ + cairo \ + openssl-dev \ + gobject-introspection-dev -# download the grpc health probe +# get packages +COPY requirements.txt . +RUN pip install -r requirements.txt + +FROM base as final + +# Enable unbuffered logging +ENV PYTHONUNBUFFERED=1 + +# Download the grpc health probe RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe -# show python logs as they occur -ENV PYTHONUNBUFFERED=0 - -# install pip for python3 -RUN apt-get -qqy update && \ - apt-get -qqy install python3-pip - -# get packages WORKDIR /email_server -COPY requirements.txt . -RUN pip3 install -r requirements.txt + +# Grab packages from builder +COPY --from=builder /usr/local/lib/python3.7/ /usr/local/lib/python3.7/ + +# Need libstdc++ for grpc +RUN apk add --no-cache libstdc++ # Add the application COPY . . EXPOSE 8080 -ENTRYPOINT [ "python3", "email_server.py" ] +ENTRYPOINT [ "python", "email_server.py" ] \ No newline at end of file diff --git a/src/emailservice/requirements.txt b/src/emailservice/requirements.txt index de1567e..ca3f1c3 100644 --- a/src/emailservice/requirements.txt +++ b/src/emailservice/requirements.txt @@ -1,31 +1,41 @@ +asn1crypto==0.24.0 cachetools==2.1.0 -certifi==2018.4.16 +certifi==2018.8.24 +cffi==1.11.5 chardet==3.0.4 -cryptography==1.7.1 -google-api-core==1.2.1 -google-auth==1.5.0 +configparser==3.5.0 +cryptography==2.3.1 +entrypoints==0.2.3 +enum34==1.1.6 +futures==3.1.1 +google-api-core==1.4.0 +google-auth==1.5.1 google-cloud-core==0.28.1 google-cloud-trace==0.19.0 googleapis-common-protos==1.5.3 grpc-google-iam-v1==0.11.4 grpcio==1.12.1 -grpcio-health-checking==1.14.1 +grpcio-health-checking==1.12.1 grpcio-tools==1.12.1 idna==2.7 +ipaddress==1.0.22 +jeepney==0.4 Jinja2==2.10 -keyring==10.1 -keyrings.alt==1.3 +keyring==15.1.0 +keyrings.alt==3.1 MarkupSafe==1.0 -opencensus==0.1.5 -protobuf==3.6.0 -pyasn1==0.4.3 +opencensus==0.1.7 +protobuf==3.6.1 +pyasn1==0.4.4 pyasn1-modules==0.2.2 +pycairo==1.17.1 +pycparser==2.19 pycrypto==2.6.1 -pygobject==3.22.0 +PyGObject==3.30.1 pytz==2018.5 -pyxdg==0.25 +pyxdg==0.26 requests==2.19.1 -rsa==3.4.2 -SecretStorage==2.3.1 +rsa==4.0 +SecretStorage==3.1.0 six==1.11.0 -urllib3==1.23 +urllib3==1.23 \ No newline at end of file From 1263da2172f9f6100dfb1a148d7f60e0e15183a0 Mon Sep 17 00:00:00 2001 From: Colin Nelson Date: Wed, 26 Sep 2018 09:18:23 -0700 Subject: [PATCH 04/91] Reduced loadgenerator's image size (#52) Reduce loadgenerator's image size from ~972MB to ~117MB * Changed loadgen.sh to execute with `/bin/sh` as opposed to `/bin/bash` * Changed dockerfile to a multi stage build * Changed base image to `python:3-alpine` as opposed to `python:3.6` --- src/loadgenerator/Dockerfile | 18 ++++++++++++++++-- src/loadgenerator/loadgen.sh | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/loadgenerator/Dockerfile b/src/loadgenerator/Dockerfile index a90c23e..b0004cf 100644 --- a/src/loadgenerator/Dockerfile +++ b/src/loadgenerator/Dockerfile @@ -1,7 +1,21 @@ -FROM python:3.6 +FROM python:3-alpine as base + +FROM base as builder + +RUN apk add --update --no-cache \ + gcc \ + linux-headers \ + make \ + musl-dev \ + python-dev \ + g++ COPY requirements.txt . -RUN pip install -r requirements.txt + +RUN pip install --install-option="--prefix=/install" -r requirements.txt + +FROM base +COPY --from=builder /install /usr/local COPY . . ENTRYPOINT ./loadgen.sh diff --git a/src/loadgenerator/loadgen.sh b/src/loadgenerator/loadgen.sh index 514174e..2a68db7 100755 --- a/src/loadgenerator/loadgen.sh +++ b/src/loadgenerator/loadgen.sh @@ -1,4 +1,4 @@ -#!/bin/bash -eu +#!/bin/sh -eu # # Copyright 2018 Google LLC # From 7ced638e2f30dc5fb84bb1c0613ebf8de69dcde6 Mon Sep 17 00:00:00 2001 From: Colin Nelson Date: Wed, 26 Sep 2018 10:58:33 -0700 Subject: [PATCH 05/91] paymentservice: Docker image size optimization (#53) Reduced docker image size to ~153MB (was ~781MB). * Uses alpine linux and multi stage builds. * Changed `CMD` to `ENTRYPOINT` --- src/paymentservice/Dockerfile | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/paymentservice/Dockerfile b/src/paymentservice/Dockerfile index abe0eba..5785d35 100644 --- a/src/paymentservice/Dockerfile +++ b/src/paymentservice/Dockerfile @@ -1,7 +1,13 @@ -FROM node:8 -RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ - wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ - chmod +x /bin/grpc_health_probe +FROM node:8-alpine as base + +FROM base as builder + +# Some packages (e.g. @google-cloud/profiler) require additional +# deps for post-install scripts +RUN apk add --update --no-cache \ + python \ + make \ + g++ WORKDIR /usr/src/app @@ -9,8 +15,18 @@ COPY package*.json ./ RUN npm install --only=production +FROM base + +RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ + wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ + chmod +x /bin/grpc_health_probe + +WORKDIR /usr/src/app + +COPY --from=builder /usr/src/app/node_modules ./node_modules + COPY . . EXPOSE 50051 -CMD [ "node", "index.js" ] +ENTRYPOINT [ "node", "index.js" ] From 3be5c82c73ff5e3343fe2926938fb52ec97f2033 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Wed, 26 Sep 2018 12:22:51 -0700 Subject: [PATCH 06/91] skaffold: add gcb timeout (default is too low) Signed-off-by: Ahmet Alp Balkan --- skaffold.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/skaffold.yaml b/skaffold.yaml index bd04f86..9bf9d46 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -66,3 +66,4 @@ profiles: googleCloudBuild: diskSizeGb: 300 machineType: "N1_HIGHCPU_32" + timeout: 4000s From c61a8aea4ce316307c81d8e433fad67fd7fe6329 Mon Sep 17 00:00:00 2001 From: sebright Date: Wed, 26 Sep 2018 19:33:52 -0700 Subject: [PATCH 07/91] adservice: upgrade grpc-java to 1.15.0 (#54) Upgrading grpc-java fixed an error that I encountered when I tried modifying the adservice to write logs to Stackdriver with google-cloud-logging ("`com.google.cloud.logging.LoggingException: io.grpc.StatusRuntimeException: UNAUTHENTICATED: Credentials require channel with PRIVACY_AND_INTEGRITY security level. Observed security level: NONE`"). --- src/adservice/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adservice/build.gradle b/src/adservice/build.gradle index 47653ac..2c6bce7 100644 --- a/src/adservice/build.gradle +++ b/src/adservice/build.gradle @@ -26,7 +26,7 @@ group = "adservice" version = "0.1.0-SNAPSHOT" // CURRENT_OPENCENSUS_VERSION def opencensusVersion = "0.15.0" // LATEST_OPENCENSUS_RELEASE_VERSION -def grpcVersion = "1.10.1" // CURRENT_GRPC_VERSION +def grpcVersion = "1.15.0" // CURRENT_GRPC_VERSION def prometheusVersion = "0.3.0" tasks.withType(JavaCompile) { From be65dd1fcd739d48e51ff60e3267cdc6b2b878f6 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Fri, 28 Sep 2018 12:52:06 -0700 Subject: [PATCH 08/91] cartservice: fix health Check() method signature (#57) - Use the method provided in HealthBase - Use the same version of GrpcHealth as Grpc core. Fixes #50. --- src/cartservice/HealthImpl.cs | 10 ++++++---- src/cartservice/cartservice.csproj | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/cartservice/HealthImpl.cs b/src/cartservice/HealthImpl.cs index 5ac6551..f231c7c 100644 --- a/src/cartservice/HealthImpl.cs +++ b/src/cartservice/HealthImpl.cs @@ -1,5 +1,7 @@ using System; +using System.Threading.Tasks; using cartservice.interfaces; +using Grpc.Core; using Grpc.Health.V1; using StackExchange.Redis; using static Grpc.Health.V1.Health; @@ -11,12 +13,12 @@ namespace cartservice { this.dependency = dependency; } - public HealthCheckResponse Check (HealthCheckRequest request) { + public override Task Check(HealthCheckRequest request, ServerCallContext context){ Console.WriteLine ("Checking CartService Health"); - return new HealthCheckResponse { + return Task.FromResult(new HealthCheckResponse { Status = dependency.Ping() ? HealthCheckResponse.Types.ServingStatus.Serving : HealthCheckResponse.Types.ServingStatus.NotServing - }; + }); } } -} \ No newline at end of file +} diff --git a/src/cartservice/cartservice.csproj b/src/cartservice/cartservice.csproj index 91a1c61..3fea4a1 100644 --- a/src/cartservice/cartservice.csproj +++ b/src/cartservice/cartservice.csproj @@ -10,7 +10,7 @@ - + From 34f8fb18aa3a72c63e5c43780f27bc8ed1ad9748 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Sun, 30 Sep 2018 16:49:08 -0700 Subject: [PATCH 09/91] Add development principles (#56) --- CONTRIBUTING.md | 6 +++++ docs/development-principles.md | 44 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 docs/development-principles.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 939e534..1dce611 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,6 +3,12 @@ We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow. +## Development Principles (for Googlers) + +There are a few principles for developing or refactoring the service +implementations. Read the [Development Principles +Guide](./docs/development-principles.md). + ## Contributor License Agreement Contributions to this project must be accompanied by a Contributor License diff --git a/docs/development-principles.md b/docs/development-principles.md new file mode 100644 index 0000000..0deae0c --- /dev/null +++ b/docs/development-principles.md @@ -0,0 +1,44 @@ +# Development Principles + +> **Note:** This document outlines guidances behind some development decisions +> behind the Hipster Shop demo application. + +### Minimal configuration + +Running the demo locally or on GCP should not require minimal to no +configuration unless absolutely necessary to run critical parts of the demo. + +Configuration that takes multiple steps, especially such as creating service +accounts should be avoided. + +### App must work well outside GCP + +Demo application should work reasonably well when it is not deployed to GCP +services. The experience of running the application locally or on GCP should +be close. + +For example: +- OpenCensus prints the traces to stdout when it cannot connect to GCP. +- Stackdriver Debugging tries connecting to GCP multiple times, eventually gives + up. + +### Running on GCP must not reduce functionality + +Running the demo on the GCP must not reduce/lose any of the capabilities +developers have when running locally. + +For example: Logs should still be printed to stdout/stderr even though logs are +uploaded to Stackdriver Logging when on GCP, so that developers can use "kubectl +logs" to diagnose each container. + +### Microservice implementations should not be complex + +Each service should provide a minimal implementation and try to avoid +unnecessary code and logic that's not executed. + +Keep in mind that any service implementation is a decent example of “a GRPC +application that runs on Kubernetes”. Keeping the source code short and +navigable will serve this purpose. + +It is okay to have intentional inefficiencies in the code as they help +illustrate the capabilities of profiling and diagnostics offerings. From 86c8c06cc1e0aa616796a19493f042466d93098d Mon Sep 17 00:00:00 2001 From: sebright Date: Mon, 1 Oct 2018 21:33:25 -0700 Subject: [PATCH 10/91] pb: add "categories" field to Product (#60) This field can be used as the context keys to look up relevant ads in the ad service. /cc @rghetia I also ran the genproto.sh scripts for the Java and Go services and included those changes in the second commit. I encountered an issue when I ran genproto.sh for the recommendation service, and I'm still looking into it. --- pb/demo.proto | 4 + src/adservice/src/main/proto/demo.proto | 4 + src/frontend/genproto/demo.pb.go | 445 +++++---- src/productcatalogservice/genproto/demo.pb.go | 880 ++++++++++-------- 4 files changed, 745 insertions(+), 588 deletions(-) diff --git a/pb/demo.proto b/pb/demo.proto index 09e5e4d..46e6b7c 100644 --- a/pb/demo.proto +++ b/pb/demo.proto @@ -64,6 +64,10 @@ message Product { string description = 3; string picture = 4; Money price_usd = 5; + + // Categories such as "vintage" or "gardening" that can be used to look up + // other related products. + repeated string categories = 6; } message ListProductsResponse { diff --git a/src/adservice/src/main/proto/demo.proto b/src/adservice/src/main/proto/demo.proto index 09e5e4d..46e6b7c 100644 --- a/src/adservice/src/main/proto/demo.proto +++ b/src/adservice/src/main/proto/demo.proto @@ -64,6 +64,10 @@ message Product { string description = 3; string picture = 4; Money price_usd = 5; + + // Categories such as "vintage" or "gardening" that can be used to look up + // other related products. + repeated string categories = 6; } message ListProductsResponse { diff --git a/src/frontend/genproto/demo.pb.go b/src/frontend/genproto/demo.pb.go index e63e268..f59af20 100644 --- a/src/frontend/genproto/demo.pb.go +++ b/src/frontend/genproto/demo.pb.go @@ -3,9 +3,11 @@ package hipstershop -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) import ( context "golang.org/x/net/context" @@ -35,16 +37,17 @@ func (m *CartItem) Reset() { *m = CartItem{} } func (m *CartItem) String() string { return proto.CompactTextString(m) } func (*CartItem) ProtoMessage() {} func (*CartItem) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{0} + return fileDescriptor_ca53982754088a9d, []int{0} } + func (m *CartItem) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CartItem.Unmarshal(m, b) } func (m *CartItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CartItem.Marshal(b, m, deterministic) } -func (dst *CartItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_CartItem.Merge(dst, src) +func (m *CartItem) XXX_Merge(src proto.Message) { + xxx_messageInfo_CartItem.Merge(m, src) } func (m *CartItem) XXX_Size() int { return xxx_messageInfo_CartItem.Size(m) @@ -81,16 +84,17 @@ func (m *AddItemRequest) Reset() { *m = AddItemRequest{} } func (m *AddItemRequest) String() string { return proto.CompactTextString(m) } func (*AddItemRequest) ProtoMessage() {} func (*AddItemRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{1} + return fileDescriptor_ca53982754088a9d, []int{1} } + func (m *AddItemRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AddItemRequest.Unmarshal(m, b) } func (m *AddItemRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_AddItemRequest.Marshal(b, m, deterministic) } -func (dst *AddItemRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_AddItemRequest.Merge(dst, src) +func (m *AddItemRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddItemRequest.Merge(m, src) } func (m *AddItemRequest) XXX_Size() int { return xxx_messageInfo_AddItemRequest.Size(m) @@ -126,16 +130,17 @@ func (m *EmptyCartRequest) Reset() { *m = EmptyCartRequest{} } func (m *EmptyCartRequest) String() string { return proto.CompactTextString(m) } func (*EmptyCartRequest) ProtoMessage() {} func (*EmptyCartRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{2} + return fileDescriptor_ca53982754088a9d, []int{2} } + func (m *EmptyCartRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EmptyCartRequest.Unmarshal(m, b) } func (m *EmptyCartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_EmptyCartRequest.Marshal(b, m, deterministic) } -func (dst *EmptyCartRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_EmptyCartRequest.Merge(dst, src) +func (m *EmptyCartRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_EmptyCartRequest.Merge(m, src) } func (m *EmptyCartRequest) XXX_Size() int { return xxx_messageInfo_EmptyCartRequest.Size(m) @@ -164,16 +169,17 @@ func (m *GetCartRequest) Reset() { *m = GetCartRequest{} } func (m *GetCartRequest) String() string { return proto.CompactTextString(m) } func (*GetCartRequest) ProtoMessage() {} func (*GetCartRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{3} + return fileDescriptor_ca53982754088a9d, []int{3} } + func (m *GetCartRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetCartRequest.Unmarshal(m, b) } func (m *GetCartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetCartRequest.Marshal(b, m, deterministic) } -func (dst *GetCartRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetCartRequest.Merge(dst, src) +func (m *GetCartRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetCartRequest.Merge(m, src) } func (m *GetCartRequest) XXX_Size() int { return xxx_messageInfo_GetCartRequest.Size(m) @@ -203,16 +209,17 @@ func (m *Cart) Reset() { *m = Cart{} } func (m *Cart) String() string { return proto.CompactTextString(m) } func (*Cart) ProtoMessage() {} func (*Cart) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{4} + return fileDescriptor_ca53982754088a9d, []int{4} } + func (m *Cart) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Cart.Unmarshal(m, b) } func (m *Cart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Cart.Marshal(b, m, deterministic) } -func (dst *Cart) XXX_Merge(src proto.Message) { - xxx_messageInfo_Cart.Merge(dst, src) +func (m *Cart) XXX_Merge(src proto.Message) { + xxx_messageInfo_Cart.Merge(m, src) } func (m *Cart) XXX_Size() int { return xxx_messageInfo_Cart.Size(m) @@ -247,16 +254,17 @@ func (m *Empty) Reset() { *m = Empty{} } func (m *Empty) String() string { return proto.CompactTextString(m) } func (*Empty) ProtoMessage() {} func (*Empty) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{5} + return fileDescriptor_ca53982754088a9d, []int{5} } + func (m *Empty) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Empty.Unmarshal(m, b) } func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Empty.Marshal(b, m, deterministic) } -func (dst *Empty) XXX_Merge(src proto.Message) { - xxx_messageInfo_Empty.Merge(dst, src) +func (m *Empty) XXX_Merge(src proto.Message) { + xxx_messageInfo_Empty.Merge(m, src) } func (m *Empty) XXX_Size() int { return xxx_messageInfo_Empty.Size(m) @@ -279,16 +287,17 @@ func (m *ListRecommendationsRequest) Reset() { *m = ListRecommendationsR func (m *ListRecommendationsRequest) String() string { return proto.CompactTextString(m) } func (*ListRecommendationsRequest) ProtoMessage() {} func (*ListRecommendationsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{6} + return fileDescriptor_ca53982754088a9d, []int{6} } + func (m *ListRecommendationsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListRecommendationsRequest.Unmarshal(m, b) } func (m *ListRecommendationsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListRecommendationsRequest.Marshal(b, m, deterministic) } -func (dst *ListRecommendationsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListRecommendationsRequest.Merge(dst, src) +func (m *ListRecommendationsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListRecommendationsRequest.Merge(m, src) } func (m *ListRecommendationsRequest) XXX_Size() int { return xxx_messageInfo_ListRecommendationsRequest.Size(m) @@ -324,16 +333,17 @@ func (m *ListRecommendationsResponse) Reset() { *m = ListRecommendations func (m *ListRecommendationsResponse) String() string { return proto.CompactTextString(m) } func (*ListRecommendationsResponse) ProtoMessage() {} func (*ListRecommendationsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{7} + return fileDescriptor_ca53982754088a9d, []int{7} } + func (m *ListRecommendationsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListRecommendationsResponse.Unmarshal(m, b) } func (m *ListRecommendationsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListRecommendationsResponse.Marshal(b, m, deterministic) } -func (dst *ListRecommendationsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListRecommendationsResponse.Merge(dst, src) +func (m *ListRecommendationsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListRecommendationsResponse.Merge(m, src) } func (m *ListRecommendationsResponse) XXX_Size() int { return xxx_messageInfo_ListRecommendationsResponse.Size(m) @@ -352,11 +362,14 @@ func (m *ListRecommendationsResponse) GetProductIds() []string { } type Product struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` - Picture string `protobuf:"bytes,4,opt,name=picture,proto3" json:"picture,omitempty"` - PriceUsd *Money `protobuf:"bytes,5,opt,name=price_usd,json=priceUsd,proto3" json:"price_usd,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + Picture string `protobuf:"bytes,4,opt,name=picture,proto3" json:"picture,omitempty"` + PriceUsd *Money `protobuf:"bytes,5,opt,name=price_usd,json=priceUsd,proto3" json:"price_usd,omitempty"` + // Categories such as "vintage" or "gardening" that can be used to look up + // other related products. + Categories []string `protobuf:"bytes,6,rep,name=categories,proto3" json:"categories,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -366,16 +379,17 @@ func (m *Product) Reset() { *m = Product{} } func (m *Product) String() string { return proto.CompactTextString(m) } func (*Product) ProtoMessage() {} func (*Product) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{8} + return fileDescriptor_ca53982754088a9d, []int{8} } + func (m *Product) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Product.Unmarshal(m, b) } func (m *Product) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Product.Marshal(b, m, deterministic) } -func (dst *Product) XXX_Merge(src proto.Message) { - xxx_messageInfo_Product.Merge(dst, src) +func (m *Product) XXX_Merge(src proto.Message) { + xxx_messageInfo_Product.Merge(m, src) } func (m *Product) XXX_Size() int { return xxx_messageInfo_Product.Size(m) @@ -421,6 +435,13 @@ func (m *Product) GetPriceUsd() *Money { return nil } +func (m *Product) GetCategories() []string { + if m != nil { + return m.Categories + } + return nil +} + type ListProductsResponse struct { Products []*Product `protobuf:"bytes,1,rep,name=products,proto3" json:"products,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -432,16 +453,17 @@ func (m *ListProductsResponse) Reset() { *m = ListProductsResponse{} } func (m *ListProductsResponse) String() string { return proto.CompactTextString(m) } func (*ListProductsResponse) ProtoMessage() {} func (*ListProductsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{9} + return fileDescriptor_ca53982754088a9d, []int{9} } + func (m *ListProductsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListProductsResponse.Unmarshal(m, b) } func (m *ListProductsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListProductsResponse.Marshal(b, m, deterministic) } -func (dst *ListProductsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListProductsResponse.Merge(dst, src) +func (m *ListProductsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListProductsResponse.Merge(m, src) } func (m *ListProductsResponse) XXX_Size() int { return xxx_messageInfo_ListProductsResponse.Size(m) @@ -470,16 +492,17 @@ func (m *GetProductRequest) Reset() { *m = GetProductRequest{} } func (m *GetProductRequest) String() string { return proto.CompactTextString(m) } func (*GetProductRequest) ProtoMessage() {} func (*GetProductRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{10} + return fileDescriptor_ca53982754088a9d, []int{10} } + func (m *GetProductRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetProductRequest.Unmarshal(m, b) } func (m *GetProductRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetProductRequest.Marshal(b, m, deterministic) } -func (dst *GetProductRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetProductRequest.Merge(dst, src) +func (m *GetProductRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetProductRequest.Merge(m, src) } func (m *GetProductRequest) XXX_Size() int { return xxx_messageInfo_GetProductRequest.Size(m) @@ -508,16 +531,17 @@ func (m *SearchProductsRequest) Reset() { *m = SearchProductsRequest{} } func (m *SearchProductsRequest) String() string { return proto.CompactTextString(m) } func (*SearchProductsRequest) ProtoMessage() {} func (*SearchProductsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{11} + return fileDescriptor_ca53982754088a9d, []int{11} } + func (m *SearchProductsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SearchProductsRequest.Unmarshal(m, b) } func (m *SearchProductsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SearchProductsRequest.Marshal(b, m, deterministic) } -func (dst *SearchProductsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_SearchProductsRequest.Merge(dst, src) +func (m *SearchProductsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SearchProductsRequest.Merge(m, src) } func (m *SearchProductsRequest) XXX_Size() int { return xxx_messageInfo_SearchProductsRequest.Size(m) @@ -546,16 +570,17 @@ func (m *SearchProductsResponse) Reset() { *m = SearchProductsResponse{} func (m *SearchProductsResponse) String() string { return proto.CompactTextString(m) } func (*SearchProductsResponse) ProtoMessage() {} func (*SearchProductsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{12} + return fileDescriptor_ca53982754088a9d, []int{12} } + func (m *SearchProductsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SearchProductsResponse.Unmarshal(m, b) } func (m *SearchProductsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SearchProductsResponse.Marshal(b, m, deterministic) } -func (dst *SearchProductsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_SearchProductsResponse.Merge(dst, src) +func (m *SearchProductsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_SearchProductsResponse.Merge(m, src) } func (m *SearchProductsResponse) XXX_Size() int { return xxx_messageInfo_SearchProductsResponse.Size(m) @@ -585,16 +610,17 @@ func (m *GetQuoteRequest) Reset() { *m = GetQuoteRequest{} } func (m *GetQuoteRequest) String() string { return proto.CompactTextString(m) } func (*GetQuoteRequest) ProtoMessage() {} func (*GetQuoteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{13} + return fileDescriptor_ca53982754088a9d, []int{13} } + func (m *GetQuoteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetQuoteRequest.Unmarshal(m, b) } func (m *GetQuoteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetQuoteRequest.Marshal(b, m, deterministic) } -func (dst *GetQuoteRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetQuoteRequest.Merge(dst, src) +func (m *GetQuoteRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetQuoteRequest.Merge(m, src) } func (m *GetQuoteRequest) XXX_Size() int { return xxx_messageInfo_GetQuoteRequest.Size(m) @@ -630,16 +656,17 @@ func (m *GetQuoteResponse) Reset() { *m = GetQuoteResponse{} } func (m *GetQuoteResponse) String() string { return proto.CompactTextString(m) } func (*GetQuoteResponse) ProtoMessage() {} func (*GetQuoteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{14} + return fileDescriptor_ca53982754088a9d, []int{14} } + func (m *GetQuoteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetQuoteResponse.Unmarshal(m, b) } func (m *GetQuoteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetQuoteResponse.Marshal(b, m, deterministic) } -func (dst *GetQuoteResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetQuoteResponse.Merge(dst, src) +func (m *GetQuoteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetQuoteResponse.Merge(m, src) } func (m *GetQuoteResponse) XXX_Size() int { return xxx_messageInfo_GetQuoteResponse.Size(m) @@ -669,16 +696,17 @@ func (m *ShipOrderRequest) Reset() { *m = ShipOrderRequest{} } func (m *ShipOrderRequest) String() string { return proto.CompactTextString(m) } func (*ShipOrderRequest) ProtoMessage() {} func (*ShipOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{15} + return fileDescriptor_ca53982754088a9d, []int{15} } + func (m *ShipOrderRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShipOrderRequest.Unmarshal(m, b) } func (m *ShipOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ShipOrderRequest.Marshal(b, m, deterministic) } -func (dst *ShipOrderRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ShipOrderRequest.Merge(dst, src) +func (m *ShipOrderRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShipOrderRequest.Merge(m, src) } func (m *ShipOrderRequest) XXX_Size() int { return xxx_messageInfo_ShipOrderRequest.Size(m) @@ -714,16 +742,17 @@ func (m *ShipOrderResponse) Reset() { *m = ShipOrderResponse{} } func (m *ShipOrderResponse) String() string { return proto.CompactTextString(m) } func (*ShipOrderResponse) ProtoMessage() {} func (*ShipOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{16} + return fileDescriptor_ca53982754088a9d, []int{16} } + func (m *ShipOrderResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShipOrderResponse.Unmarshal(m, b) } func (m *ShipOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ShipOrderResponse.Marshal(b, m, deterministic) } -func (dst *ShipOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ShipOrderResponse.Merge(dst, src) +func (m *ShipOrderResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShipOrderResponse.Merge(m, src) } func (m *ShipOrderResponse) XXX_Size() int { return xxx_messageInfo_ShipOrderResponse.Size(m) @@ -756,16 +785,17 @@ func (m *Address) Reset() { *m = Address{} } func (m *Address) String() string { return proto.CompactTextString(m) } func (*Address) ProtoMessage() {} func (*Address) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{17} + return fileDescriptor_ca53982754088a9d, []int{17} } + func (m *Address) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Address.Unmarshal(m, b) } func (m *Address) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Address.Marshal(b, m, deterministic) } -func (dst *Address) XXX_Merge(src proto.Message) { - xxx_messageInfo_Address.Merge(dst, src) +func (m *Address) XXX_Merge(src proto.Message) { + xxx_messageInfo_Address.Merge(m, src) } func (m *Address) XXX_Size() int { return xxx_messageInfo_Address.Size(m) @@ -834,16 +864,17 @@ func (m *Money) Reset() { *m = Money{} } func (m *Money) String() string { return proto.CompactTextString(m) } func (*Money) ProtoMessage() {} func (*Money) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{18} + return fileDescriptor_ca53982754088a9d, []int{18} } + func (m *Money) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Money.Unmarshal(m, b) } func (m *Money) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Money.Marshal(b, m, deterministic) } -func (dst *Money) XXX_Merge(src proto.Message) { - xxx_messageInfo_Money.Merge(dst, src) +func (m *Money) XXX_Merge(src proto.Message) { + xxx_messageInfo_Money.Merge(m, src) } func (m *Money) XXX_Size() int { return xxx_messageInfo_Money.Size(m) @@ -887,16 +918,17 @@ func (m *GetSupportedCurrenciesResponse) Reset() { *m = GetSupportedCurr func (m *GetSupportedCurrenciesResponse) String() string { return proto.CompactTextString(m) } func (*GetSupportedCurrenciesResponse) ProtoMessage() {} func (*GetSupportedCurrenciesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{19} + return fileDescriptor_ca53982754088a9d, []int{19} } + func (m *GetSupportedCurrenciesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSupportedCurrenciesResponse.Unmarshal(m, b) } func (m *GetSupportedCurrenciesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetSupportedCurrenciesResponse.Marshal(b, m, deterministic) } -func (dst *GetSupportedCurrenciesResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetSupportedCurrenciesResponse.Merge(dst, src) +func (m *GetSupportedCurrenciesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetSupportedCurrenciesResponse.Merge(m, src) } func (m *GetSupportedCurrenciesResponse) XXX_Size() int { return xxx_messageInfo_GetSupportedCurrenciesResponse.Size(m) @@ -927,16 +959,17 @@ func (m *CurrencyConversionRequest) Reset() { *m = CurrencyConversionReq func (m *CurrencyConversionRequest) String() string { return proto.CompactTextString(m) } func (*CurrencyConversionRequest) ProtoMessage() {} func (*CurrencyConversionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{20} + return fileDescriptor_ca53982754088a9d, []int{20} } + func (m *CurrencyConversionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CurrencyConversionRequest.Unmarshal(m, b) } func (m *CurrencyConversionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CurrencyConversionRequest.Marshal(b, m, deterministic) } -func (dst *CurrencyConversionRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_CurrencyConversionRequest.Merge(dst, src) +func (m *CurrencyConversionRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CurrencyConversionRequest.Merge(m, src) } func (m *CurrencyConversionRequest) XXX_Size() int { return xxx_messageInfo_CurrencyConversionRequest.Size(m) @@ -975,16 +1008,17 @@ func (m *CreditCardInfo) Reset() { *m = CreditCardInfo{} } func (m *CreditCardInfo) String() string { return proto.CompactTextString(m) } func (*CreditCardInfo) ProtoMessage() {} func (*CreditCardInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{21} + return fileDescriptor_ca53982754088a9d, []int{21} } + func (m *CreditCardInfo) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CreditCardInfo.Unmarshal(m, b) } func (m *CreditCardInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CreditCardInfo.Marshal(b, m, deterministic) } -func (dst *CreditCardInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_CreditCardInfo.Merge(dst, src) +func (m *CreditCardInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreditCardInfo.Merge(m, src) } func (m *CreditCardInfo) XXX_Size() int { return xxx_messageInfo_CreditCardInfo.Size(m) @@ -1035,16 +1069,17 @@ func (m *ChargeRequest) Reset() { *m = ChargeRequest{} } func (m *ChargeRequest) String() string { return proto.CompactTextString(m) } func (*ChargeRequest) ProtoMessage() {} func (*ChargeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{22} + return fileDescriptor_ca53982754088a9d, []int{22} } + func (m *ChargeRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChargeRequest.Unmarshal(m, b) } func (m *ChargeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ChargeRequest.Marshal(b, m, deterministic) } -func (dst *ChargeRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ChargeRequest.Merge(dst, src) +func (m *ChargeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChargeRequest.Merge(m, src) } func (m *ChargeRequest) XXX_Size() int { return xxx_messageInfo_ChargeRequest.Size(m) @@ -1080,16 +1115,17 @@ func (m *ChargeResponse) Reset() { *m = ChargeResponse{} } func (m *ChargeResponse) String() string { return proto.CompactTextString(m) } func (*ChargeResponse) ProtoMessage() {} func (*ChargeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{23} + return fileDescriptor_ca53982754088a9d, []int{23} } + func (m *ChargeResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChargeResponse.Unmarshal(m, b) } func (m *ChargeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ChargeResponse.Marshal(b, m, deterministic) } -func (dst *ChargeResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ChargeResponse.Merge(dst, src) +func (m *ChargeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChargeResponse.Merge(m, src) } func (m *ChargeResponse) XXX_Size() int { return xxx_messageInfo_ChargeResponse.Size(m) @@ -1119,16 +1155,17 @@ func (m *OrderItem) Reset() { *m = OrderItem{} } func (m *OrderItem) String() string { return proto.CompactTextString(m) } func (*OrderItem) ProtoMessage() {} func (*OrderItem) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{24} + return fileDescriptor_ca53982754088a9d, []int{24} } + func (m *OrderItem) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OrderItem.Unmarshal(m, b) } func (m *OrderItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_OrderItem.Marshal(b, m, deterministic) } -func (dst *OrderItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrderItem.Merge(dst, src) +func (m *OrderItem) XXX_Merge(src proto.Message) { + xxx_messageInfo_OrderItem.Merge(m, src) } func (m *OrderItem) XXX_Size() int { return xxx_messageInfo_OrderItem.Size(m) @@ -1168,16 +1205,17 @@ func (m *OrderResult) Reset() { *m = OrderResult{} } func (m *OrderResult) String() string { return proto.CompactTextString(m) } func (*OrderResult) ProtoMessage() {} func (*OrderResult) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{25} + return fileDescriptor_ca53982754088a9d, []int{25} } + func (m *OrderResult) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OrderResult.Unmarshal(m, b) } func (m *OrderResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_OrderResult.Marshal(b, m, deterministic) } -func (dst *OrderResult) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrderResult.Merge(dst, src) +func (m *OrderResult) XXX_Merge(src proto.Message) { + xxx_messageInfo_OrderResult.Merge(m, src) } func (m *OrderResult) XXX_Size() int { return xxx_messageInfo_OrderResult.Size(m) @@ -1235,16 +1273,17 @@ func (m *SendOrderConfirmationRequest) Reset() { *m = SendOrderConfirmat func (m *SendOrderConfirmationRequest) String() string { return proto.CompactTextString(m) } func (*SendOrderConfirmationRequest) ProtoMessage() {} func (*SendOrderConfirmationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{26} + return fileDescriptor_ca53982754088a9d, []int{26} } + func (m *SendOrderConfirmationRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SendOrderConfirmationRequest.Unmarshal(m, b) } func (m *SendOrderConfirmationRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SendOrderConfirmationRequest.Marshal(b, m, deterministic) } -func (dst *SendOrderConfirmationRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_SendOrderConfirmationRequest.Merge(dst, src) +func (m *SendOrderConfirmationRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SendOrderConfirmationRequest.Merge(m, src) } func (m *SendOrderConfirmationRequest) XXX_Size() int { return xxx_messageInfo_SendOrderConfirmationRequest.Size(m) @@ -1284,16 +1323,17 @@ func (m *PlaceOrderRequest) Reset() { *m = PlaceOrderRequest{} } func (m *PlaceOrderRequest) String() string { return proto.CompactTextString(m) } func (*PlaceOrderRequest) ProtoMessage() {} func (*PlaceOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{27} + return fileDescriptor_ca53982754088a9d, []int{27} } + func (m *PlaceOrderRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PlaceOrderRequest.Unmarshal(m, b) } func (m *PlaceOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_PlaceOrderRequest.Marshal(b, m, deterministic) } -func (dst *PlaceOrderRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_PlaceOrderRequest.Merge(dst, src) +func (m *PlaceOrderRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlaceOrderRequest.Merge(m, src) } func (m *PlaceOrderRequest) XXX_Size() int { return xxx_messageInfo_PlaceOrderRequest.Size(m) @@ -1350,16 +1390,17 @@ func (m *PlaceOrderResponse) Reset() { *m = PlaceOrderResponse{} } func (m *PlaceOrderResponse) String() string { return proto.CompactTextString(m) } func (*PlaceOrderResponse) ProtoMessage() {} func (*PlaceOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{28} + return fileDescriptor_ca53982754088a9d, []int{28} } + func (m *PlaceOrderResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PlaceOrderResponse.Unmarshal(m, b) } func (m *PlaceOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_PlaceOrderResponse.Marshal(b, m, deterministic) } -func (dst *PlaceOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_PlaceOrderResponse.Merge(dst, src) +func (m *PlaceOrderResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlaceOrderResponse.Merge(m, src) } func (m *PlaceOrderResponse) XXX_Size() int { return xxx_messageInfo_PlaceOrderResponse.Size(m) @@ -1389,16 +1430,17 @@ func (m *AdRequest) Reset() { *m = AdRequest{} } func (m *AdRequest) String() string { return proto.CompactTextString(m) } func (*AdRequest) ProtoMessage() {} func (*AdRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{29} + return fileDescriptor_ca53982754088a9d, []int{29} } + func (m *AdRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AdRequest.Unmarshal(m, b) } func (m *AdRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_AdRequest.Marshal(b, m, deterministic) } -func (dst *AdRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_AdRequest.Merge(dst, src) +func (m *AdRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdRequest.Merge(m, src) } func (m *AdRequest) XXX_Size() int { return xxx_messageInfo_AdRequest.Size(m) @@ -1427,16 +1469,17 @@ func (m *AdResponse) Reset() { *m = AdResponse{} } func (m *AdResponse) String() string { return proto.CompactTextString(m) } func (*AdResponse) ProtoMessage() {} func (*AdResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{30} + return fileDescriptor_ca53982754088a9d, []int{30} } + func (m *AdResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AdResponse.Unmarshal(m, b) } func (m *AdResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_AdResponse.Marshal(b, m, deterministic) } -func (dst *AdResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_AdResponse.Merge(dst, src) +func (m *AdResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdResponse.Merge(m, src) } func (m *AdResponse) XXX_Size() int { return xxx_messageInfo_AdResponse.Size(m) @@ -1468,16 +1511,17 @@ func (m *Ad) Reset() { *m = Ad{} } func (m *Ad) String() string { return proto.CompactTextString(m) } func (*Ad) ProtoMessage() {} func (*Ad) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_88bb8fdac9cd6be5, []int{31} + return fileDescriptor_ca53982754088a9d, []int{31} } + func (m *Ad) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Ad.Unmarshal(m, b) } func (m *Ad) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Ad.Marshal(b, m, deterministic) } -func (dst *Ad) XXX_Merge(src proto.Message) { - xxx_messageInfo_Ad.Merge(dst, src) +func (m *Ad) XXX_Merge(src proto.Message) { + xxx_messageInfo_Ad.Merge(m, src) } func (m *Ad) XXX_Size() int { return xxx_messageInfo_Ad.Size(m) @@ -2319,101 +2363,102 @@ var _AdService_serviceDesc = grpc.ServiceDesc{ Metadata: "demo.proto", } -func init() { proto.RegisterFile("demo.proto", fileDescriptor_demo_88bb8fdac9cd6be5) } +func init() { proto.RegisterFile("demo.proto", fileDescriptor_ca53982754088a9d) } -var fileDescriptor_demo_88bb8fdac9cd6be5 = []byte{ - // 1483 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xdd, 0x72, 0xd3, 0xc6, - 0x17, 0x8f, 0x92, 0x38, 0x8e, 0x8f, 0x63, 0x27, 0xd9, 0x7f, 0x12, 0x8c, 0xc2, 0x47, 0xd8, 0x0c, - 0xfc, 0xa1, 0x80, 0x61, 0xd2, 0xce, 0x70, 0x01, 0x2d, 0xcd, 0x98, 0x8c, 0xf1, 0x14, 0x0a, 0x55, - 0xa0, 0x43, 0x87, 0x4e, 0x3d, 0x42, 0xbb, 0x60, 0x95, 0x48, 0x2b, 0x76, 0x57, 0x19, 0xcc, 0x65, - 0xfb, 0x00, 0xbd, 0xef, 0x23, 0xf4, 0x05, 0xfa, 0x0e, 0xbd, 0xef, 0x2b, 0xf4, 0x39, 0x3a, 0xbb, - 0xd2, 0xea, 0xcb, 0x76, 0x02, 0x37, 0xbd, 0xf3, 0x9e, 0xfd, 0xe9, 0x9c, 0xdf, 0x39, 0x7b, 0xbe, - 0x12, 0x00, 0x42, 0x03, 0xd6, 0x8d, 0x38, 0x93, 0x0c, 0x35, 0x47, 0x7e, 0x24, 0x24, 0xe5, 0x62, - 0xc4, 0x22, 0x7c, 0x00, 0xcb, 0x3d, 0x97, 0xcb, 0x81, 0xa4, 0x01, 0x3a, 0x0f, 0x10, 0x71, 0x46, - 0x62, 0x4f, 0x0e, 0x7d, 0xd2, 0xb1, 0x76, 0xac, 0xab, 0x0d, 0xa7, 0x91, 0x4a, 0x06, 0x04, 0xd9, - 0xb0, 0xfc, 0x2e, 0x76, 0x43, 0xe9, 0xcb, 0x71, 0x67, 0x7e, 0xc7, 0xba, 0x5a, 0x73, 0xb2, 0x33, - 0x7e, 0x06, 0xed, 0x7d, 0x42, 0x94, 0x16, 0x87, 0xbe, 0x8b, 0xa9, 0x90, 0xe8, 0x0c, 0xd4, 0x63, - 0x41, 0x79, 0xae, 0x69, 0x49, 0x1d, 0x07, 0x04, 0x5d, 0x83, 0x45, 0x5f, 0xd2, 0x40, 0xab, 0x68, - 0xee, 0x6d, 0x76, 0x0b, 0x6c, 0xba, 0x86, 0x8a, 0xa3, 0x21, 0xf8, 0x3a, 0xac, 0x1d, 0x04, 0x91, - 0x1c, 0x2b, 0xf1, 0x69, 0x7a, 0xf1, 0x35, 0x68, 0xf7, 0xa9, 0xfc, 0x28, 0xe8, 0x23, 0x58, 0x54, - 0xb8, 0xd9, 0x1c, 0xaf, 0x43, 0x4d, 0x11, 0x10, 0x9d, 0xf9, 0x9d, 0x85, 0xd9, 0x24, 0x13, 0x0c, - 0xae, 0x43, 0x4d, 0xb3, 0xc4, 0xdf, 0x83, 0xfd, 0xc8, 0x17, 0xd2, 0xa1, 0x1e, 0x0b, 0x02, 0x1a, - 0x12, 0x57, 0xfa, 0x2c, 0x14, 0xa7, 0x06, 0xe4, 0x22, 0x34, 0xf3, 0xb0, 0x27, 0x26, 0x1b, 0x0e, - 0x64, 0x71, 0x17, 0xf8, 0x2b, 0xd8, 0x9e, 0xaa, 0x57, 0x44, 0x2c, 0x14, 0xb4, 0xfa, 0xbd, 0x35, - 0xf1, 0xfd, 0xef, 0x16, 0xd4, 0x9f, 0x26, 0x47, 0xd4, 0x86, 0xf9, 0x8c, 0xc0, 0xbc, 0x4f, 0x10, - 0x82, 0xc5, 0xd0, 0x0d, 0xa8, 0x7e, 0x8d, 0x86, 0xa3, 0x7f, 0xa3, 0x1d, 0x68, 0x12, 0x2a, 0x3c, - 0xee, 0x47, 0xca, 0x50, 0x67, 0x41, 0x5f, 0x15, 0x45, 0xa8, 0x03, 0xf5, 0xc8, 0xf7, 0x64, 0xcc, - 0x69, 0x67, 0x51, 0xdf, 0x9a, 0x23, 0xba, 0x05, 0x8d, 0x88, 0xfb, 0x1e, 0x1d, 0xc6, 0x82, 0x74, - 0x6a, 0xfa, 0x89, 0x51, 0x29, 0x7a, 0x8f, 0x59, 0x48, 0xc7, 0xce, 0xb2, 0x06, 0x3d, 0x17, 0x04, - 0x3f, 0x84, 0x0d, 0xe5, 0x5c, 0xca, 0x2f, 0xf7, 0xea, 0x36, 0x2c, 0xa7, 0x2e, 0x24, 0x2e, 0x35, - 0xf7, 0x36, 0x4a, 0x7a, 0xd2, 0x0f, 0x9c, 0x0c, 0x85, 0x77, 0x61, 0xbd, 0x4f, 0x8d, 0x22, 0x13, - 0xf5, 0x8a, 0xbf, 0xf8, 0x26, 0x6c, 0x1e, 0x52, 0x97, 0x7b, 0xa3, 0xdc, 0x60, 0x02, 0xdc, 0x80, - 0xda, 0xbb, 0x98, 0xf2, 0x71, 0x8a, 0x4d, 0x0e, 0xf8, 0x21, 0x6c, 0x55, 0xe1, 0x29, 0xbf, 0x2e, - 0xd4, 0x39, 0x15, 0xf1, 0xd1, 0x29, 0xf4, 0x0c, 0x08, 0x87, 0xb0, 0xda, 0xa7, 0xf2, 0xbb, 0x98, - 0x49, 0x6a, 0x4c, 0x76, 0xa1, 0xee, 0x12, 0xc2, 0xa9, 0x10, 0xda, 0x68, 0x55, 0xc5, 0x7e, 0x72, - 0xe7, 0x18, 0xd0, 0xa7, 0x65, 0xe5, 0x3e, 0xac, 0xe5, 0xf6, 0x52, 0xce, 0x37, 0x61, 0xd9, 0x63, - 0x42, 0xea, 0xb7, 0xb1, 0x66, 0xbe, 0x4d, 0x5d, 0x61, 0xd4, 0xd3, 0x30, 0x58, 0x3b, 0x1c, 0xf9, - 0xd1, 0x13, 0x4e, 0x28, 0xff, 0x4f, 0x38, 0x7f, 0x01, 0xeb, 0x05, 0x83, 0x79, 0x7a, 0x4b, 0xee, - 0x7a, 0x6f, 0xfd, 0xf0, 0x4d, 0x5e, 0x3b, 0x60, 0x44, 0x03, 0x82, 0x7f, 0xb3, 0xa0, 0x9e, 0xda, - 0x45, 0x97, 0xa1, 0x2d, 0x24, 0xa7, 0x54, 0x0e, 0x8b, 0x2c, 0x1b, 0x4e, 0x2b, 0x91, 0x1a, 0x18, - 0x82, 0x45, 0xcf, 0xb4, 0xb1, 0x86, 0xa3, 0x7f, 0xab, 0x04, 0x10, 0xd2, 0x95, 0x34, 0xcd, 0xf7, - 0xe4, 0xa0, 0x32, 0xdd, 0x63, 0x71, 0x28, 0xf9, 0xd8, 0x64, 0x7a, 0x7a, 0x44, 0x67, 0x61, 0xf9, - 0x83, 0x1f, 0x0d, 0x3d, 0x46, 0xa8, 0x4e, 0xf4, 0x9a, 0x53, 0xff, 0xe0, 0x47, 0x3d, 0x46, 0x28, - 0x7e, 0x01, 0x35, 0x1d, 0x4a, 0xb4, 0x0b, 0x2d, 0x2f, 0xe6, 0x9c, 0x86, 0xde, 0x38, 0x01, 0x26, - 0x6c, 0x56, 0x8c, 0x50, 0xa1, 0x95, 0xe1, 0x38, 0xf4, 0xa5, 0xd0, 0x6c, 0x16, 0x9c, 0xe4, 0xa0, - 0xa4, 0xa1, 0x1b, 0x32, 0xa1, 0xe9, 0xd4, 0x9c, 0xe4, 0x80, 0xfb, 0x70, 0xa1, 0x4f, 0xe5, 0x61, - 0x1c, 0x45, 0x8c, 0x4b, 0x4a, 0x7a, 0x89, 0x1e, 0x9f, 0xe6, 0x79, 0x79, 0x19, 0xda, 0x25, 0x93, - 0xa6, 0x21, 0xb4, 0x8a, 0x36, 0x05, 0xfe, 0x11, 0xce, 0xf6, 0x32, 0x41, 0x78, 0x4c, 0xb9, 0xf0, - 0x59, 0x68, 0x1e, 0xf9, 0x0a, 0x2c, 0xbe, 0xe6, 0x2c, 0x38, 0x21, 0x47, 0xf4, 0xbd, 0x6a, 0x69, - 0x92, 0x25, 0x8e, 0x25, 0x91, 0x5c, 0x92, 0x4c, 0x07, 0xe0, 0x1f, 0x0b, 0xda, 0x3d, 0x4e, 0x89, - 0xaf, 0xfa, 0x31, 0x19, 0x84, 0xaf, 0x19, 0xba, 0x01, 0xc8, 0xd3, 0x92, 0xa1, 0xe7, 0x72, 0x32, - 0x0c, 0xe3, 0xe0, 0x15, 0xe5, 0x69, 0x3c, 0xd6, 0xbc, 0x0c, 0xfb, 0xad, 0x96, 0xa3, 0x2b, 0xb0, - 0x5a, 0x44, 0x7b, 0xc7, 0xc7, 0xe9, 0xc8, 0x69, 0xe5, 0xd0, 0xde, 0xf1, 0x31, 0xfa, 0x12, 0xb6, - 0x8b, 0x38, 0xfa, 0x3e, 0xf2, 0xb9, 0x6e, 0x8f, 0xc3, 0x31, 0x75, 0x79, 0x1a, 0xbb, 0x4e, 0xfe, - 0xcd, 0x41, 0x06, 0xf8, 0x81, 0xba, 0x1c, 0xdd, 0x87, 0x73, 0x33, 0x3e, 0x0f, 0x58, 0x28, 0x47, - 0xfa, 0xc9, 0x6b, 0xce, 0xd9, 0x69, 0xdf, 0x3f, 0x56, 0x00, 0x3c, 0x86, 0x56, 0x6f, 0xe4, 0xf2, - 0x37, 0x59, 0x4d, 0x7f, 0x06, 0x4b, 0x6e, 0xa0, 0x32, 0xe4, 0x84, 0xe0, 0xa5, 0x08, 0x74, 0x0f, - 0x9a, 0x05, 0xeb, 0xe9, 0x40, 0xdc, 0x2e, 0x57, 0x48, 0x29, 0x88, 0x0e, 0xe4, 0x4c, 0xf0, 0x1d, - 0x68, 0x1b, 0xd3, 0xf9, 0xd3, 0x4b, 0xee, 0x86, 0xc2, 0xf5, 0xb4, 0x0b, 0x59, 0xb1, 0xb4, 0x0a, - 0xd2, 0x01, 0xc1, 0x3f, 0x41, 0x43, 0x57, 0x98, 0x9e, 0xf9, 0x66, 0x1a, 0x5b, 0xa7, 0x4e, 0x63, - 0x95, 0x15, 0xaa, 0x33, 0xa4, 0x3c, 0xa7, 0x66, 0x85, 0xba, 0xc7, 0xbf, 0xcc, 0x43, 0xd3, 0x94, - 0x70, 0x7c, 0x24, 0x55, 0xa1, 0x30, 0x75, 0xcc, 0x09, 0xd5, 0xf5, 0x79, 0x40, 0xd0, 0x6d, 0xd8, - 0x10, 0x23, 0x3f, 0x8a, 0x54, 0x6d, 0x17, 0x8b, 0x3c, 0xc9, 0x26, 0x64, 0xee, 0x9e, 0x65, 0xc5, - 0x8e, 0xee, 0x40, 0x2b, 0xfb, 0x42, 0xb3, 0x59, 0x98, 0xc9, 0x66, 0xc5, 0x00, 0x7b, 0x4c, 0x48, - 0x74, 0x1f, 0xd6, 0xb2, 0x0f, 0x4d, 0x6f, 0x58, 0x3c, 0xa1, 0x83, 0xad, 0x1a, 0xb4, 0xe9, 0x19, - 0x37, 0x4c, 0x27, 0xab, 0xe9, 0x4e, 0xb6, 0x55, 0xfa, 0x2a, 0x0b, 0xa8, 0x69, 0x65, 0x04, 0xce, - 0x1d, 0xd2, 0x90, 0x68, 0x79, 0x8f, 0x85, 0xaf, 0x7d, 0x1e, 0xe8, 0xb4, 0x29, 0x8c, 0x1b, 0x1a, - 0xb8, 0xfe, 0x91, 0x19, 0x37, 0xfa, 0x80, 0xba, 0x50, 0xd3, 0xa1, 0x49, 0x63, 0xdc, 0x99, 0xb4, - 0x91, 0xc4, 0xd4, 0x49, 0x60, 0xf8, 0x6f, 0x0b, 0xd6, 0x9f, 0x1e, 0xb9, 0x1e, 0x2d, 0xf5, 0xe8, - 0x99, 0x9b, 0xc6, 0x2e, 0xb4, 0xf4, 0x85, 0x69, 0x05, 0x69, 0x9c, 0x57, 0x94, 0xd0, 0x74, 0x83, - 0x62, 0x87, 0x5f, 0xf8, 0x98, 0x0e, 0x9f, 0x79, 0x52, 0x2b, 0x7a, 0x52, 0xc9, 0xed, 0xa5, 0x4f, - 0xcb, 0xed, 0x07, 0x80, 0x8a, 0x6e, 0x65, 0x23, 0x37, 0x8d, 0x8e, 0xf5, 0x71, 0xd1, 0xe9, 0x42, - 0x63, 0x9f, 0x98, 0xa0, 0x5c, 0x82, 0x15, 0x8f, 0x85, 0x92, 0xbe, 0x97, 0xc3, 0xb7, 0x74, 0x6c, - 0xba, 0x62, 0x33, 0x95, 0x7d, 0x43, 0xc7, 0x02, 0xdf, 0x02, 0x50, 0xf8, 0xd4, 0xda, 0x25, 0x58, - 0x70, 0x89, 0x19, 0xee, 0xab, 0x95, 0x18, 0x38, 0xea, 0x0e, 0xdf, 0x85, 0xf9, 0x7d, 0xa2, 0x34, - 0x2b, 0xe6, 0x9c, 0x7a, 0x72, 0x18, 0x73, 0xf3, 0xa2, 0x4d, 0x23, 0x7b, 0xce, 0x8f, 0xd4, 0xbc, - 0x51, 0x56, 0xcc, 0xbc, 0x51, 0xbf, 0xf7, 0xfe, 0xb2, 0xa0, 0xa9, 0x2a, 0xec, 0x90, 0xf2, 0x63, - 0xdf, 0xa3, 0xe8, 0x9e, 0x9e, 0x62, 0xba, 0x28, 0xb7, 0xab, 0x11, 0x2f, 0x2c, 0xd6, 0x76, 0x39, - 0xd5, 0x93, 0xcd, 0x73, 0x0e, 0xdd, 0x85, 0x7a, 0xba, 0xfd, 0x56, 0xbe, 0x2e, 0xef, 0xc4, 0xf6, - 0xfa, 0x44, 0x85, 0xe3, 0x39, 0xf4, 0x35, 0x34, 0xb2, 0x3d, 0x1b, 0x9d, 0x9f, 0xd4, 0x5f, 0x54, - 0x30, 0xd5, 0xfc, 0xde, 0xaf, 0x16, 0x6c, 0x96, 0xf7, 0x53, 0xe3, 0xd6, 0xcf, 0xf0, 0xbf, 0x29, - 0xcb, 0x2b, 0xfa, 0x7f, 0x49, 0xcd, 0xec, 0xb5, 0xd9, 0xbe, 0x7a, 0x3a, 0x30, 0x79, 0x30, 0xc5, - 0x62, 0x1e, 0x36, 0xd3, 0xc5, 0xab, 0xe7, 0x4a, 0xf7, 0x88, 0xbd, 0x31, 0x2c, 0xfa, 0xb0, 0x52, - 0xdc, 0x32, 0xd1, 0x14, 0x2f, 0xec, 0x4b, 0x13, 0x96, 0xaa, 0x4b, 0x1f, 0x9e, 0x43, 0x0f, 0x00, - 0xf2, 0x25, 0x13, 0x5d, 0xa8, 0x86, 0xba, 0xbc, 0x7d, 0xda, 0x53, 0x77, 0x42, 0x3c, 0x87, 0x5e, - 0x42, 0xbb, 0xbc, 0x56, 0x22, 0x5c, 0x42, 0x4e, 0x5d, 0x51, 0xed, 0xdd, 0x13, 0x31, 0x59, 0x14, - 0xfe, 0xb0, 0x60, 0xf5, 0x30, 0x6d, 0x5e, 0xc6, 0xff, 0x01, 0x2c, 0x9b, 0x6d, 0x10, 0x9d, 0xab, - 0x92, 0x2e, 0x2e, 0xa5, 0xf6, 0xf9, 0x19, 0xb7, 0x59, 0x04, 0x1e, 0x41, 0x23, 0x5b, 0xd2, 0x2a, - 0xc9, 0x52, 0xdd, 0x16, 0xed, 0x0b, 0xb3, 0xae, 0x33, 0xb2, 0x7f, 0x5a, 0xb0, 0x6a, 0x5a, 0x8f, - 0x21, 0xfb, 0x12, 0xb6, 0xa6, 0x2f, 0x39, 0x53, 0x9f, 0xed, 0x7a, 0x95, 0xf0, 0x09, 0xdb, 0x11, - 0x9e, 0x43, 0x7d, 0xa8, 0x27, 0x0b, 0x8f, 0x44, 0x57, 0xca, 0xb5, 0x30, 0x6b, 0x1d, 0xb2, 0xa7, - 0x0c, 0x17, 0x3c, 0xb7, 0xf7, 0x1c, 0xda, 0x4f, 0xdd, 0x71, 0x40, 0xc3, 0xac, 0x82, 0x7b, 0xb0, - 0x94, 0x4c, 0x64, 0x64, 0x97, 0x35, 0x17, 0x37, 0x04, 0x7b, 0x7b, 0xea, 0x5d, 0x16, 0x90, 0x11, - 0xac, 0x1c, 0xa8, 0x0e, 0x6a, 0x94, 0xbe, 0x50, 0x7f, 0xb0, 0x4c, 0x19, 0x24, 0xe8, 0x5a, 0x25, - 0x1b, 0x66, 0x0f, 0x9b, 0x19, 0x35, 0xfb, 0x0a, 0x56, 0x7b, 0x23, 0xea, 0xbd, 0x65, 0x71, 0xe6, - 0xc1, 0x13, 0x80, 0xbc, 0xef, 0x56, 0xb2, 0x7b, 0x62, 0xce, 0xd8, 0x17, 0x67, 0xde, 0x67, 0xde, - 0x3c, 0x54, 0x2d, 0xd8, 0x68, 0xbf, 0x0b, 0x4b, 0x7d, 0xb5, 0x83, 0x0b, 0xb4, 0x55, 0x6d, 0xa7, - 0xa9, 0xc6, 0x33, 0x13, 0x72, 0xa3, 0xe9, 0xd5, 0x92, 0xfe, 0xe7, 0xc5, 0xe7, 0xff, 0x06, 0x00, - 0x00, 0xff, 0xff, 0x22, 0xc9, 0xfe, 0x20, 0xca, 0x10, 0x00, 0x00, +var fileDescriptor_ca53982754088a9d = []byte{ + // 1500 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xef, 0x72, 0x13, 0xb7, + 0x16, 0xcf, 0x26, 0xb1, 0x1d, 0x1f, 0xc7, 0x4e, 0xa2, 0x9b, 0x04, 0xb3, 0x81, 0x10, 0x94, 0x81, + 0x0b, 0x17, 0x08, 0x4c, 0xee, 0x9d, 0xe1, 0x03, 0xdc, 0xd2, 0x8c, 0xc9, 0x18, 0x4f, 0xa1, 0xd0, + 0x0d, 0xe9, 0xd0, 0xa1, 0x53, 0xcf, 0xb2, 0x12, 0xf1, 0x96, 0xec, 0x6a, 0x91, 0xb4, 0x19, 0xcc, + 0xc7, 0xf6, 0x01, 0xfa, 0x1e, 0x7d, 0x81, 0xce, 0xf4, 0x11, 0xfa, 0xbd, 0xaf, 0xd0, 0xe7, 0xe8, + 0x48, 0xbb, 0xda, 0x7f, 0xb1, 0x13, 0xf8, 0xd2, 0x6f, 0xab, 0xa3, 0x9f, 0xce, 0xf9, 0xe9, 0xe8, + 0xfc, 0xb3, 0x01, 0x08, 0x0d, 0xd8, 0x4e, 0xc4, 0x99, 0x64, 0xa8, 0x35, 0xf2, 0x23, 0x21, 0x29, + 0x17, 0x23, 0x16, 0xe1, 0x7d, 0x58, 0xe8, 0xb9, 0x5c, 0x0e, 0x24, 0x0d, 0xd0, 0x65, 0x80, 0x88, + 0x33, 0x12, 0x7b, 0x72, 0xe8, 0x93, 0xae, 0xb5, 0x65, 0xdd, 0x68, 0x3a, 0xcd, 0x54, 0x32, 0x20, + 0xc8, 0x86, 0x85, 0xf7, 0xb1, 0x1b, 0x4a, 0x5f, 0x8e, 0xbb, 0xb3, 0x5b, 0xd6, 0x8d, 0x9a, 0x93, + 0xad, 0xf1, 0x4b, 0xe8, 0xec, 0x11, 0xa2, 0xb4, 0x38, 0xf4, 0x7d, 0x4c, 0x85, 0x44, 0x17, 0xa0, + 0x11, 0x0b, 0xca, 0x73, 0x4d, 0x75, 0xb5, 0x1c, 0x10, 0x74, 0x13, 0xe6, 0x7d, 0x49, 0x03, 0xad, + 0xa2, 0xb5, 0xbb, 0xb6, 0x53, 0x60, 0xb3, 0x63, 0xa8, 0x38, 0x1a, 0x82, 0x6f, 0xc1, 0xf2, 0x7e, + 0x10, 0xc9, 0xb1, 0x12, 0x9f, 0xa7, 0x17, 0xdf, 0x84, 0x4e, 0x9f, 0xca, 0x4f, 0x82, 0x3e, 0x85, + 0x79, 0x85, 0x9b, 0xce, 0xf1, 0x16, 0xd4, 0x14, 0x01, 0xd1, 0x9d, 0xdd, 0x9a, 0x9b, 0x4e, 0x32, + 0xc1, 0xe0, 0x06, 0xd4, 0x34, 0x4b, 0xfc, 0x2d, 0xd8, 0x4f, 0x7d, 0x21, 0x1d, 0xea, 0xb1, 0x20, + 0xa0, 0x21, 0x71, 0xa5, 0xcf, 0x42, 0x71, 0xae, 0x43, 0xae, 0x40, 0x2b, 0x77, 0x7b, 0x62, 0xb2, + 0xe9, 0x40, 0xe6, 0x77, 0x81, 0xbf, 0x80, 0x8d, 0x89, 0x7a, 0x45, 0xc4, 0x42, 0x41, 0xab, 0xe7, + 0xad, 0x53, 0xe7, 0x7f, 0xb7, 0xa0, 0xf1, 0x22, 0x59, 0xa2, 0x0e, 0xcc, 0x66, 0x04, 0x66, 0x7d, + 0x82, 0x10, 0xcc, 0x87, 0x6e, 0x40, 0xf5, 0x6b, 0x34, 0x1d, 0xfd, 0x8d, 0xb6, 0xa0, 0x45, 0xa8, + 0xf0, 0xb8, 0x1f, 0x29, 0x43, 0xdd, 0x39, 0xbd, 0x55, 0x14, 0xa1, 0x2e, 0x34, 0x22, 0xdf, 0x93, + 0x31, 0xa7, 0xdd, 0x79, 0xbd, 0x6b, 0x96, 0xe8, 0x2e, 0x34, 0x23, 0xee, 0x7b, 0x74, 0x18, 0x0b, + 0xd2, 0xad, 0xe9, 0x27, 0x46, 0x25, 0xef, 0x3d, 0x63, 0x21, 0x1d, 0x3b, 0x0b, 0x1a, 0x74, 0x28, + 0x08, 0xda, 0x04, 0xf0, 0x5c, 0x49, 0x8f, 0x18, 0xf7, 0xa9, 0xe8, 0xd6, 0x13, 0xf2, 0xb9, 0x04, + 0x3f, 0x81, 0x55, 0x75, 0xf9, 0x94, 0x7f, 0x7e, 0xeb, 0x7b, 0xb0, 0x90, 0x5e, 0x31, 0xb9, 0x72, + 0x6b, 0x77, 0xb5, 0x64, 0x27, 0x3d, 0xe0, 0x64, 0x28, 0xbc, 0x0d, 0x2b, 0x7d, 0x6a, 0x14, 0x99, + 0x57, 0xa9, 0xf8, 0x03, 0xdf, 0x81, 0xb5, 0x03, 0xea, 0x72, 0x6f, 0x94, 0x1b, 0x4c, 0x80, 0xab, + 0x50, 0x7b, 0x1f, 0x53, 0x3e, 0x4e, 0xb1, 0xc9, 0x02, 0x3f, 0x81, 0xf5, 0x2a, 0x3c, 0xe5, 0xb7, + 0x03, 0x0d, 0x4e, 0x45, 0x7c, 0x7c, 0x0e, 0x3d, 0x03, 0xc2, 0x21, 0x2c, 0xf5, 0xa9, 0xfc, 0x26, + 0x66, 0x92, 0x1a, 0x93, 0x3b, 0xd0, 0x70, 0x09, 0xe1, 0x54, 0x08, 0x6d, 0xb4, 0xaa, 0x62, 0x2f, + 0xd9, 0x73, 0x0c, 0xe8, 0xf3, 0xa2, 0x76, 0x0f, 0x96, 0x73, 0x7b, 0x29, 0xe7, 0x3b, 0xb0, 0xe0, + 0x31, 0x21, 0xf5, 0xdb, 0x59, 0x53, 0xdf, 0xae, 0xa1, 0x30, 0x87, 0x82, 0x60, 0x06, 0xcb, 0x07, + 0x23, 0x3f, 0x7a, 0xce, 0x09, 0xe5, 0xff, 0x08, 0xe7, 0xff, 0xc1, 0x4a, 0xc1, 0x60, 0x1e, 0xfe, + 0x92, 0xbb, 0xde, 0x3b, 0x3f, 0x3c, 0xca, 0x73, 0x0b, 0x8c, 0x68, 0x40, 0xf0, 0x2f, 0x16, 0x34, + 0x52, 0xbb, 0xe8, 0x1a, 0x74, 0x84, 0xe4, 0x94, 0xca, 0x61, 0x91, 0x65, 0xd3, 0x69, 0x27, 0x52, + 0x03, 0x43, 0x30, 0xef, 0x99, 0x32, 0xd7, 0x74, 0xf4, 0xb7, 0x0a, 0x00, 0x21, 0x5d, 0x49, 0xd3, + 0x7c, 0x48, 0x16, 0x2a, 0x13, 0x3c, 0x16, 0x87, 0x92, 0x8f, 0x4d, 0x26, 0xa4, 0x4b, 0x74, 0x11, + 0x16, 0x3e, 0xfa, 0xd1, 0xd0, 0x63, 0x84, 0xea, 0x44, 0xa8, 0x39, 0x8d, 0x8f, 0x7e, 0xd4, 0x63, + 0x84, 0xe2, 0x57, 0x50, 0xd3, 0xae, 0x44, 0xdb, 0xd0, 0xf6, 0x62, 0xce, 0x69, 0xe8, 0x8d, 0x13, + 0x60, 0xc2, 0x66, 0xd1, 0x08, 0x15, 0x5a, 0x19, 0x8e, 0x43, 0x5f, 0x0a, 0xcd, 0x66, 0xce, 0x49, + 0x16, 0x4a, 0x1a, 0xba, 0x21, 0x13, 0x9a, 0x4e, 0xcd, 0x49, 0x16, 0xb8, 0x0f, 0x9b, 0x7d, 0x2a, + 0x0f, 0xe2, 0x28, 0x62, 0x5c, 0x52, 0xd2, 0x4b, 0xf4, 0xf8, 0x34, 0x8f, 0xcb, 0x6b, 0xd0, 0x29, + 0x99, 0x34, 0x05, 0xa3, 0x5d, 0xb4, 0x29, 0xf0, 0xf7, 0x70, 0xb1, 0x97, 0x09, 0xc2, 0x13, 0xca, + 0x85, 0xcf, 0x42, 0xf3, 0xc8, 0xd7, 0x61, 0xfe, 0x2d, 0x67, 0xc1, 0x19, 0x31, 0xa2, 0xf7, 0x55, + 0xc9, 0x93, 0x2c, 0xb9, 0x58, 0xe2, 0xc9, 0xba, 0x64, 0xda, 0x01, 0x7f, 0x59, 0xd0, 0xe9, 0x71, + 0x4a, 0x7c, 0x55, 0xaf, 0xc9, 0x20, 0x7c, 0xcb, 0xd0, 0x6d, 0x40, 0x9e, 0x96, 0x0c, 0x3d, 0x97, + 0x93, 0x61, 0x18, 0x07, 0x6f, 0x28, 0x4f, 0xfd, 0xb1, 0xec, 0x65, 0xd8, 0xaf, 0xb5, 0x1c, 0x5d, + 0x87, 0xa5, 0x22, 0xda, 0x3b, 0x39, 0x49, 0x5b, 0x52, 0x3b, 0x87, 0xf6, 0x4e, 0x4e, 0xd0, 0xff, + 0x61, 0xa3, 0x88, 0xa3, 0x1f, 0x22, 0x9f, 0xeb, 0xf2, 0x39, 0x1c, 0x53, 0x97, 0xa7, 0xbe, 0xeb, + 0xe6, 0x67, 0xf6, 0x33, 0xc0, 0x77, 0xd4, 0xe5, 0xe8, 0x11, 0x5c, 0x9a, 0x72, 0x3c, 0x60, 0xa1, + 0x1c, 0xe9, 0x27, 0xaf, 0x39, 0x17, 0x27, 0x9d, 0x7f, 0xa6, 0x00, 0x78, 0x0c, 0xed, 0xde, 0xc8, + 0xe5, 0x47, 0x59, 0x4e, 0xff, 0x07, 0xea, 0x6e, 0xa0, 0x22, 0xe4, 0x0c, 0xe7, 0xa5, 0x08, 0xf4, + 0x10, 0x5a, 0x05, 0xeb, 0x69, 0xc3, 0xdc, 0x28, 0x67, 0x48, 0xc9, 0x89, 0x0e, 0xe4, 0x4c, 0xf0, + 0x7d, 0xe8, 0x18, 0xd3, 0xf9, 0xd3, 0x4b, 0xee, 0x86, 0xc2, 0xf5, 0xf4, 0x15, 0xb2, 0x64, 0x69, + 0x17, 0xa4, 0x03, 0x82, 0x7f, 0x80, 0xa6, 0xce, 0x30, 0x3d, 0x13, 0x98, 0x6e, 0x6d, 0x9d, 0xdb, + 0xad, 0x55, 0x54, 0xa8, 0xca, 0x90, 0xf2, 0x9c, 0x18, 0x15, 0x6a, 0x1f, 0xff, 0x34, 0x0b, 0x2d, + 0x93, 0xc2, 0xf1, 0xb1, 0x54, 0x89, 0xc2, 0xd4, 0x32, 0x27, 0xd4, 0xd0, 0xeb, 0x01, 0x41, 0xf7, + 0x60, 0x55, 0x8c, 0xfc, 0x28, 0x52, 0xb9, 0x5d, 0x4c, 0xf2, 0x24, 0x9a, 0x90, 0xd9, 0x7b, 0x99, + 0x25, 0x3b, 0xba, 0x0f, 0xed, 0xec, 0x84, 0x66, 0x33, 0x37, 0x95, 0xcd, 0xa2, 0x01, 0xf6, 0x98, + 0x90, 0xe8, 0x11, 0x2c, 0x67, 0x07, 0x4d, 0x6d, 0x98, 0x3f, 0xa3, 0x82, 0x2d, 0x19, 0xb4, 0xa9, + 0x19, 0xb7, 0x4d, 0x25, 0xab, 0xe9, 0x4a, 0xb6, 0x5e, 0x3a, 0x95, 0x39, 0xd4, 0x94, 0x32, 0x02, + 0x97, 0x0e, 0x68, 0x48, 0xb4, 0xbc, 0xc7, 0xc2, 0xb7, 0x3e, 0x0f, 0x74, 0xd8, 0x14, 0xda, 0x0d, + 0x0d, 0x5c, 0xff, 0xd8, 0xb4, 0x1b, 0xbd, 0x40, 0x3b, 0x50, 0xd3, 0xae, 0x49, 0x7d, 0xdc, 0x3d, + 0x6d, 0x23, 0xf1, 0xa9, 0x93, 0xc0, 0xf0, 0x9f, 0x16, 0xac, 0xbc, 0x38, 0x76, 0x3d, 0x5a, 0xaa, + 0xd1, 0x53, 0x27, 0x91, 0x6d, 0x68, 0xeb, 0x0d, 0x53, 0x0a, 0x52, 0x3f, 0x2f, 0x2a, 0xa1, 0xa9, + 0x06, 0xc5, 0x0a, 0x3f, 0xf7, 0x29, 0x15, 0x3e, 0xbb, 0x49, 0xad, 0x78, 0x93, 0x4a, 0x6c, 0xd7, + 0x3f, 0x2f, 0xb6, 0x1f, 0x03, 0x2a, 0x5e, 0x2b, 0x6b, 0xb9, 0xa9, 0x77, 0xac, 0x4f, 0xf3, 0xce, + 0x0e, 0x34, 0xf7, 0x88, 0x71, 0xca, 0x55, 0x58, 0xf4, 0x58, 0x28, 0xe9, 0x07, 0x39, 0x7c, 0x47, + 0xc7, 0xa6, 0x2a, 0xb6, 0x52, 0xd9, 0x57, 0x74, 0x2c, 0xf0, 0x5d, 0x00, 0x85, 0x4f, 0xad, 0x5d, + 0x85, 0x39, 0x97, 0x98, 0xe6, 0xbe, 0x54, 0xf1, 0x81, 0xa3, 0xf6, 0xf0, 0x03, 0x98, 0xdd, 0x23, + 0x4a, 0xb3, 0x62, 0xce, 0xa9, 0x27, 0x87, 0x31, 0x37, 0x2f, 0xda, 0x32, 0xb2, 0x43, 0x7e, 0xac, + 0xfa, 0x8d, 0xb2, 0x62, 0xfa, 0x8d, 0xfa, 0xde, 0xfd, 0xc3, 0x82, 0x96, 0xca, 0xb0, 0x03, 0xca, + 0x4f, 0x7c, 0x8f, 0xa2, 0x87, 0xba, 0x8b, 0xe9, 0xa4, 0xdc, 0xa8, 0x7a, 0xbc, 0x30, 0x78, 0xdb, + 0xe5, 0x50, 0x4f, 0x26, 0xd3, 0x19, 0xf4, 0x00, 0x1a, 0xe9, 0x74, 0x5c, 0x39, 0x5d, 0x9e, 0x99, + 0xed, 0x95, 0x53, 0x19, 0x8e, 0x67, 0xd0, 0x97, 0xd0, 0xcc, 0xe6, 0x70, 0x74, 0xf9, 0xb4, 0xfe, + 0xa2, 0x82, 0x89, 0xe6, 0x77, 0x7f, 0xb6, 0x60, 0xad, 0x3c, 0xbf, 0x9a, 0x6b, 0xfd, 0x08, 0xff, + 0x9a, 0x30, 0xdc, 0xa2, 0x7f, 0x97, 0xd4, 0x4c, 0x1f, 0xab, 0xed, 0x1b, 0xe7, 0x03, 0x93, 0x07, + 0x53, 0x2c, 0x66, 0x61, 0x2d, 0x1d, 0xbc, 0x7a, 0xae, 0x74, 0x8f, 0xd9, 0x91, 0x61, 0xd1, 0x87, + 0xc5, 0xe2, 0x94, 0x89, 0x26, 0xdc, 0xc2, 0xbe, 0x7a, 0xca, 0x52, 0x75, 0xe8, 0xc3, 0x33, 0xe8, + 0x31, 0x40, 0x3e, 0x64, 0xa2, 0xcd, 0xaa, 0xab, 0xcb, 0xd3, 0xa7, 0x3d, 0x71, 0x26, 0xc4, 0x33, + 0xe8, 0x35, 0x74, 0xca, 0x63, 0x25, 0xc2, 0x25, 0xe4, 0xc4, 0x11, 0xd5, 0xde, 0x3e, 0x13, 0x93, + 0x79, 0xe1, 0x57, 0x0b, 0x96, 0x0e, 0xd2, 0xe2, 0x65, 0xee, 0x3f, 0x80, 0x05, 0x33, 0x0d, 0xa2, + 0x4b, 0x55, 0xd2, 0xc5, 0xa1, 0xd4, 0xbe, 0x3c, 0x65, 0x37, 0xf3, 0xc0, 0x53, 0x68, 0x66, 0x43, + 0x5a, 0x25, 0x58, 0xaa, 0xd3, 0xa2, 0xbd, 0x39, 0x6d, 0x3b, 0x23, 0xfb, 0x9b, 0x05, 0x4b, 0xa6, + 0xf4, 0x18, 0xb2, 0xaf, 0x61, 0x7d, 0xf2, 0x90, 0x33, 0xf1, 0xd9, 0x6e, 0x55, 0x09, 0x9f, 0x31, + 0x1d, 0xe1, 0x19, 0xd4, 0x87, 0x46, 0x32, 0xf0, 0x48, 0x74, 0xbd, 0x9c, 0x0b, 0xd3, 0xc6, 0x21, + 0x7b, 0x42, 0x73, 0xc1, 0x33, 0xbb, 0x87, 0xd0, 0x79, 0xe1, 0x8e, 0x03, 0x1a, 0x66, 0x19, 0xdc, + 0x83, 0x7a, 0xd2, 0x91, 0x91, 0x5d, 0xd6, 0x5c, 0x9c, 0x10, 0xec, 0x8d, 0x89, 0x7b, 0x99, 0x43, + 0x46, 0xb0, 0xb8, 0xaf, 0x2a, 0xa8, 0x51, 0xfa, 0x4a, 0xfd, 0x60, 0x99, 0xd0, 0x48, 0xd0, 0xcd, + 0x4a, 0x34, 0x4c, 0x6f, 0x36, 0x53, 0x72, 0xf6, 0x0d, 0x2c, 0xf5, 0x46, 0xd4, 0x7b, 0xc7, 0xe2, + 0xec, 0x06, 0xcf, 0x01, 0xf2, 0xba, 0x5b, 0x89, 0xee, 0x53, 0x7d, 0xc6, 0xbe, 0x32, 0x75, 0x3f, + 0xbb, 0xcd, 0x13, 0x55, 0x82, 0x8d, 0xf6, 0x07, 0x50, 0xef, 0xab, 0x19, 0x5c, 0xa0, 0xf5, 0x6a, + 0x39, 0x4d, 0x35, 0x5e, 0x38, 0x25, 0x37, 0x9a, 0xde, 0xd4, 0xf5, 0x9f, 0x1b, 0xff, 0xfd, 0x3b, + 0x00, 0x00, 0xff, 0xff, 0xb2, 0xa0, 0x6e, 0x6c, 0xea, 0x10, 0x00, 0x00, } diff --git a/src/productcatalogservice/genproto/demo.pb.go b/src/productcatalogservice/genproto/demo.pb.go index 7e64573..f59af20 100644 --- a/src/productcatalogservice/genproto/demo.pb.go +++ b/src/productcatalogservice/genproto/demo.pb.go @@ -3,9 +3,11 @@ package hipstershop -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) import ( context "golang.org/x/net/context" @@ -24,8 +26,8 @@ var _ = math.Inf const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package type CartItem struct { - ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId" json:"product_id,omitempty"` - Quantity int32 `protobuf:"varint,2,opt,name=quantity" json:"quantity,omitempty"` + ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` + Quantity int32 `protobuf:"varint,2,opt,name=quantity,proto3" json:"quantity,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -35,16 +37,17 @@ func (m *CartItem) Reset() { *m = CartItem{} } func (m *CartItem) String() string { return proto.CompactTextString(m) } func (*CartItem) ProtoMessage() {} func (*CartItem) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{0} + return fileDescriptor_ca53982754088a9d, []int{0} } + func (m *CartItem) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CartItem.Unmarshal(m, b) } func (m *CartItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CartItem.Marshal(b, m, deterministic) } -func (dst *CartItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_CartItem.Merge(dst, src) +func (m *CartItem) XXX_Merge(src proto.Message) { + xxx_messageInfo_CartItem.Merge(m, src) } func (m *CartItem) XXX_Size() int { return xxx_messageInfo_CartItem.Size(m) @@ -70,8 +73,8 @@ func (m *CartItem) GetQuantity() int32 { } type AddItemRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - Item *CartItem `protobuf:"bytes,2,opt,name=item" json:"item,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Item *CartItem `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -81,16 +84,17 @@ func (m *AddItemRequest) Reset() { *m = AddItemRequest{} } func (m *AddItemRequest) String() string { return proto.CompactTextString(m) } func (*AddItemRequest) ProtoMessage() {} func (*AddItemRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{1} + return fileDescriptor_ca53982754088a9d, []int{1} } + func (m *AddItemRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AddItemRequest.Unmarshal(m, b) } func (m *AddItemRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_AddItemRequest.Marshal(b, m, deterministic) } -func (dst *AddItemRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_AddItemRequest.Merge(dst, src) +func (m *AddItemRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddItemRequest.Merge(m, src) } func (m *AddItemRequest) XXX_Size() int { return xxx_messageInfo_AddItemRequest.Size(m) @@ -116,7 +120,7 @@ func (m *AddItemRequest) GetItem() *CartItem { } type EmptyCartRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -126,16 +130,17 @@ func (m *EmptyCartRequest) Reset() { *m = EmptyCartRequest{} } func (m *EmptyCartRequest) String() string { return proto.CompactTextString(m) } func (*EmptyCartRequest) ProtoMessage() {} func (*EmptyCartRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{2} + return fileDescriptor_ca53982754088a9d, []int{2} } + func (m *EmptyCartRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EmptyCartRequest.Unmarshal(m, b) } func (m *EmptyCartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_EmptyCartRequest.Marshal(b, m, deterministic) } -func (dst *EmptyCartRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_EmptyCartRequest.Merge(dst, src) +func (m *EmptyCartRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_EmptyCartRequest.Merge(m, src) } func (m *EmptyCartRequest) XXX_Size() int { return xxx_messageInfo_EmptyCartRequest.Size(m) @@ -154,7 +159,7 @@ func (m *EmptyCartRequest) GetUserId() string { } type GetCartRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -164,16 +169,17 @@ func (m *GetCartRequest) Reset() { *m = GetCartRequest{} } func (m *GetCartRequest) String() string { return proto.CompactTextString(m) } func (*GetCartRequest) ProtoMessage() {} func (*GetCartRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{3} + return fileDescriptor_ca53982754088a9d, []int{3} } + func (m *GetCartRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetCartRequest.Unmarshal(m, b) } func (m *GetCartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetCartRequest.Marshal(b, m, deterministic) } -func (dst *GetCartRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetCartRequest.Merge(dst, src) +func (m *GetCartRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetCartRequest.Merge(m, src) } func (m *GetCartRequest) XXX_Size() int { return xxx_messageInfo_GetCartRequest.Size(m) @@ -192,8 +198,8 @@ func (m *GetCartRequest) GetUserId() string { } type Cart struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -203,16 +209,17 @@ func (m *Cart) Reset() { *m = Cart{} } func (m *Cart) String() string { return proto.CompactTextString(m) } func (*Cart) ProtoMessage() {} func (*Cart) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{4} + return fileDescriptor_ca53982754088a9d, []int{4} } + func (m *Cart) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Cart.Unmarshal(m, b) } func (m *Cart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Cart.Marshal(b, m, deterministic) } -func (dst *Cart) XXX_Merge(src proto.Message) { - xxx_messageInfo_Cart.Merge(dst, src) +func (m *Cart) XXX_Merge(src proto.Message) { + xxx_messageInfo_Cart.Merge(m, src) } func (m *Cart) XXX_Size() int { return xxx_messageInfo_Cart.Size(m) @@ -247,16 +254,17 @@ func (m *Empty) Reset() { *m = Empty{} } func (m *Empty) String() string { return proto.CompactTextString(m) } func (*Empty) ProtoMessage() {} func (*Empty) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{5} + return fileDescriptor_ca53982754088a9d, []int{5} } + func (m *Empty) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Empty.Unmarshal(m, b) } func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Empty.Marshal(b, m, deterministic) } -func (dst *Empty) XXX_Merge(src proto.Message) { - xxx_messageInfo_Empty.Merge(dst, src) +func (m *Empty) XXX_Merge(src proto.Message) { + xxx_messageInfo_Empty.Merge(m, src) } func (m *Empty) XXX_Size() int { return xxx_messageInfo_Empty.Size(m) @@ -268,8 +276,8 @@ func (m *Empty) XXX_DiscardUnknown() { var xxx_messageInfo_Empty proto.InternalMessageInfo type ListRecommendationsRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - ProductIds []string `protobuf:"bytes,2,rep,name=product_ids,json=productIds" json:"product_ids,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ProductIds []string `protobuf:"bytes,2,rep,name=product_ids,json=productIds,proto3" json:"product_ids,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -279,16 +287,17 @@ func (m *ListRecommendationsRequest) Reset() { *m = ListRecommendationsR func (m *ListRecommendationsRequest) String() string { return proto.CompactTextString(m) } func (*ListRecommendationsRequest) ProtoMessage() {} func (*ListRecommendationsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{6} + return fileDescriptor_ca53982754088a9d, []int{6} } + func (m *ListRecommendationsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListRecommendationsRequest.Unmarshal(m, b) } func (m *ListRecommendationsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListRecommendationsRequest.Marshal(b, m, deterministic) } -func (dst *ListRecommendationsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListRecommendationsRequest.Merge(dst, src) +func (m *ListRecommendationsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListRecommendationsRequest.Merge(m, src) } func (m *ListRecommendationsRequest) XXX_Size() int { return xxx_messageInfo_ListRecommendationsRequest.Size(m) @@ -314,7 +323,7 @@ func (m *ListRecommendationsRequest) GetProductIds() []string { } type ListRecommendationsResponse struct { - ProductIds []string `protobuf:"bytes,1,rep,name=product_ids,json=productIds" json:"product_ids,omitempty"` + ProductIds []string `protobuf:"bytes,1,rep,name=product_ids,json=productIds,proto3" json:"product_ids,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -324,16 +333,17 @@ func (m *ListRecommendationsResponse) Reset() { *m = ListRecommendations func (m *ListRecommendationsResponse) String() string { return proto.CompactTextString(m) } func (*ListRecommendationsResponse) ProtoMessage() {} func (*ListRecommendationsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{7} + return fileDescriptor_ca53982754088a9d, []int{7} } + func (m *ListRecommendationsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListRecommendationsResponse.Unmarshal(m, b) } func (m *ListRecommendationsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListRecommendationsResponse.Marshal(b, m, deterministic) } -func (dst *ListRecommendationsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListRecommendationsResponse.Merge(dst, src) +func (m *ListRecommendationsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListRecommendationsResponse.Merge(m, src) } func (m *ListRecommendationsResponse) XXX_Size() int { return xxx_messageInfo_ListRecommendationsResponse.Size(m) @@ -352,11 +362,14 @@ func (m *ListRecommendationsResponse) GetProductIds() []string { } type Product struct { - Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` - Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` - Picture string `protobuf:"bytes,4,opt,name=picture" json:"picture,omitempty"` - PriceUsd *Money `protobuf:"bytes,5,opt,name=price_usd,json=priceUsd" json:"price_usd,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + Picture string `protobuf:"bytes,4,opt,name=picture,proto3" json:"picture,omitempty"` + PriceUsd *Money `protobuf:"bytes,5,opt,name=price_usd,json=priceUsd,proto3" json:"price_usd,omitempty"` + // Categories such as "vintage" or "gardening" that can be used to look up + // other related products. + Categories []string `protobuf:"bytes,6,rep,name=categories,proto3" json:"categories,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -366,16 +379,17 @@ func (m *Product) Reset() { *m = Product{} } func (m *Product) String() string { return proto.CompactTextString(m) } func (*Product) ProtoMessage() {} func (*Product) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{8} + return fileDescriptor_ca53982754088a9d, []int{8} } + func (m *Product) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Product.Unmarshal(m, b) } func (m *Product) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Product.Marshal(b, m, deterministic) } -func (dst *Product) XXX_Merge(src proto.Message) { - xxx_messageInfo_Product.Merge(dst, src) +func (m *Product) XXX_Merge(src proto.Message) { + xxx_messageInfo_Product.Merge(m, src) } func (m *Product) XXX_Size() int { return xxx_messageInfo_Product.Size(m) @@ -421,8 +435,15 @@ func (m *Product) GetPriceUsd() *Money { return nil } +func (m *Product) GetCategories() []string { + if m != nil { + return m.Categories + } + return nil +} + type ListProductsResponse struct { - Products []*Product `protobuf:"bytes,1,rep,name=products" json:"products,omitempty"` + Products []*Product `protobuf:"bytes,1,rep,name=products,proto3" json:"products,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -432,16 +453,17 @@ func (m *ListProductsResponse) Reset() { *m = ListProductsResponse{} } func (m *ListProductsResponse) String() string { return proto.CompactTextString(m) } func (*ListProductsResponse) ProtoMessage() {} func (*ListProductsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{9} + return fileDescriptor_ca53982754088a9d, []int{9} } + func (m *ListProductsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListProductsResponse.Unmarshal(m, b) } func (m *ListProductsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListProductsResponse.Marshal(b, m, deterministic) } -func (dst *ListProductsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListProductsResponse.Merge(dst, src) +func (m *ListProductsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListProductsResponse.Merge(m, src) } func (m *ListProductsResponse) XXX_Size() int { return xxx_messageInfo_ListProductsResponse.Size(m) @@ -460,7 +482,7 @@ func (m *ListProductsResponse) GetProducts() []*Product { } type GetProductRequest struct { - Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -470,16 +492,17 @@ func (m *GetProductRequest) Reset() { *m = GetProductRequest{} } func (m *GetProductRequest) String() string { return proto.CompactTextString(m) } func (*GetProductRequest) ProtoMessage() {} func (*GetProductRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{10} + return fileDescriptor_ca53982754088a9d, []int{10} } + func (m *GetProductRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetProductRequest.Unmarshal(m, b) } func (m *GetProductRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetProductRequest.Marshal(b, m, deterministic) } -func (dst *GetProductRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetProductRequest.Merge(dst, src) +func (m *GetProductRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetProductRequest.Merge(m, src) } func (m *GetProductRequest) XXX_Size() int { return xxx_messageInfo_GetProductRequest.Size(m) @@ -498,7 +521,7 @@ func (m *GetProductRequest) GetId() string { } type SearchProductsRequest struct { - Query string `protobuf:"bytes,1,opt,name=query" json:"query,omitempty"` + Query string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -508,16 +531,17 @@ func (m *SearchProductsRequest) Reset() { *m = SearchProductsRequest{} } func (m *SearchProductsRequest) String() string { return proto.CompactTextString(m) } func (*SearchProductsRequest) ProtoMessage() {} func (*SearchProductsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{11} + return fileDescriptor_ca53982754088a9d, []int{11} } + func (m *SearchProductsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SearchProductsRequest.Unmarshal(m, b) } func (m *SearchProductsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SearchProductsRequest.Marshal(b, m, deterministic) } -func (dst *SearchProductsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_SearchProductsRequest.Merge(dst, src) +func (m *SearchProductsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SearchProductsRequest.Merge(m, src) } func (m *SearchProductsRequest) XXX_Size() int { return xxx_messageInfo_SearchProductsRequest.Size(m) @@ -536,7 +560,7 @@ func (m *SearchProductsRequest) GetQuery() string { } type SearchProductsResponse struct { - Results []*Product `protobuf:"bytes,1,rep,name=results" json:"results,omitempty"` + Results []*Product `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -546,16 +570,17 @@ func (m *SearchProductsResponse) Reset() { *m = SearchProductsResponse{} func (m *SearchProductsResponse) String() string { return proto.CompactTextString(m) } func (*SearchProductsResponse) ProtoMessage() {} func (*SearchProductsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{12} + return fileDescriptor_ca53982754088a9d, []int{12} } + func (m *SearchProductsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SearchProductsResponse.Unmarshal(m, b) } func (m *SearchProductsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SearchProductsResponse.Marshal(b, m, deterministic) } -func (dst *SearchProductsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_SearchProductsResponse.Merge(dst, src) +func (m *SearchProductsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_SearchProductsResponse.Merge(m, src) } func (m *SearchProductsResponse) XXX_Size() int { return xxx_messageInfo_SearchProductsResponse.Size(m) @@ -574,8 +599,8 @@ func (m *SearchProductsResponse) GetResults() []*Product { } type GetQuoteRequest struct { - Address *Address `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"` + Address *Address `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -585,16 +610,17 @@ func (m *GetQuoteRequest) Reset() { *m = GetQuoteRequest{} } func (m *GetQuoteRequest) String() string { return proto.CompactTextString(m) } func (*GetQuoteRequest) ProtoMessage() {} func (*GetQuoteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{13} + return fileDescriptor_ca53982754088a9d, []int{13} } + func (m *GetQuoteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetQuoteRequest.Unmarshal(m, b) } func (m *GetQuoteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetQuoteRequest.Marshal(b, m, deterministic) } -func (dst *GetQuoteRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetQuoteRequest.Merge(dst, src) +func (m *GetQuoteRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetQuoteRequest.Merge(m, src) } func (m *GetQuoteRequest) XXX_Size() int { return xxx_messageInfo_GetQuoteRequest.Size(m) @@ -620,7 +646,7 @@ func (m *GetQuoteRequest) GetItems() []*CartItem { } type GetQuoteResponse struct { - CostUsd *Money `protobuf:"bytes,1,opt,name=cost_usd,json=costUsd" json:"cost_usd,omitempty"` + CostUsd *Money `protobuf:"bytes,1,opt,name=cost_usd,json=costUsd,proto3" json:"cost_usd,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -630,16 +656,17 @@ func (m *GetQuoteResponse) Reset() { *m = GetQuoteResponse{} } func (m *GetQuoteResponse) String() string { return proto.CompactTextString(m) } func (*GetQuoteResponse) ProtoMessage() {} func (*GetQuoteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{14} + return fileDescriptor_ca53982754088a9d, []int{14} } + func (m *GetQuoteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetQuoteResponse.Unmarshal(m, b) } func (m *GetQuoteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetQuoteResponse.Marshal(b, m, deterministic) } -func (dst *GetQuoteResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetQuoteResponse.Merge(dst, src) +func (m *GetQuoteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetQuoteResponse.Merge(m, src) } func (m *GetQuoteResponse) XXX_Size() int { return xxx_messageInfo_GetQuoteResponse.Size(m) @@ -658,8 +685,8 @@ func (m *GetQuoteResponse) GetCostUsd() *Money { } type ShipOrderRequest struct { - Address *Address `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"` + Address *Address `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -669,16 +696,17 @@ func (m *ShipOrderRequest) Reset() { *m = ShipOrderRequest{} } func (m *ShipOrderRequest) String() string { return proto.CompactTextString(m) } func (*ShipOrderRequest) ProtoMessage() {} func (*ShipOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{15} + return fileDescriptor_ca53982754088a9d, []int{15} } + func (m *ShipOrderRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShipOrderRequest.Unmarshal(m, b) } func (m *ShipOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ShipOrderRequest.Marshal(b, m, deterministic) } -func (dst *ShipOrderRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ShipOrderRequest.Merge(dst, src) +func (m *ShipOrderRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShipOrderRequest.Merge(m, src) } func (m *ShipOrderRequest) XXX_Size() int { return xxx_messageInfo_ShipOrderRequest.Size(m) @@ -704,7 +732,7 @@ func (m *ShipOrderRequest) GetItems() []*CartItem { } type ShipOrderResponse struct { - TrackingId string `protobuf:"bytes,1,opt,name=tracking_id,json=trackingId" json:"tracking_id,omitempty"` + TrackingId string `protobuf:"bytes,1,opt,name=tracking_id,json=trackingId,proto3" json:"tracking_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -714,16 +742,17 @@ func (m *ShipOrderResponse) Reset() { *m = ShipOrderResponse{} } func (m *ShipOrderResponse) String() string { return proto.CompactTextString(m) } func (*ShipOrderResponse) ProtoMessage() {} func (*ShipOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{16} + return fileDescriptor_ca53982754088a9d, []int{16} } + func (m *ShipOrderResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShipOrderResponse.Unmarshal(m, b) } func (m *ShipOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ShipOrderResponse.Marshal(b, m, deterministic) } -func (dst *ShipOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ShipOrderResponse.Merge(dst, src) +func (m *ShipOrderResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShipOrderResponse.Merge(m, src) } func (m *ShipOrderResponse) XXX_Size() int { return xxx_messageInfo_ShipOrderResponse.Size(m) @@ -742,11 +771,11 @@ func (m *ShipOrderResponse) GetTrackingId() string { } type Address struct { - StreetAddress_1 string `protobuf:"bytes,1,opt,name=street_address_1,json=streetAddress1" json:"street_address_1,omitempty"` - StreetAddress_2 string `protobuf:"bytes,2,opt,name=street_address_2,json=streetAddress2" json:"street_address_2,omitempty"` - City string `protobuf:"bytes,3,opt,name=city" json:"city,omitempty"` - Country string `protobuf:"bytes,4,opt,name=country" json:"country,omitempty"` - ZipCode int32 `protobuf:"varint,5,opt,name=zip_code,json=zipCode" json:"zip_code,omitempty"` + StreetAddress string `protobuf:"bytes,1,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` + City string `protobuf:"bytes,2,opt,name=city,proto3" json:"city,omitempty"` + State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` + Country string `protobuf:"bytes,4,opt,name=country,proto3" json:"country,omitempty"` + ZipCode int32 `protobuf:"varint,5,opt,name=zip_code,json=zipCode,proto3" json:"zip_code,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -756,16 +785,17 @@ func (m *Address) Reset() { *m = Address{} } func (m *Address) String() string { return proto.CompactTextString(m) } func (*Address) ProtoMessage() {} func (*Address) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{17} + return fileDescriptor_ca53982754088a9d, []int{17} } + func (m *Address) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Address.Unmarshal(m, b) } func (m *Address) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Address.Marshal(b, m, deterministic) } -func (dst *Address) XXX_Merge(src proto.Message) { - xxx_messageInfo_Address.Merge(dst, src) +func (m *Address) XXX_Merge(src proto.Message) { + xxx_messageInfo_Address.Merge(m, src) } func (m *Address) XXX_Size() int { return xxx_messageInfo_Address.Size(m) @@ -776,16 +806,9 @@ func (m *Address) XXX_DiscardUnknown() { var xxx_messageInfo_Address proto.InternalMessageInfo -func (m *Address) GetStreetAddress_1() string { +func (m *Address) GetStreetAddress() string { if m != nil { - return m.StreetAddress_1 - } - return "" -} - -func (m *Address) GetStreetAddress_2() string { - if m != nil { - return m.StreetAddress_2 + return m.StreetAddress } return "" } @@ -797,6 +820,13 @@ func (m *Address) GetCity() string { return "" } +func (m *Address) GetState() string { + if m != nil { + return m.State + } + return "" +} + func (m *Address) GetCountry() string { if m != nil { return m.Country @@ -814,17 +844,17 @@ func (m *Address) GetZipCode() int32 { // Represents an amount of money with its currency type. type Money struct { // The 3-letter currency code defined in ISO 4217. - CurrencyCode string `protobuf:"bytes,1,opt,name=currency_code,json=currencyCode" json:"currency_code,omitempty"` + CurrencyCode string `protobuf:"bytes,1,opt,name=currency_code,json=currencyCode,proto3" json:"currency_code,omitempty"` // The whole units of the amount. // For example if `currencyCode` is `"USD"`, then 1 unit is one US dollar. - Units int64 `protobuf:"varint,2,opt,name=units" json:"units,omitempty"` + Units int64 `protobuf:"varint,2,opt,name=units,proto3" json:"units,omitempty"` // Number of nano (10^-9) units of the amount. // The value must be between -999,999,999 and +999,999,999 inclusive. // If `units` is positive, `nanos` must be positive or zero. // If `units` is zero, `nanos` can be positive, zero, or negative. // If `units` is negative, `nanos` must be negative or zero. // For example $-1.75 is represented as `units`=-1 and `nanos`=-750,000,000. - Nanos int32 `protobuf:"varint,3,opt,name=nanos" json:"nanos,omitempty"` + Nanos int32 `protobuf:"varint,3,opt,name=nanos,proto3" json:"nanos,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -834,16 +864,17 @@ func (m *Money) Reset() { *m = Money{} } func (m *Money) String() string { return proto.CompactTextString(m) } func (*Money) ProtoMessage() {} func (*Money) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{18} + return fileDescriptor_ca53982754088a9d, []int{18} } + func (m *Money) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Money.Unmarshal(m, b) } func (m *Money) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Money.Marshal(b, m, deterministic) } -func (dst *Money) XXX_Merge(src proto.Message) { - xxx_messageInfo_Money.Merge(dst, src) +func (m *Money) XXX_Merge(src proto.Message) { + xxx_messageInfo_Money.Merge(m, src) } func (m *Money) XXX_Size() int { return xxx_messageInfo_Money.Size(m) @@ -877,7 +908,7 @@ func (m *Money) GetNanos() int32 { type GetSupportedCurrenciesResponse struct { // The 3-letter currency code defined in ISO 4217. - CurrencyCodes []string `protobuf:"bytes,1,rep,name=currency_codes,json=currencyCodes" json:"currency_codes,omitempty"` + CurrencyCodes []string `protobuf:"bytes,1,rep,name=currency_codes,json=currencyCodes,proto3" json:"currency_codes,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -887,16 +918,17 @@ func (m *GetSupportedCurrenciesResponse) Reset() { *m = GetSupportedCurr func (m *GetSupportedCurrenciesResponse) String() string { return proto.CompactTextString(m) } func (*GetSupportedCurrenciesResponse) ProtoMessage() {} func (*GetSupportedCurrenciesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{19} + return fileDescriptor_ca53982754088a9d, []int{19} } + func (m *GetSupportedCurrenciesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSupportedCurrenciesResponse.Unmarshal(m, b) } func (m *GetSupportedCurrenciesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetSupportedCurrenciesResponse.Marshal(b, m, deterministic) } -func (dst *GetSupportedCurrenciesResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetSupportedCurrenciesResponse.Merge(dst, src) +func (m *GetSupportedCurrenciesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetSupportedCurrenciesResponse.Merge(m, src) } func (m *GetSupportedCurrenciesResponse) XXX_Size() int { return xxx_messageInfo_GetSupportedCurrenciesResponse.Size(m) @@ -915,9 +947,9 @@ func (m *GetSupportedCurrenciesResponse) GetCurrencyCodes() []string { } type CurrencyConversionRequest struct { - From *Money `protobuf:"bytes,1,opt,name=from" json:"from,omitempty"` + From *Money `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` // The 3-letter currency code defined in ISO 4217. - ToCode string `protobuf:"bytes,2,opt,name=to_code,json=toCode" json:"to_code,omitempty"` + ToCode string `protobuf:"bytes,2,opt,name=to_code,json=toCode,proto3" json:"to_code,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -927,16 +959,17 @@ func (m *CurrencyConversionRequest) Reset() { *m = CurrencyConversionReq func (m *CurrencyConversionRequest) String() string { return proto.CompactTextString(m) } func (*CurrencyConversionRequest) ProtoMessage() {} func (*CurrencyConversionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{20} + return fileDescriptor_ca53982754088a9d, []int{20} } + func (m *CurrencyConversionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CurrencyConversionRequest.Unmarshal(m, b) } func (m *CurrencyConversionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CurrencyConversionRequest.Marshal(b, m, deterministic) } -func (dst *CurrencyConversionRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_CurrencyConversionRequest.Merge(dst, src) +func (m *CurrencyConversionRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CurrencyConversionRequest.Merge(m, src) } func (m *CurrencyConversionRequest) XXX_Size() int { return xxx_messageInfo_CurrencyConversionRequest.Size(m) @@ -962,10 +995,10 @@ func (m *CurrencyConversionRequest) GetToCode() string { } type CreditCardInfo struct { - CreditCardNumber string `protobuf:"bytes,1,opt,name=credit_card_number,json=creditCardNumber" json:"credit_card_number,omitempty"` - CreditCardCvv int32 `protobuf:"varint,2,opt,name=credit_card_cvv,json=creditCardCvv" json:"credit_card_cvv,omitempty"` - CreditCardExpirationYear int32 `protobuf:"varint,3,opt,name=credit_card_expiration_year,json=creditCardExpirationYear" json:"credit_card_expiration_year,omitempty"` - CreditCardExpirationMonth int32 `protobuf:"varint,4,opt,name=credit_card_expiration_month,json=creditCardExpirationMonth" json:"credit_card_expiration_month,omitempty"` + CreditCardNumber string `protobuf:"bytes,1,opt,name=credit_card_number,json=creditCardNumber,proto3" json:"credit_card_number,omitempty"` + CreditCardCvv int32 `protobuf:"varint,2,opt,name=credit_card_cvv,json=creditCardCvv,proto3" json:"credit_card_cvv,omitempty"` + CreditCardExpirationYear int32 `protobuf:"varint,3,opt,name=credit_card_expiration_year,json=creditCardExpirationYear,proto3" json:"credit_card_expiration_year,omitempty"` + CreditCardExpirationMonth int32 `protobuf:"varint,4,opt,name=credit_card_expiration_month,json=creditCardExpirationMonth,proto3" json:"credit_card_expiration_month,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -975,16 +1008,17 @@ func (m *CreditCardInfo) Reset() { *m = CreditCardInfo{} } func (m *CreditCardInfo) String() string { return proto.CompactTextString(m) } func (*CreditCardInfo) ProtoMessage() {} func (*CreditCardInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{21} + return fileDescriptor_ca53982754088a9d, []int{21} } + func (m *CreditCardInfo) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CreditCardInfo.Unmarshal(m, b) } func (m *CreditCardInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CreditCardInfo.Marshal(b, m, deterministic) } -func (dst *CreditCardInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_CreditCardInfo.Merge(dst, src) +func (m *CreditCardInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreditCardInfo.Merge(m, src) } func (m *CreditCardInfo) XXX_Size() int { return xxx_messageInfo_CreditCardInfo.Size(m) @@ -1024,8 +1058,8 @@ func (m *CreditCardInfo) GetCreditCardExpirationMonth() int32 { } type ChargeRequest struct { - Amount *Money `protobuf:"bytes,1,opt,name=amount" json:"amount,omitempty"` - CreditCard *CreditCardInfo `protobuf:"bytes,2,opt,name=credit_card,json=creditCard" json:"credit_card,omitempty"` + Amount *Money `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` + CreditCard *CreditCardInfo `protobuf:"bytes,2,opt,name=credit_card,json=creditCard,proto3" json:"credit_card,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1035,16 +1069,17 @@ func (m *ChargeRequest) Reset() { *m = ChargeRequest{} } func (m *ChargeRequest) String() string { return proto.CompactTextString(m) } func (*ChargeRequest) ProtoMessage() {} func (*ChargeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{22} + return fileDescriptor_ca53982754088a9d, []int{22} } + func (m *ChargeRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChargeRequest.Unmarshal(m, b) } func (m *ChargeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ChargeRequest.Marshal(b, m, deterministic) } -func (dst *ChargeRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ChargeRequest.Merge(dst, src) +func (m *ChargeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChargeRequest.Merge(m, src) } func (m *ChargeRequest) XXX_Size() int { return xxx_messageInfo_ChargeRequest.Size(m) @@ -1070,7 +1105,7 @@ func (m *ChargeRequest) GetCreditCard() *CreditCardInfo { } type ChargeResponse struct { - TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId" json:"transaction_id,omitempty"` + TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1080,16 +1115,17 @@ func (m *ChargeResponse) Reset() { *m = ChargeResponse{} } func (m *ChargeResponse) String() string { return proto.CompactTextString(m) } func (*ChargeResponse) ProtoMessage() {} func (*ChargeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{23} + return fileDescriptor_ca53982754088a9d, []int{23} } + func (m *ChargeResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChargeResponse.Unmarshal(m, b) } func (m *ChargeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ChargeResponse.Marshal(b, m, deterministic) } -func (dst *ChargeResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ChargeResponse.Merge(dst, src) +func (m *ChargeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChargeResponse.Merge(m, src) } func (m *ChargeResponse) XXX_Size() int { return xxx_messageInfo_ChargeResponse.Size(m) @@ -1108,8 +1144,8 @@ func (m *ChargeResponse) GetTransactionId() string { } type OrderItem struct { - Item *CartItem `protobuf:"bytes,1,opt,name=item" json:"item,omitempty"` - Cost *Money `protobuf:"bytes,2,opt,name=cost" json:"cost,omitempty"` + Item *CartItem `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` + Cost *Money `protobuf:"bytes,2,opt,name=cost,proto3" json:"cost,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1119,16 +1155,17 @@ func (m *OrderItem) Reset() { *m = OrderItem{} } func (m *OrderItem) String() string { return proto.CompactTextString(m) } func (*OrderItem) ProtoMessage() {} func (*OrderItem) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{24} + return fileDescriptor_ca53982754088a9d, []int{24} } + func (m *OrderItem) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OrderItem.Unmarshal(m, b) } func (m *OrderItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_OrderItem.Marshal(b, m, deterministic) } -func (dst *OrderItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrderItem.Merge(dst, src) +func (m *OrderItem) XXX_Merge(src proto.Message) { + xxx_messageInfo_OrderItem.Merge(m, src) } func (m *OrderItem) XXX_Size() int { return xxx_messageInfo_OrderItem.Size(m) @@ -1154,11 +1191,11 @@ func (m *OrderItem) GetCost() *Money { } type OrderResult struct { - OrderId string `protobuf:"bytes,1,opt,name=order_id,json=orderId" json:"order_id,omitempty"` - ShippingTrackingId string `protobuf:"bytes,2,opt,name=shipping_tracking_id,json=shippingTrackingId" json:"shipping_tracking_id,omitempty"` - ShippingCost *Money `protobuf:"bytes,3,opt,name=shipping_cost,json=shippingCost" json:"shipping_cost,omitempty"` - ShippingAddress *Address `protobuf:"bytes,4,opt,name=shipping_address,json=shippingAddress" json:"shipping_address,omitempty"` - Items []*OrderItem `protobuf:"bytes,5,rep,name=items" json:"items,omitempty"` + OrderId string `protobuf:"bytes,1,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"` + ShippingTrackingId string `protobuf:"bytes,2,opt,name=shipping_tracking_id,json=shippingTrackingId,proto3" json:"shipping_tracking_id,omitempty"` + ShippingCost *Money `protobuf:"bytes,3,opt,name=shipping_cost,json=shippingCost,proto3" json:"shipping_cost,omitempty"` + ShippingAddress *Address `protobuf:"bytes,4,opt,name=shipping_address,json=shippingAddress,proto3" json:"shipping_address,omitempty"` + Items []*OrderItem `protobuf:"bytes,5,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1168,16 +1205,17 @@ func (m *OrderResult) Reset() { *m = OrderResult{} } func (m *OrderResult) String() string { return proto.CompactTextString(m) } func (*OrderResult) ProtoMessage() {} func (*OrderResult) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{25} + return fileDescriptor_ca53982754088a9d, []int{25} } + func (m *OrderResult) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OrderResult.Unmarshal(m, b) } func (m *OrderResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_OrderResult.Marshal(b, m, deterministic) } -func (dst *OrderResult) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrderResult.Merge(dst, src) +func (m *OrderResult) XXX_Merge(src proto.Message) { + xxx_messageInfo_OrderResult.Merge(m, src) } func (m *OrderResult) XXX_Size() int { return xxx_messageInfo_OrderResult.Size(m) @@ -1224,8 +1262,8 @@ func (m *OrderResult) GetItems() []*OrderItem { } type SendOrderConfirmationRequest struct { - Email string `protobuf:"bytes,1,opt,name=email" json:"email,omitempty"` - Order *OrderResult `protobuf:"bytes,2,opt,name=order" json:"order,omitempty"` + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` + Order *OrderResult `protobuf:"bytes,2,opt,name=order,proto3" json:"order,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1235,16 +1273,17 @@ func (m *SendOrderConfirmationRequest) Reset() { *m = SendOrderConfirmat func (m *SendOrderConfirmationRequest) String() string { return proto.CompactTextString(m) } func (*SendOrderConfirmationRequest) ProtoMessage() {} func (*SendOrderConfirmationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{26} + return fileDescriptor_ca53982754088a9d, []int{26} } + func (m *SendOrderConfirmationRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SendOrderConfirmationRequest.Unmarshal(m, b) } func (m *SendOrderConfirmationRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SendOrderConfirmationRequest.Marshal(b, m, deterministic) } -func (dst *SendOrderConfirmationRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_SendOrderConfirmationRequest.Merge(dst, src) +func (m *SendOrderConfirmationRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SendOrderConfirmationRequest.Merge(m, src) } func (m *SendOrderConfirmationRequest) XXX_Size() int { return xxx_messageInfo_SendOrderConfirmationRequest.Size(m) @@ -1269,112 +1308,12 @@ func (m *SendOrderConfirmationRequest) GetOrder() *OrderResult { return nil } -type CreateOrderRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - UserCurrency string `protobuf:"bytes,2,opt,name=user_currency,json=userCurrency" json:"user_currency,omitempty"` - Address *Address `protobuf:"bytes,3,opt,name=address" json:"address,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *CreateOrderRequest) Reset() { *m = CreateOrderRequest{} } -func (m *CreateOrderRequest) String() string { return proto.CompactTextString(m) } -func (*CreateOrderRequest) ProtoMessage() {} -func (*CreateOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{27} -} -func (m *CreateOrderRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_CreateOrderRequest.Unmarshal(m, b) -} -func (m *CreateOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_CreateOrderRequest.Marshal(b, m, deterministic) -} -func (dst *CreateOrderRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_CreateOrderRequest.Merge(dst, src) -} -func (m *CreateOrderRequest) XXX_Size() int { - return xxx_messageInfo_CreateOrderRequest.Size(m) -} -func (m *CreateOrderRequest) XXX_DiscardUnknown() { - xxx_messageInfo_CreateOrderRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_CreateOrderRequest proto.InternalMessageInfo - -func (m *CreateOrderRequest) GetUserId() string { - if m != nil { - return m.UserId - } - return "" -} - -func (m *CreateOrderRequest) GetUserCurrency() string { - if m != nil { - return m.UserCurrency - } - return "" -} - -func (m *CreateOrderRequest) GetAddress() *Address { - if m != nil { - return m.Address - } - return nil -} - -type CreateOrderResponse struct { - Items []*OrderItem `protobuf:"bytes,1,rep,name=items" json:"items,omitempty"` - ShippingCost *Money `protobuf:"bytes,2,opt,name=shipping_cost,json=shippingCost" json:"shipping_cost,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *CreateOrderResponse) Reset() { *m = CreateOrderResponse{} } -func (m *CreateOrderResponse) String() string { return proto.CompactTextString(m) } -func (*CreateOrderResponse) ProtoMessage() {} -func (*CreateOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{28} -} -func (m *CreateOrderResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_CreateOrderResponse.Unmarshal(m, b) -} -func (m *CreateOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_CreateOrderResponse.Marshal(b, m, deterministic) -} -func (dst *CreateOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_CreateOrderResponse.Merge(dst, src) -} -func (m *CreateOrderResponse) XXX_Size() int { - return xxx_messageInfo_CreateOrderResponse.Size(m) -} -func (m *CreateOrderResponse) XXX_DiscardUnknown() { - xxx_messageInfo_CreateOrderResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_CreateOrderResponse proto.InternalMessageInfo - -func (m *CreateOrderResponse) GetItems() []*OrderItem { - if m != nil { - return m.Items - } - return nil -} - -func (m *CreateOrderResponse) GetShippingCost() *Money { - if m != nil { - return m.ShippingCost - } - return nil -} - type PlaceOrderRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - UserCurrency string `protobuf:"bytes,2,opt,name=user_currency,json=userCurrency" json:"user_currency,omitempty"` - Address *Address `protobuf:"bytes,3,opt,name=address" json:"address,omitempty"` - Email string `protobuf:"bytes,5,opt,name=email" json:"email,omitempty"` - CreditCard *CreditCardInfo `protobuf:"bytes,6,opt,name=credit_card,json=creditCard" json:"credit_card,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + UserCurrency string `protobuf:"bytes,2,opt,name=user_currency,json=userCurrency,proto3" json:"user_currency,omitempty"` + Address *Address `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` + Email string `protobuf:"bytes,5,opt,name=email,proto3" json:"email,omitempty"` + CreditCard *CreditCardInfo `protobuf:"bytes,6,opt,name=credit_card,json=creditCard,proto3" json:"credit_card,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1384,16 +1323,17 @@ func (m *PlaceOrderRequest) Reset() { *m = PlaceOrderRequest{} } func (m *PlaceOrderRequest) String() string { return proto.CompactTextString(m) } func (*PlaceOrderRequest) ProtoMessage() {} func (*PlaceOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{29} + return fileDescriptor_ca53982754088a9d, []int{27} } + func (m *PlaceOrderRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PlaceOrderRequest.Unmarshal(m, b) } func (m *PlaceOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_PlaceOrderRequest.Marshal(b, m, deterministic) } -func (dst *PlaceOrderRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_PlaceOrderRequest.Merge(dst, src) +func (m *PlaceOrderRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlaceOrderRequest.Merge(m, src) } func (m *PlaceOrderRequest) XXX_Size() int { return xxx_messageInfo_PlaceOrderRequest.Size(m) @@ -1440,7 +1380,7 @@ func (m *PlaceOrderRequest) GetCreditCard() *CreditCardInfo { } type PlaceOrderResponse struct { - Order *OrderResult `protobuf:"bytes,1,opt,name=order" json:"order,omitempty"` + Order *OrderResult `protobuf:"bytes,1,opt,name=order,proto3" json:"order,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1450,16 +1390,17 @@ func (m *PlaceOrderResponse) Reset() { *m = PlaceOrderResponse{} } func (m *PlaceOrderResponse) String() string { return proto.CompactTextString(m) } func (*PlaceOrderResponse) ProtoMessage() {} func (*PlaceOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_be349a9cb1cf0a0c, []int{30} + return fileDescriptor_ca53982754088a9d, []int{28} } + func (m *PlaceOrderResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PlaceOrderResponse.Unmarshal(m, b) } func (m *PlaceOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_PlaceOrderResponse.Marshal(b, m, deterministic) } -func (dst *PlaceOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_PlaceOrderResponse.Merge(dst, src) +func (m *PlaceOrderResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlaceOrderResponse.Merge(m, src) } func (m *PlaceOrderResponse) XXX_Size() int { return xxx_messageInfo_PlaceOrderResponse.Size(m) @@ -1477,6 +1418,134 @@ func (m *PlaceOrderResponse) GetOrder() *OrderResult { return nil } +type AdRequest struct { + // List of important key words from the current page describing the context. + ContextKeys []string `protobuf:"bytes,1,rep,name=context_keys,json=contextKeys,proto3" json:"context_keys,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AdRequest) Reset() { *m = AdRequest{} } +func (m *AdRequest) String() string { return proto.CompactTextString(m) } +func (*AdRequest) ProtoMessage() {} +func (*AdRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_ca53982754088a9d, []int{29} +} + +func (m *AdRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AdRequest.Unmarshal(m, b) +} +func (m *AdRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AdRequest.Marshal(b, m, deterministic) +} +func (m *AdRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdRequest.Merge(m, src) +} +func (m *AdRequest) XXX_Size() int { + return xxx_messageInfo_AdRequest.Size(m) +} +func (m *AdRequest) XXX_DiscardUnknown() { + xxx_messageInfo_AdRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_AdRequest proto.InternalMessageInfo + +func (m *AdRequest) GetContextKeys() []string { + if m != nil { + return m.ContextKeys + } + return nil +} + +type AdResponse struct { + Ads []*Ad `protobuf:"bytes,1,rep,name=ads,proto3" json:"ads,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AdResponse) Reset() { *m = AdResponse{} } +func (m *AdResponse) String() string { return proto.CompactTextString(m) } +func (*AdResponse) ProtoMessage() {} +func (*AdResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_ca53982754088a9d, []int{30} +} + +func (m *AdResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AdResponse.Unmarshal(m, b) +} +func (m *AdResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AdResponse.Marshal(b, m, deterministic) +} +func (m *AdResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdResponse.Merge(m, src) +} +func (m *AdResponse) XXX_Size() int { + return xxx_messageInfo_AdResponse.Size(m) +} +func (m *AdResponse) XXX_DiscardUnknown() { + xxx_messageInfo_AdResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_AdResponse proto.InternalMessageInfo + +func (m *AdResponse) GetAds() []*Ad { + if m != nil { + return m.Ads + } + return nil +} + +type Ad struct { + // url to redirect to when an ad is clicked. + RedirectUrl string `protobuf:"bytes,1,opt,name=redirect_url,json=redirectUrl,proto3" json:"redirect_url,omitempty"` + // short advertisement text to display. + Text string `protobuf:"bytes,2,opt,name=text,proto3" json:"text,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Ad) Reset() { *m = Ad{} } +func (m *Ad) String() string { return proto.CompactTextString(m) } +func (*Ad) ProtoMessage() {} +func (*Ad) Descriptor() ([]byte, []int) { + return fileDescriptor_ca53982754088a9d, []int{31} +} + +func (m *Ad) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Ad.Unmarshal(m, b) +} +func (m *Ad) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Ad.Marshal(b, m, deterministic) +} +func (m *Ad) XXX_Merge(src proto.Message) { + xxx_messageInfo_Ad.Merge(m, src) +} +func (m *Ad) XXX_Size() int { + return xxx_messageInfo_Ad.Size(m) +} +func (m *Ad) XXX_DiscardUnknown() { + xxx_messageInfo_Ad.DiscardUnknown(m) +} + +var xxx_messageInfo_Ad proto.InternalMessageInfo + +func (m *Ad) GetRedirectUrl() string { + if m != nil { + return m.RedirectUrl + } + return "" +} + +func (m *Ad) GetText() string { + if m != nil { + return m.Text + } + return "" +} + func init() { proto.RegisterType((*CartItem)(nil), "hipstershop.CartItem") proto.RegisterType((*AddItemRequest)(nil), "hipstershop.AddItemRequest") @@ -1505,10 +1574,11 @@ func init() { proto.RegisterType((*OrderItem)(nil), "hipstershop.OrderItem") proto.RegisterType((*OrderResult)(nil), "hipstershop.OrderResult") proto.RegisterType((*SendOrderConfirmationRequest)(nil), "hipstershop.SendOrderConfirmationRequest") - proto.RegisterType((*CreateOrderRequest)(nil), "hipstershop.CreateOrderRequest") - proto.RegisterType((*CreateOrderResponse)(nil), "hipstershop.CreateOrderResponse") proto.RegisterType((*PlaceOrderRequest)(nil), "hipstershop.PlaceOrderRequest") proto.RegisterType((*PlaceOrderResponse)(nil), "hipstershop.PlaceOrderResponse") + proto.RegisterType((*AdRequest)(nil), "hipstershop.AdRequest") + proto.RegisterType((*AdResponse)(nil), "hipstershop.AdResponse") + proto.RegisterType((*Ad)(nil), "hipstershop.Ad") } // Reference imports to suppress errors if they are not otherwise used. @@ -2169,7 +2239,6 @@ var _EmailService_serviceDesc = grpc.ServiceDesc{ // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type CheckoutServiceClient interface { - CreateOrder(ctx context.Context, in *CreateOrderRequest, opts ...grpc.CallOption) (*CreateOrderResponse, error) PlaceOrder(ctx context.Context, in *PlaceOrderRequest, opts ...grpc.CallOption) (*PlaceOrderResponse, error) } @@ -2181,15 +2250,6 @@ func NewCheckoutServiceClient(cc *grpc.ClientConn) CheckoutServiceClient { return &checkoutServiceClient{cc} } -func (c *checkoutServiceClient) CreateOrder(ctx context.Context, in *CreateOrderRequest, opts ...grpc.CallOption) (*CreateOrderResponse, error) { - out := new(CreateOrderResponse) - err := c.cc.Invoke(ctx, "/hipstershop.CheckoutService/CreateOrder", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *checkoutServiceClient) PlaceOrder(ctx context.Context, in *PlaceOrderRequest, opts ...grpc.CallOption) (*PlaceOrderResponse, error) { out := new(PlaceOrderResponse) err := c.cc.Invoke(ctx, "/hipstershop.CheckoutService/PlaceOrder", in, out, opts...) @@ -2201,7 +2261,6 @@ func (c *checkoutServiceClient) PlaceOrder(ctx context.Context, in *PlaceOrderRe // CheckoutServiceServer is the server API for CheckoutService service. type CheckoutServiceServer interface { - CreateOrder(context.Context, *CreateOrderRequest) (*CreateOrderResponse, error) PlaceOrder(context.Context, *PlaceOrderRequest) (*PlaceOrderResponse, error) } @@ -2209,24 +2268,6 @@ func RegisterCheckoutServiceServer(s *grpc.Server, srv CheckoutServiceServer) { s.RegisterService(&_CheckoutService_serviceDesc, srv) } -func _CheckoutService_CreateOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(CreateOrderRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckoutServiceServer).CreateOrder(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.CheckoutService/CreateOrder", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckoutServiceServer).CreateOrder(ctx, req.(*CreateOrderRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _CheckoutService_PlaceOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(PlaceOrderRequest) if err := dec(in); err != nil { @@ -2249,10 +2290,6 @@ var _CheckoutService_serviceDesc = grpc.ServiceDesc{ ServiceName: "hipstershop.CheckoutService", HandlerType: (*CheckoutServiceServer)(nil), Methods: []grpc.MethodDesc{ - { - MethodName: "CreateOrder", - Handler: _CheckoutService_CreateOrder_Handler, - }, { MethodName: "PlaceOrder", Handler: _CheckoutService_PlaceOrder_Handler, @@ -2262,99 +2299,166 @@ var _CheckoutService_serviceDesc = grpc.ServiceDesc{ Metadata: "demo.proto", } -func init() { proto.RegisterFile("demo.proto", fileDescriptor_demo_be349a9cb1cf0a0c) } - -var fileDescriptor_demo_be349a9cb1cf0a0c = []byte{ - // 1442 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0xdf, 0x72, 0xd3, 0xc6, - 0x17, 0x8e, 0x92, 0x38, 0x8e, 0x8f, 0x63, 0x27, 0x59, 0x12, 0x7e, 0x46, 0xe1, 0x4f, 0x7e, 0x9b, - 0x29, 0x0d, 0x05, 0x52, 0x70, 0x3b, 0xc3, 0x45, 0x69, 0x29, 0x63, 0x32, 0xc6, 0x33, 0x50, 0xa8, - 0x02, 0x1d, 0x3a, 0x74, 0xea, 0x11, 0xd2, 0x82, 0x55, 0x22, 0xad, 0x58, 0xad, 0x32, 0x35, 0xd3, - 0x2b, 0xfa, 0x16, 0x7d, 0x80, 0x5e, 0xf4, 0x01, 0xda, 0x77, 0xe8, 0x7d, 0x5f, 0xa1, 0xcf, 0xd1, - 0xd9, 0xd5, 0xae, 0xfe, 0x59, 0x4a, 0xc2, 0x4d, 0x7b, 0xa7, 0xdd, 0xfd, 0xf6, 0x9c, 0x6f, 0xcf, - 0x9e, 0x73, 0xf6, 0xb3, 0x01, 0x5c, 0xe2, 0xd3, 0xbd, 0x90, 0x51, 0x4e, 0x51, 0x7b, 0xe2, 0x85, - 0x11, 0x27, 0x2c, 0x9a, 0xd0, 0x10, 0xef, 0xc3, 0xf2, 0xc0, 0x66, 0x7c, 0xc4, 0x89, 0x8f, 0x2e, - 0x00, 0x84, 0x8c, 0xba, 0xb1, 0xc3, 0xc7, 0x9e, 0xdb, 0x33, 0xb6, 0x8d, 0xdd, 0x96, 0xd5, 0x52, - 0x33, 0x23, 0x17, 0x99, 0xb0, 0xfc, 0x26, 0xb6, 0x03, 0xee, 0xf1, 0x69, 0x6f, 0x7e, 0xdb, 0xd8, - 0x6d, 0x58, 0xe9, 0x18, 0x3f, 0x81, 0xee, 0x5d, 0xd7, 0x15, 0x56, 0x2c, 0xf2, 0x26, 0x26, 0x11, - 0x47, 0xff, 0x83, 0x66, 0x1c, 0x11, 0x96, 0x59, 0x5a, 0x12, 0xc3, 0x91, 0x8b, 0xae, 0xc0, 0xa2, - 0xc7, 0x89, 0x2f, 0x4d, 0xb4, 0xfb, 0x9b, 0x7b, 0x39, 0x36, 0x7b, 0x9a, 0x8a, 0x25, 0x21, 0xf8, - 0x2a, 0xac, 0xed, 0xfb, 0x21, 0x9f, 0x8a, 0xe9, 0x93, 0xec, 0xe2, 0x2b, 0xd0, 0x1d, 0x12, 0x7e, - 0x2a, 0xe8, 0x03, 0x58, 0x14, 0xb8, 0x7a, 0x8e, 0x57, 0xa1, 0x21, 0x08, 0x44, 0xbd, 0xf9, 0xed, - 0x85, 0x7a, 0x92, 0x09, 0x06, 0x37, 0xa1, 0x21, 0x59, 0xe2, 0x6f, 0xc0, 0x7c, 0xe0, 0x45, 0xdc, - 0x22, 0x0e, 0xf5, 0x7d, 0x12, 0xb8, 0x36, 0xf7, 0x68, 0x10, 0x9d, 0x18, 0x90, 0x4b, 0xd0, 0xce, - 0xc2, 0x9e, 0xb8, 0x6c, 0x59, 0x90, 0xc6, 0x3d, 0xc2, 0x5f, 0xc0, 0x56, 0xa5, 0xdd, 0x28, 0xa4, - 0x41, 0x44, 0xca, 0xfb, 0x8d, 0x99, 0xfd, 0xbf, 0x18, 0xd0, 0x7c, 0x9c, 0x0c, 0x51, 0x17, 0xe6, - 0x53, 0x02, 0xf3, 0x9e, 0x8b, 0x10, 0x2c, 0x06, 0xb6, 0x4f, 0xe4, 0x6d, 0xb4, 0x2c, 0xf9, 0x8d, - 0xb6, 0xa1, 0xed, 0x92, 0xc8, 0x61, 0x5e, 0x28, 0x1c, 0xf5, 0x16, 0xe4, 0x52, 0x7e, 0x0a, 0xf5, - 0xa0, 0x19, 0x7a, 0x0e, 0x8f, 0x19, 0xe9, 0x2d, 0xca, 0x55, 0x3d, 0x44, 0x1f, 0x43, 0x2b, 0x64, - 0x9e, 0x43, 0xc6, 0x71, 0xe4, 0xf6, 0x1a, 0xf2, 0x8a, 0x51, 0x21, 0x7a, 0x0f, 0x69, 0x40, 0xa6, - 0xd6, 0xb2, 0x04, 0x3d, 0x8d, 0x5c, 0x7c, 0x1f, 0x36, 0xc4, 0xe1, 0x14, 0xbf, 0xec, 0x54, 0x37, - 0x60, 0x59, 0x1d, 0x21, 0x39, 0x52, 0xbb, 0xbf, 0x51, 0xb0, 0xa3, 0x36, 0x58, 0x29, 0x0a, 0xef, - 0xc0, 0xfa, 0x90, 0x68, 0x43, 0x3a, 0xea, 0xa5, 0xf3, 0xe2, 0xeb, 0xb0, 0x79, 0x40, 0x6c, 0xe6, - 0x4c, 0x32, 0x87, 0x09, 0x70, 0x03, 0x1a, 0x6f, 0x62, 0xc2, 0xa6, 0x0a, 0x9b, 0x0c, 0xf0, 0x7d, - 0x38, 0x5b, 0x86, 0x2b, 0x7e, 0x7b, 0xd0, 0x64, 0x24, 0x8a, 0x0f, 0x4f, 0xa0, 0xa7, 0x41, 0x38, - 0x80, 0xd5, 0x21, 0xe1, 0x5f, 0xc7, 0x94, 0x13, 0xed, 0x72, 0x0f, 0x9a, 0xb6, 0xeb, 0x32, 0x12, - 0x45, 0xd2, 0x69, 0xd9, 0xc4, 0xdd, 0x64, 0xcd, 0xd2, 0xa0, 0xf7, 0xcb, 0xca, 0xbb, 0xb0, 0x96, - 0xf9, 0x53, 0x9c, 0xaf, 0xc3, 0xb2, 0x43, 0x23, 0x2e, 0xef, 0xc6, 0xa8, 0xbd, 0x9b, 0xa6, 0xc0, - 0x88, 0xab, 0xa1, 0xb0, 0x76, 0x30, 0xf1, 0xc2, 0x47, 0xcc, 0x25, 0xec, 0x5f, 0xe1, 0xfc, 0x29, - 0xac, 0xe7, 0x1c, 0x66, 0xe9, 0xcd, 0x99, 0xed, 0xbc, 0xf6, 0x82, 0x57, 0x59, 0xed, 0x80, 0x9e, - 0x1a, 0xb9, 0xf8, 0x57, 0x03, 0x9a, 0xca, 0x2f, 0xda, 0x85, 0xb5, 0x88, 0x33, 0x42, 0xf8, 0x58, - 0x11, 0x18, 0xdf, 0x54, 0x3b, 0xba, 0xc9, 0xbc, 0x02, 0xde, 0xac, 0x40, 0xf6, 0x55, 0x11, 0x14, - 0x91, 0x7d, 0x51, 0x22, 0x8e, 0xe8, 0x79, 0x49, 0x1d, 0xc8, 0x6f, 0x51, 0x00, 0x0e, 0x8d, 0x03, - 0xce, 0xa6, 0xba, 0x00, 0xd4, 0x10, 0x9d, 0x83, 0xe5, 0xb7, 0x5e, 0x38, 0x76, 0xa8, 0x4b, 0x64, - 0xfe, 0x37, 0xac, 0xe6, 0x5b, 0x2f, 0x1c, 0x50, 0x97, 0xe0, 0x67, 0xd0, 0x90, 0x11, 0x46, 0x3b, - 0xd0, 0x71, 0x62, 0xc6, 0x48, 0xe0, 0x4c, 0x13, 0x60, 0x42, 0x71, 0x45, 0x4f, 0x0a, 0xb4, 0x48, - 0xc8, 0x38, 0xf0, 0x78, 0x24, 0x59, 0x2d, 0x58, 0xc9, 0x40, 0xcc, 0x06, 0x76, 0x40, 0x23, 0xc9, - 0xa6, 0x61, 0x25, 0x03, 0x3c, 0x84, 0x8b, 0x43, 0xc2, 0x0f, 0xe2, 0x30, 0xa4, 0x8c, 0x13, 0x77, - 0x90, 0xd8, 0xf1, 0x48, 0x96, 0xae, 0x1f, 0x40, 0xb7, 0xe0, 0x52, 0xf7, 0x89, 0x4e, 0xde, 0x67, - 0x84, 0xbf, 0x83, 0x73, 0x83, 0x74, 0x22, 0x38, 0x22, 0x2c, 0xf2, 0x68, 0xa0, 0xef, 0xfe, 0x32, - 0x2c, 0xbe, 0x64, 0xd4, 0x3f, 0x26, 0x75, 0xe4, 0xba, 0xe8, 0x74, 0x9c, 0x26, 0x07, 0x4b, 0x22, - 0xba, 0xc4, 0xa9, 0x0c, 0xc0, 0xdf, 0x06, 0x74, 0x07, 0x8c, 0xb8, 0x9e, 0x68, 0xd3, 0xee, 0x28, - 0x78, 0x49, 0xd1, 0x35, 0x40, 0x8e, 0x9c, 0x19, 0x3b, 0x36, 0x73, 0xc7, 0x41, 0xec, 0xbf, 0x20, - 0x4c, 0xc5, 0x63, 0xcd, 0x49, 0xb1, 0x5f, 0xc9, 0x79, 0x74, 0x19, 0x56, 0xf3, 0x68, 0xe7, 0xe8, - 0x48, 0xbd, 0x44, 0x9d, 0x0c, 0x3a, 0x38, 0x3a, 0x42, 0x9f, 0xc3, 0x56, 0x1e, 0x47, 0x7e, 0x0c, - 0x3d, 0x26, 0xbb, 0xe6, 0x78, 0x4a, 0x6c, 0xa6, 0x62, 0xd7, 0xcb, 0xf6, 0xec, 0xa7, 0x80, 0x6f, - 0x89, 0xcd, 0xd0, 0x1d, 0x38, 0x5f, 0xb3, 0xdd, 0xa7, 0x01, 0x9f, 0xc8, 0x2b, 0x6f, 0x58, 0xe7, - 0xaa, 0xf6, 0x3f, 0x14, 0x00, 0x3c, 0x85, 0xce, 0x60, 0x62, 0xb3, 0x57, 0x69, 0xa9, 0x7f, 0x04, - 0x4b, 0xb6, 0x2f, 0x32, 0xe4, 0x98, 0xe0, 0x29, 0x04, 0xba, 0x0d, 0xed, 0x9c, 0x77, 0xf5, 0x4e, - 0x6e, 0x15, 0x0b, 0xa7, 0x10, 0x44, 0x0b, 0x32, 0x26, 0xf8, 0x16, 0x74, 0xb5, 0xeb, 0xec, 0xea, - 0x39, 0xb3, 0x83, 0xc8, 0x76, 0xe4, 0x11, 0xd2, 0x1a, 0xea, 0xe4, 0x66, 0x47, 0x2e, 0xfe, 0x1e, - 0x5a, 0xb2, 0xf0, 0xa4, 0x14, 0xd0, 0x8f, 0xb4, 0x71, 0xe2, 0x23, 0x2d, 0xb2, 0x42, 0x34, 0x0c, - 0xc5, 0xb3, 0x32, 0x2b, 0xc4, 0x3a, 0x7e, 0x37, 0x0f, 0x6d, 0x5d, 0xd9, 0xf1, 0x21, 0x17, 0x85, - 0x42, 0xc5, 0x30, 0x23, 0xd4, 0x94, 0xe3, 0x91, 0x8b, 0x6e, 0xc0, 0x46, 0x34, 0xf1, 0xc2, 0x50, - 0x94, 0x7c, 0xbe, 0xf6, 0x93, 0x6c, 0x42, 0x7a, 0xed, 0x49, 0xda, 0x03, 0xd0, 0x2d, 0xe8, 0xa4, - 0x3b, 0x24, 0x9b, 0x85, 0x5a, 0x36, 0x2b, 0x1a, 0x38, 0xa0, 0x11, 0x47, 0x77, 0x60, 0x2d, 0xdd, - 0xa8, 0x1b, 0xdb, 0xe2, 0x31, 0x8d, 0x6d, 0x55, 0xa3, 0x75, 0xc7, 0xb9, 0xa6, 0x1b, 0x5c, 0x43, - 0x36, 0xb8, 0xb3, 0x85, 0x5d, 0x69, 0x40, 0x75, 0x87, 0x73, 0xe1, 0xfc, 0x01, 0x09, 0x5c, 0x39, - 0x3f, 0xa0, 0xc1, 0x4b, 0x8f, 0xf9, 0x32, 0x6d, 0x72, 0xaf, 0x10, 0xf1, 0x6d, 0xef, 0x50, 0xbf, - 0x42, 0x72, 0x80, 0xf6, 0xa0, 0x21, 0x43, 0xa3, 0x62, 0xdc, 0x9b, 0xf5, 0x91, 0xc4, 0xd4, 0x4a, - 0x60, 0xf8, 0x9d, 0x01, 0x68, 0xc0, 0x88, 0xcd, 0x49, 0xa1, 0x77, 0xd7, 0x2a, 0x90, 0x1d, 0xe8, - 0xc8, 0x05, 0xdd, 0x0b, 0x54, 0xa0, 0x57, 0xc4, 0xa4, 0x6e, 0x07, 0xf9, 0xce, 0xbf, 0x70, 0x8a, - 0xce, 0x8f, 0x7f, 0x82, 0x33, 0x05, 0x0e, 0x2a, 0x1b, 0xd3, 0x78, 0x19, 0xa7, 0x88, 0xd7, 0xec, - 0xbd, 0xce, 0x9f, 0xee, 0x5e, 0xf1, 0x5f, 0x06, 0xac, 0x3f, 0x3e, 0xb4, 0x9d, 0xff, 0x30, 0x02, - 0xd9, 0x65, 0x36, 0xf2, 0x97, 0x59, 0x2a, 0xef, 0xa5, 0xf7, 0x2b, 0xef, 0x7b, 0x80, 0xf2, 0xc7, - 0x4a, 0xc5, 0x88, 0x4a, 0x10, 0xe3, 0x54, 0x09, 0xd2, 0xff, 0xd3, 0x80, 0xb6, 0x28, 0xe3, 0x03, - 0xc2, 0x8e, 0x3c, 0x87, 0xa0, 0xdb, 0xf2, 0x05, 0x95, 0x95, 0xbf, 0x55, 0x3e, 0x53, 0x4e, 0xd4, - 0x9b, 0xc5, 0xb8, 0x27, 0xaa, 0x77, 0x0e, 0x7d, 0x06, 0x4d, 0xa5, 0xbc, 0x4b, 0xbb, 0x8b, 0x7a, - 0xdc, 0x5c, 0x9f, 0x69, 0x23, 0x78, 0x0e, 0x7d, 0x09, 0xad, 0x54, 0xe3, 0xa3, 0x0b, 0xb3, 0xf6, - 0xf3, 0x06, 0x2a, 0xdd, 0xf7, 0x7f, 0x36, 0x60, 0xb3, 0xa8, 0x8d, 0xf5, 0xb1, 0x7e, 0x80, 0x33, - 0x15, 0xc2, 0x19, 0x7d, 0x58, 0x30, 0x53, 0x2f, 0xd9, 0xcd, 0xdd, 0x93, 0x81, 0xc9, 0x05, 0x08, - 0x16, 0xf3, 0xb0, 0xa9, 0x44, 0xdf, 0xc0, 0xe6, 0xf6, 0x21, 0x7d, 0xa5, 0x59, 0x0c, 0x61, 0x25, - 0xaf, 0x70, 0x51, 0xc5, 0x29, 0xcc, 0xff, 0xcf, 0x78, 0x2a, 0x0b, 0x4e, 0x3c, 0x87, 0xee, 0x01, - 0x64, 0x02, 0x17, 0x5d, 0x2c, 0x87, 0xba, 0xa8, 0x7c, 0xcd, 0x4a, 0x3d, 0x8a, 0xe7, 0xd0, 0x73, - 0xe8, 0x16, 0x25, 0x2d, 0xc2, 0x05, 0x64, 0xa5, 0x3c, 0x36, 0x77, 0x8e, 0xc5, 0xa4, 0x51, 0xf8, - 0xcd, 0x80, 0xd5, 0x03, 0x55, 0x87, 0xfa, 0xfc, 0x23, 0x58, 0xd6, 0x4a, 0x14, 0x9d, 0x2f, 0x93, - 0xce, 0x0b, 0x62, 0xf3, 0x42, 0xcd, 0x6a, 0x1a, 0x81, 0x07, 0xd0, 0x4a, 0x05, 0x62, 0x29, 0x59, - 0xca, 0x4a, 0xd5, 0xbc, 0x58, 0xb7, 0x9c, 0x92, 0xfd, 0xc3, 0x80, 0x55, 0x5d, 0xdc, 0x9a, 0xec, - 0x73, 0x38, 0x5b, 0xad, 0xa4, 0x2a, 0xaf, 0xed, 0x6a, 0x99, 0xf0, 0x31, 0x12, 0x0c, 0xcf, 0xa1, - 0x21, 0x34, 0x13, 0x55, 0xc5, 0xd1, 0xe5, 0x62, 0x2d, 0xd4, 0x69, 0x2e, 0xb3, 0xa2, 0xd3, 0xe1, - 0xb9, 0xfe, 0x53, 0xe8, 0x3e, 0xb6, 0xa7, 0x3e, 0x09, 0xd2, 0x0a, 0x1e, 0xc0, 0x52, 0xf2, 0xec, - 0x23, 0xb3, 0x68, 0x39, 0x2f, 0x43, 0xcc, 0xad, 0xca, 0xb5, 0x34, 0x20, 0x13, 0x58, 0xd9, 0x17, - 0x3d, 0x4a, 0x1b, 0x7d, 0x26, 0x7e, 0x2c, 0x55, 0xbc, 0x56, 0xe8, 0x4a, 0x29, 0x1b, 0xea, 0x5f, - 0xb4, 0x9a, 0x9a, 0xfd, 0x5d, 0x84, 0x7e, 0x42, 0x9c, 0xd7, 0x34, 0x4e, 0x8f, 0x60, 0x41, 0x3b, - 0xf7, 0x60, 0xa0, 0x4b, 0xe5, 0x96, 0x58, 0x7a, 0xce, 0xcc, 0xed, 0x7a, 0x40, 0x1a, 0xf1, 0x47, - 0x00, 0x59, 0xbb, 0x2c, 0x95, 0xcc, 0xcc, 0xf3, 0x60, 0x5e, 0xaa, 0x5d, 0xd7, 0x06, 0x5f, 0x2c, - 0xc9, 0xff, 0x50, 0x3e, 0xf9, 0x27, 0x00, 0x00, 0xff, 0xff, 0x67, 0x70, 0xff, 0x79, 0x51, 0x11, - 0x00, 0x00, +// AdServiceClient is the client API for AdService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type AdServiceClient interface { + GetAds(ctx context.Context, in *AdRequest, opts ...grpc.CallOption) (*AdResponse, error) +} + +type adServiceClient struct { + cc *grpc.ClientConn +} + +func NewAdServiceClient(cc *grpc.ClientConn) AdServiceClient { + return &adServiceClient{cc} +} + +func (c *adServiceClient) GetAds(ctx context.Context, in *AdRequest, opts ...grpc.CallOption) (*AdResponse, error) { + out := new(AdResponse) + err := c.cc.Invoke(ctx, "/hipstershop.AdService/GetAds", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AdServiceServer is the server API for AdService service. +type AdServiceServer interface { + GetAds(context.Context, *AdRequest) (*AdResponse, error) +} + +func RegisterAdServiceServer(s *grpc.Server, srv AdServiceServer) { + s.RegisterService(&_AdService_serviceDesc, srv) +} + +func _AdService_GetAds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdServiceServer).GetAds(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hipstershop.AdService/GetAds", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdServiceServer).GetAds(ctx, req.(*AdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _AdService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "hipstershop.AdService", + HandlerType: (*AdServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetAds", + Handler: _AdService_GetAds_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "demo.proto", +} + +func init() { proto.RegisterFile("demo.proto", fileDescriptor_ca53982754088a9d) } + +var fileDescriptor_ca53982754088a9d = []byte{ + // 1500 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xef, 0x72, 0x13, 0xb7, + 0x16, 0xcf, 0x26, 0xb1, 0x1d, 0x1f, 0xc7, 0x4e, 0xa2, 0x9b, 0x04, 0xb3, 0x81, 0x10, 0x94, 0x81, + 0x0b, 0x17, 0x08, 0x4c, 0xee, 0x9d, 0xe1, 0x03, 0xdc, 0xd2, 0x8c, 0xc9, 0x18, 0x4f, 0xa1, 0xd0, + 0x0d, 0xe9, 0xd0, 0xa1, 0x53, 0xcf, 0xb2, 0x12, 0xf1, 0x96, 0xec, 0x6a, 0x91, 0xb4, 0x19, 0xcc, + 0xc7, 0xf6, 0x01, 0xfa, 0x1e, 0x7d, 0x81, 0xce, 0xf4, 0x11, 0xfa, 0xbd, 0xaf, 0xd0, 0xe7, 0xe8, + 0x48, 0xbb, 0xda, 0x7f, 0xb1, 0x13, 0xf8, 0xd2, 0x6f, 0xab, 0xa3, 0x9f, 0xce, 0xf9, 0xe9, 0xe8, + 0xfc, 0xb3, 0x01, 0x08, 0x0d, 0xd8, 0x4e, 0xc4, 0x99, 0x64, 0xa8, 0x35, 0xf2, 0x23, 0x21, 0x29, + 0x17, 0x23, 0x16, 0xe1, 0x7d, 0x58, 0xe8, 0xb9, 0x5c, 0x0e, 0x24, 0x0d, 0xd0, 0x65, 0x80, 0x88, + 0x33, 0x12, 0x7b, 0x72, 0xe8, 0x93, 0xae, 0xb5, 0x65, 0xdd, 0x68, 0x3a, 0xcd, 0x54, 0x32, 0x20, + 0xc8, 0x86, 0x85, 0xf7, 0xb1, 0x1b, 0x4a, 0x5f, 0x8e, 0xbb, 0xb3, 0x5b, 0xd6, 0x8d, 0x9a, 0x93, + 0xad, 0xf1, 0x4b, 0xe8, 0xec, 0x11, 0xa2, 0xb4, 0x38, 0xf4, 0x7d, 0x4c, 0x85, 0x44, 0x17, 0xa0, + 0x11, 0x0b, 0xca, 0x73, 0x4d, 0x75, 0xb5, 0x1c, 0x10, 0x74, 0x13, 0xe6, 0x7d, 0x49, 0x03, 0xad, + 0xa2, 0xb5, 0xbb, 0xb6, 0x53, 0x60, 0xb3, 0x63, 0xa8, 0x38, 0x1a, 0x82, 0x6f, 0xc1, 0xf2, 0x7e, + 0x10, 0xc9, 0xb1, 0x12, 0x9f, 0xa7, 0x17, 0xdf, 0x84, 0x4e, 0x9f, 0xca, 0x4f, 0x82, 0x3e, 0x85, + 0x79, 0x85, 0x9b, 0xce, 0xf1, 0x16, 0xd4, 0x14, 0x01, 0xd1, 0x9d, 0xdd, 0x9a, 0x9b, 0x4e, 0x32, + 0xc1, 0xe0, 0x06, 0xd4, 0x34, 0x4b, 0xfc, 0x2d, 0xd8, 0x4f, 0x7d, 0x21, 0x1d, 0xea, 0xb1, 0x20, + 0xa0, 0x21, 0x71, 0xa5, 0xcf, 0x42, 0x71, 0xae, 0x43, 0xae, 0x40, 0x2b, 0x77, 0x7b, 0x62, 0xb2, + 0xe9, 0x40, 0xe6, 0x77, 0x81, 0xbf, 0x80, 0x8d, 0x89, 0x7a, 0x45, 0xc4, 0x42, 0x41, 0xab, 0xe7, + 0xad, 0x53, 0xe7, 0x7f, 0xb7, 0xa0, 0xf1, 0x22, 0x59, 0xa2, 0x0e, 0xcc, 0x66, 0x04, 0x66, 0x7d, + 0x82, 0x10, 0xcc, 0x87, 0x6e, 0x40, 0xf5, 0x6b, 0x34, 0x1d, 0xfd, 0x8d, 0xb6, 0xa0, 0x45, 0xa8, + 0xf0, 0xb8, 0x1f, 0x29, 0x43, 0xdd, 0x39, 0xbd, 0x55, 0x14, 0xa1, 0x2e, 0x34, 0x22, 0xdf, 0x93, + 0x31, 0xa7, 0xdd, 0x79, 0xbd, 0x6b, 0x96, 0xe8, 0x2e, 0x34, 0x23, 0xee, 0x7b, 0x74, 0x18, 0x0b, + 0xd2, 0xad, 0xe9, 0x27, 0x46, 0x25, 0xef, 0x3d, 0x63, 0x21, 0x1d, 0x3b, 0x0b, 0x1a, 0x74, 0x28, + 0x08, 0xda, 0x04, 0xf0, 0x5c, 0x49, 0x8f, 0x18, 0xf7, 0xa9, 0xe8, 0xd6, 0x13, 0xf2, 0xb9, 0x04, + 0x3f, 0x81, 0x55, 0x75, 0xf9, 0x94, 0x7f, 0x7e, 0xeb, 0x7b, 0xb0, 0x90, 0x5e, 0x31, 0xb9, 0x72, + 0x6b, 0x77, 0xb5, 0x64, 0x27, 0x3d, 0xe0, 0x64, 0x28, 0xbc, 0x0d, 0x2b, 0x7d, 0x6a, 0x14, 0x99, + 0x57, 0xa9, 0xf8, 0x03, 0xdf, 0x81, 0xb5, 0x03, 0xea, 0x72, 0x6f, 0x94, 0x1b, 0x4c, 0x80, 0xab, + 0x50, 0x7b, 0x1f, 0x53, 0x3e, 0x4e, 0xb1, 0xc9, 0x02, 0x3f, 0x81, 0xf5, 0x2a, 0x3c, 0xe5, 0xb7, + 0x03, 0x0d, 0x4e, 0x45, 0x7c, 0x7c, 0x0e, 0x3d, 0x03, 0xc2, 0x21, 0x2c, 0xf5, 0xa9, 0xfc, 0x26, + 0x66, 0x92, 0x1a, 0x93, 0x3b, 0xd0, 0x70, 0x09, 0xe1, 0x54, 0x08, 0x6d, 0xb4, 0xaa, 0x62, 0x2f, + 0xd9, 0x73, 0x0c, 0xe8, 0xf3, 0xa2, 0x76, 0x0f, 0x96, 0x73, 0x7b, 0x29, 0xe7, 0x3b, 0xb0, 0xe0, + 0x31, 0x21, 0xf5, 0xdb, 0x59, 0x53, 0xdf, 0xae, 0xa1, 0x30, 0x87, 0x82, 0x60, 0x06, 0xcb, 0x07, + 0x23, 0x3f, 0x7a, 0xce, 0x09, 0xe5, 0xff, 0x08, 0xe7, 0xff, 0xc1, 0x4a, 0xc1, 0x60, 0x1e, 0xfe, + 0x92, 0xbb, 0xde, 0x3b, 0x3f, 0x3c, 0xca, 0x73, 0x0b, 0x8c, 0x68, 0x40, 0xf0, 0x2f, 0x16, 0x34, + 0x52, 0xbb, 0xe8, 0x1a, 0x74, 0x84, 0xe4, 0x94, 0xca, 0x61, 0x91, 0x65, 0xd3, 0x69, 0x27, 0x52, + 0x03, 0x43, 0x30, 0xef, 0x99, 0x32, 0xd7, 0x74, 0xf4, 0xb7, 0x0a, 0x00, 0x21, 0x5d, 0x49, 0xd3, + 0x7c, 0x48, 0x16, 0x2a, 0x13, 0x3c, 0x16, 0x87, 0x92, 0x8f, 0x4d, 0x26, 0xa4, 0x4b, 0x74, 0x11, + 0x16, 0x3e, 0xfa, 0xd1, 0xd0, 0x63, 0x84, 0xea, 0x44, 0xa8, 0x39, 0x8d, 0x8f, 0x7e, 0xd4, 0x63, + 0x84, 0xe2, 0x57, 0x50, 0xd3, 0xae, 0x44, 0xdb, 0xd0, 0xf6, 0x62, 0xce, 0x69, 0xe8, 0x8d, 0x13, + 0x60, 0xc2, 0x66, 0xd1, 0x08, 0x15, 0x5a, 0x19, 0x8e, 0x43, 0x5f, 0x0a, 0xcd, 0x66, 0xce, 0x49, + 0x16, 0x4a, 0x1a, 0xba, 0x21, 0x13, 0x9a, 0x4e, 0xcd, 0x49, 0x16, 0xb8, 0x0f, 0x9b, 0x7d, 0x2a, + 0x0f, 0xe2, 0x28, 0x62, 0x5c, 0x52, 0xd2, 0x4b, 0xf4, 0xf8, 0x34, 0x8f, 0xcb, 0x6b, 0xd0, 0x29, + 0x99, 0x34, 0x05, 0xa3, 0x5d, 0xb4, 0x29, 0xf0, 0xf7, 0x70, 0xb1, 0x97, 0x09, 0xc2, 0x13, 0xca, + 0x85, 0xcf, 0x42, 0xf3, 0xc8, 0xd7, 0x61, 0xfe, 0x2d, 0x67, 0xc1, 0x19, 0x31, 0xa2, 0xf7, 0x55, + 0xc9, 0x93, 0x2c, 0xb9, 0x58, 0xe2, 0xc9, 0xba, 0x64, 0xda, 0x01, 0x7f, 0x59, 0xd0, 0xe9, 0x71, + 0x4a, 0x7c, 0x55, 0xaf, 0xc9, 0x20, 0x7c, 0xcb, 0xd0, 0x6d, 0x40, 0x9e, 0x96, 0x0c, 0x3d, 0x97, + 0x93, 0x61, 0x18, 0x07, 0x6f, 0x28, 0x4f, 0xfd, 0xb1, 0xec, 0x65, 0xd8, 0xaf, 0xb5, 0x1c, 0x5d, + 0x87, 0xa5, 0x22, 0xda, 0x3b, 0x39, 0x49, 0x5b, 0x52, 0x3b, 0x87, 0xf6, 0x4e, 0x4e, 0xd0, 0xff, + 0x61, 0xa3, 0x88, 0xa3, 0x1f, 0x22, 0x9f, 0xeb, 0xf2, 0x39, 0x1c, 0x53, 0x97, 0xa7, 0xbe, 0xeb, + 0xe6, 0x67, 0xf6, 0x33, 0xc0, 0x77, 0xd4, 0xe5, 0xe8, 0x11, 0x5c, 0x9a, 0x72, 0x3c, 0x60, 0xa1, + 0x1c, 0xe9, 0x27, 0xaf, 0x39, 0x17, 0x27, 0x9d, 0x7f, 0xa6, 0x00, 0x78, 0x0c, 0xed, 0xde, 0xc8, + 0xe5, 0x47, 0x59, 0x4e, 0xff, 0x07, 0xea, 0x6e, 0xa0, 0x22, 0xe4, 0x0c, 0xe7, 0xa5, 0x08, 0xf4, + 0x10, 0x5a, 0x05, 0xeb, 0x69, 0xc3, 0xdc, 0x28, 0x67, 0x48, 0xc9, 0x89, 0x0e, 0xe4, 0x4c, 0xf0, + 0x7d, 0xe8, 0x18, 0xd3, 0xf9, 0xd3, 0x4b, 0xee, 0x86, 0xc2, 0xf5, 0xf4, 0x15, 0xb2, 0x64, 0x69, + 0x17, 0xa4, 0x03, 0x82, 0x7f, 0x80, 0xa6, 0xce, 0x30, 0x3d, 0x13, 0x98, 0x6e, 0x6d, 0x9d, 0xdb, + 0xad, 0x55, 0x54, 0xa8, 0xca, 0x90, 0xf2, 0x9c, 0x18, 0x15, 0x6a, 0x1f, 0xff, 0x34, 0x0b, 0x2d, + 0x93, 0xc2, 0xf1, 0xb1, 0x54, 0x89, 0xc2, 0xd4, 0x32, 0x27, 0xd4, 0xd0, 0xeb, 0x01, 0x41, 0xf7, + 0x60, 0x55, 0x8c, 0xfc, 0x28, 0x52, 0xb9, 0x5d, 0x4c, 0xf2, 0x24, 0x9a, 0x90, 0xd9, 0x7b, 0x99, + 0x25, 0x3b, 0xba, 0x0f, 0xed, 0xec, 0x84, 0x66, 0x33, 0x37, 0x95, 0xcd, 0xa2, 0x01, 0xf6, 0x98, + 0x90, 0xe8, 0x11, 0x2c, 0x67, 0x07, 0x4d, 0x6d, 0x98, 0x3f, 0xa3, 0x82, 0x2d, 0x19, 0xb4, 0xa9, + 0x19, 0xb7, 0x4d, 0x25, 0xab, 0xe9, 0x4a, 0xb6, 0x5e, 0x3a, 0x95, 0x39, 0xd4, 0x94, 0x32, 0x02, + 0x97, 0x0e, 0x68, 0x48, 0xb4, 0xbc, 0xc7, 0xc2, 0xb7, 0x3e, 0x0f, 0x74, 0xd8, 0x14, 0xda, 0x0d, + 0x0d, 0x5c, 0xff, 0xd8, 0xb4, 0x1b, 0xbd, 0x40, 0x3b, 0x50, 0xd3, 0xae, 0x49, 0x7d, 0xdc, 0x3d, + 0x6d, 0x23, 0xf1, 0xa9, 0x93, 0xc0, 0xf0, 0x9f, 0x16, 0xac, 0xbc, 0x38, 0x76, 0x3d, 0x5a, 0xaa, + 0xd1, 0x53, 0x27, 0x91, 0x6d, 0x68, 0xeb, 0x0d, 0x53, 0x0a, 0x52, 0x3f, 0x2f, 0x2a, 0xa1, 0xa9, + 0x06, 0xc5, 0x0a, 0x3f, 0xf7, 0x29, 0x15, 0x3e, 0xbb, 0x49, 0xad, 0x78, 0x93, 0x4a, 0x6c, 0xd7, + 0x3f, 0x2f, 0xb6, 0x1f, 0x03, 0x2a, 0x5e, 0x2b, 0x6b, 0xb9, 0xa9, 0x77, 0xac, 0x4f, 0xf3, 0xce, + 0x0e, 0x34, 0xf7, 0x88, 0x71, 0xca, 0x55, 0x58, 0xf4, 0x58, 0x28, 0xe9, 0x07, 0x39, 0x7c, 0x47, + 0xc7, 0xa6, 0x2a, 0xb6, 0x52, 0xd9, 0x57, 0x74, 0x2c, 0xf0, 0x5d, 0x00, 0x85, 0x4f, 0xad, 0x5d, + 0x85, 0x39, 0x97, 0x98, 0xe6, 0xbe, 0x54, 0xf1, 0x81, 0xa3, 0xf6, 0xf0, 0x03, 0x98, 0xdd, 0x23, + 0x4a, 0xb3, 0x62, 0xce, 0xa9, 0x27, 0x87, 0x31, 0x37, 0x2f, 0xda, 0x32, 0xb2, 0x43, 0x7e, 0xac, + 0xfa, 0x8d, 0xb2, 0x62, 0xfa, 0x8d, 0xfa, 0xde, 0xfd, 0xc3, 0x82, 0x96, 0xca, 0xb0, 0x03, 0xca, + 0x4f, 0x7c, 0x8f, 0xa2, 0x87, 0xba, 0x8b, 0xe9, 0xa4, 0xdc, 0xa8, 0x7a, 0xbc, 0x30, 0x78, 0xdb, + 0xe5, 0x50, 0x4f, 0x26, 0xd3, 0x19, 0xf4, 0x00, 0x1a, 0xe9, 0x74, 0x5c, 0x39, 0x5d, 0x9e, 0x99, + 0xed, 0x95, 0x53, 0x19, 0x8e, 0x67, 0xd0, 0x97, 0xd0, 0xcc, 0xe6, 0x70, 0x74, 0xf9, 0xb4, 0xfe, + 0xa2, 0x82, 0x89, 0xe6, 0x77, 0x7f, 0xb6, 0x60, 0xad, 0x3c, 0xbf, 0x9a, 0x6b, 0xfd, 0x08, 0xff, + 0x9a, 0x30, 0xdc, 0xa2, 0x7f, 0x97, 0xd4, 0x4c, 0x1f, 0xab, 0xed, 0x1b, 0xe7, 0x03, 0x93, 0x07, + 0x53, 0x2c, 0x66, 0x61, 0x2d, 0x1d, 0xbc, 0x7a, 0xae, 0x74, 0x8f, 0xd9, 0x91, 0x61, 0xd1, 0x87, + 0xc5, 0xe2, 0x94, 0x89, 0x26, 0xdc, 0xc2, 0xbe, 0x7a, 0xca, 0x52, 0x75, 0xe8, 0xc3, 0x33, 0xe8, + 0x31, 0x40, 0x3e, 0x64, 0xa2, 0xcd, 0xaa, 0xab, 0xcb, 0xd3, 0xa7, 0x3d, 0x71, 0x26, 0xc4, 0x33, + 0xe8, 0x35, 0x74, 0xca, 0x63, 0x25, 0xc2, 0x25, 0xe4, 0xc4, 0x11, 0xd5, 0xde, 0x3e, 0x13, 0x93, + 0x79, 0xe1, 0x57, 0x0b, 0x96, 0x0e, 0xd2, 0xe2, 0x65, 0xee, 0x3f, 0x80, 0x05, 0x33, 0x0d, 0xa2, + 0x4b, 0x55, 0xd2, 0xc5, 0xa1, 0xd4, 0xbe, 0x3c, 0x65, 0x37, 0xf3, 0xc0, 0x53, 0x68, 0x66, 0x43, + 0x5a, 0x25, 0x58, 0xaa, 0xd3, 0xa2, 0xbd, 0x39, 0x6d, 0x3b, 0x23, 0xfb, 0x9b, 0x05, 0x4b, 0xa6, + 0xf4, 0x18, 0xb2, 0xaf, 0x61, 0x7d, 0xf2, 0x90, 0x33, 0xf1, 0xd9, 0x6e, 0x55, 0x09, 0x9f, 0x31, + 0x1d, 0xe1, 0x19, 0xd4, 0x87, 0x46, 0x32, 0xf0, 0x48, 0x74, 0xbd, 0x9c, 0x0b, 0xd3, 0xc6, 0x21, + 0x7b, 0x42, 0x73, 0xc1, 0x33, 0xbb, 0x87, 0xd0, 0x79, 0xe1, 0x8e, 0x03, 0x1a, 0x66, 0x19, 0xdc, + 0x83, 0x7a, 0xd2, 0x91, 0x91, 0x5d, 0xd6, 0x5c, 0x9c, 0x10, 0xec, 0x8d, 0x89, 0x7b, 0x99, 0x43, + 0x46, 0xb0, 0xb8, 0xaf, 0x2a, 0xa8, 0x51, 0xfa, 0x4a, 0xfd, 0x60, 0x99, 0xd0, 0x48, 0xd0, 0xcd, + 0x4a, 0x34, 0x4c, 0x6f, 0x36, 0x53, 0x72, 0xf6, 0x0d, 0x2c, 0xf5, 0x46, 0xd4, 0x7b, 0xc7, 0xe2, + 0xec, 0x06, 0xcf, 0x01, 0xf2, 0xba, 0x5b, 0x89, 0xee, 0x53, 0x7d, 0xc6, 0xbe, 0x32, 0x75, 0x3f, + 0xbb, 0xcd, 0x13, 0x55, 0x82, 0x8d, 0xf6, 0x07, 0x50, 0xef, 0xab, 0x19, 0x5c, 0xa0, 0xf5, 0x6a, + 0x39, 0x4d, 0x35, 0x5e, 0x38, 0x25, 0x37, 0x9a, 0xde, 0xd4, 0xf5, 0x9f, 0x1b, 0xff, 0xfd, 0x3b, + 0x00, 0x00, 0xff, 0xff, 0xb2, 0xa0, 0x6e, 0x6c, 0xea, 0x10, 0x00, 0x00, } From dc7effd601ee18d0963928ea196e0c2c447d5b15 Mon Sep 17 00:00:00 2001 From: sebright Date: Mon, 1 Oct 2018 22:44:56 -0700 Subject: [PATCH 11/91] adservice: find relevant ads by category (#61) The ad service now returns ads matching the categories of the product that is currently displayed. Changes in this commit: - List all products' categories in products.json. - Pass the current product's categories from the frontend to the ad service when looking up ads. - Store a statically initialized multimap from product category to ad in the ad service. - Return all ads matching the given categories when handling an ads request. The ad service continues to return random ads when no categories are given or no ads match the categories. --- .../src/main/java/hipstershop/AdService.java | 68 +- src/cartservice/probe/genproto/demo.pb.go | 723 ++++++++++----- src/checkoutservice/genproto/demo.pb.go | 723 ++++++++++----- src/currencyservice/proto/demo.proto | 14 +- src/frontend/Gopkg.lock | 11 - src/frontend/Gopkg.toml | 4 - src/frontend/handlers.go | 8 +- src/frontend/rpc.go | 4 +- src/paymentservice/proto/demo.proto | 14 +- src/productcatalogservice/products.json | 27 +- src/shippingservice/genproto/demo.pb.go | 861 ++++++++++-------- 11 files changed, 1532 insertions(+), 925 deletions(-) diff --git a/src/adservice/src/main/java/hipstershop/AdService.java b/src/adservice/src/main/java/hipstershop/AdService.java index 75ce76f..dfb1e40 100644 --- a/src/adservice/src/main/java/hipstershop/AdService.java +++ b/src/adservice/src/main/java/hipstershop/AdService.java @@ -17,6 +17,8 @@ package hipstershop; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.Iterables; import hipstershop.Demo.Ad; import hipstershop.Demo.AdRequest; import hipstershop.Demo.AdResponse; @@ -42,6 +44,7 @@ import io.opencensus.trace.Tracer; import io.opencensus.trace.Tracing; import io.opencensus.trace.samplers.Samplers; import java.io.IOException; +import java.util.Collection; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -109,8 +112,8 @@ public class AdService { try (Scope scope = spanBuilder.startScopedSpan()) { Span span = tracer.getCurrentSpan(); span.putAttribute("method", AttributeValue.stringAttributeValue("getAds")); - List ads = new ArrayList<>(); - logger.info("received ad request (context_words=" + req.getContextKeysCount() + ")"); + List allAds = new ArrayList<>(); + logger.info("received ad request (context_words=" + req.getContextKeysList() + ")"); if (req.getContextKeysCount() > 0) { span.addAnnotation( "Constructing Ads using context", @@ -120,21 +123,19 @@ public class AdService { "Context Keys length", AttributeValue.longAttributeValue(req.getContextKeysCount()))); for (int i = 0; i < req.getContextKeysCount(); i++) { - Ad ad = service.getAdsByKey(req.getContextKeys(i)); - if (ad != null) { - ads.add(ad); - } + Collection ads = service.getAdsByCategory(req.getContextKeys(i)); + allAds.addAll(ads); } } else { span.addAnnotation("No Context provided. Constructing random Ads."); - ads = service.getDefaultAds(); + allAds = service.getRandomAds(); } - if (ads.isEmpty()) { - // Serve default ads. + if (allAds.isEmpty()) { + // Serve random ads. span.addAnnotation("No Ads found based on context. Constructing random Ads."); - ads = service.getDefaultAds(); + allAds = service.getRandomAds(); } - AdResponse reply = AdResponse.newBuilder().addAllAds(ads).build(); + AdResponse reply = AdResponse.newBuilder().addAllAds(allAds).build(); responseObserver.onNext(reply); responseObserver.onCompleted(); } catch (StatusRuntimeException e) { @@ -144,18 +145,19 @@ public class AdService { } } - static final HashMap cacheMap = new HashMap(); + static final ImmutableListMultimap adsMap = createAdsMap(); - Ad getAdsByKey(String key) { - return cacheMap.get(key); + Collection getAdsByCategory(String category) { + return adsMap.get(category); } + private static final Random random = new Random(); - public List getDefaultAds() { + public List getRandomAds() { List ads = new ArrayList<>(MAX_ADS_TO_SERVE); - Object[] keys = cacheMap.keySet().toArray(); + Collection allAds = adsMap.values(); for (int i=0; i createAdsMap() { + Ad camera = Ad.newBuilder().setRedirectUrl("/product/2ZYFJ3GM2N") + .setText("Film camera for sale. 50% off.").build(); + Ad lens = Ad.newBuilder().setRedirectUrl("/product/66VCHSJNUP") + .setText("Vintage camera lens for sale. 20% off.").build(); + Ad recordPlayer = Ad.newBuilder().setRedirectUrl("/product/0PUK6V6EV0") + .setText("Vintage record player for sale. 30% off.").build(); + Ad bike = Ad.newBuilder().setRedirectUrl("/product/9SIQT8TOJO") + .setText("City Bike for sale. 10% off.").build(); + Ad baristaKit = Ad.newBuilder().setRedirectUrl("/product/1YMWWN1N4O") + .setText("Home Barista kitchen kit for sale. Buy one, get second kit for free").build(); + Ad airPlant = Ad.newBuilder().setRedirectUrl("/product/6E92ZMYYFZ") + .setText("Air plants for sale. Buy two, get third one for free").build(); + Ad terrarium = Ad.newBuilder().setRedirectUrl("/product/L9ECAV7KIM") + .setText("Terrarium for sale. Buy one, get second one for free").build(); + return ImmutableListMultimap.builder() + .putAll("photography", camera, lens) + .putAll("vintage", camera, lens, recordPlayer) + .put("cycling", bike) + .put("cookware", baristaKit) + .putAll("gardening", airPlant, terrarium) + .build(); } public static void initStackdriver() { @@ -222,8 +238,6 @@ public class AdService { public static void main(String[] args) throws IOException, InterruptedException { // Add final keyword to pass checkStyle. - initializeAds(); - new Thread( new Runnable() { public void run(){ initStackdriver(); diff --git a/src/cartservice/probe/genproto/demo.pb.go b/src/cartservice/probe/genproto/demo.pb.go index 4fdb7f0..f59af20 100644 --- a/src/cartservice/probe/genproto/demo.pb.go +++ b/src/cartservice/probe/genproto/demo.pb.go @@ -3,9 +3,11 @@ package hipstershop -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) import ( context "golang.org/x/net/context" @@ -24,8 +26,8 @@ var _ = math.Inf const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package type CartItem struct { - ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId" json:"product_id,omitempty"` - Quantity int32 `protobuf:"varint,2,opt,name=quantity" json:"quantity,omitempty"` + ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` + Quantity int32 `protobuf:"varint,2,opt,name=quantity,proto3" json:"quantity,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -35,16 +37,17 @@ func (m *CartItem) Reset() { *m = CartItem{} } func (m *CartItem) String() string { return proto.CompactTextString(m) } func (*CartItem) ProtoMessage() {} func (*CartItem) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{0} + return fileDescriptor_ca53982754088a9d, []int{0} } + func (m *CartItem) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CartItem.Unmarshal(m, b) } func (m *CartItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CartItem.Marshal(b, m, deterministic) } -func (dst *CartItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_CartItem.Merge(dst, src) +func (m *CartItem) XXX_Merge(src proto.Message) { + xxx_messageInfo_CartItem.Merge(m, src) } func (m *CartItem) XXX_Size() int { return xxx_messageInfo_CartItem.Size(m) @@ -70,8 +73,8 @@ func (m *CartItem) GetQuantity() int32 { } type AddItemRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - Item *CartItem `protobuf:"bytes,2,opt,name=item" json:"item,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Item *CartItem `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -81,16 +84,17 @@ func (m *AddItemRequest) Reset() { *m = AddItemRequest{} } func (m *AddItemRequest) String() string { return proto.CompactTextString(m) } func (*AddItemRequest) ProtoMessage() {} func (*AddItemRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{1} + return fileDescriptor_ca53982754088a9d, []int{1} } + func (m *AddItemRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AddItemRequest.Unmarshal(m, b) } func (m *AddItemRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_AddItemRequest.Marshal(b, m, deterministic) } -func (dst *AddItemRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_AddItemRequest.Merge(dst, src) +func (m *AddItemRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddItemRequest.Merge(m, src) } func (m *AddItemRequest) XXX_Size() int { return xxx_messageInfo_AddItemRequest.Size(m) @@ -116,7 +120,7 @@ func (m *AddItemRequest) GetItem() *CartItem { } type EmptyCartRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -126,16 +130,17 @@ func (m *EmptyCartRequest) Reset() { *m = EmptyCartRequest{} } func (m *EmptyCartRequest) String() string { return proto.CompactTextString(m) } func (*EmptyCartRequest) ProtoMessage() {} func (*EmptyCartRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{2} + return fileDescriptor_ca53982754088a9d, []int{2} } + func (m *EmptyCartRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EmptyCartRequest.Unmarshal(m, b) } func (m *EmptyCartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_EmptyCartRequest.Marshal(b, m, deterministic) } -func (dst *EmptyCartRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_EmptyCartRequest.Merge(dst, src) +func (m *EmptyCartRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_EmptyCartRequest.Merge(m, src) } func (m *EmptyCartRequest) XXX_Size() int { return xxx_messageInfo_EmptyCartRequest.Size(m) @@ -154,7 +159,7 @@ func (m *EmptyCartRequest) GetUserId() string { } type GetCartRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -164,16 +169,17 @@ func (m *GetCartRequest) Reset() { *m = GetCartRequest{} } func (m *GetCartRequest) String() string { return proto.CompactTextString(m) } func (*GetCartRequest) ProtoMessage() {} func (*GetCartRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{3} + return fileDescriptor_ca53982754088a9d, []int{3} } + func (m *GetCartRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetCartRequest.Unmarshal(m, b) } func (m *GetCartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetCartRequest.Marshal(b, m, deterministic) } -func (dst *GetCartRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetCartRequest.Merge(dst, src) +func (m *GetCartRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetCartRequest.Merge(m, src) } func (m *GetCartRequest) XXX_Size() int { return xxx_messageInfo_GetCartRequest.Size(m) @@ -192,8 +198,8 @@ func (m *GetCartRequest) GetUserId() string { } type Cart struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -203,16 +209,17 @@ func (m *Cart) Reset() { *m = Cart{} } func (m *Cart) String() string { return proto.CompactTextString(m) } func (*Cart) ProtoMessage() {} func (*Cart) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{4} + return fileDescriptor_ca53982754088a9d, []int{4} } + func (m *Cart) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Cart.Unmarshal(m, b) } func (m *Cart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Cart.Marshal(b, m, deterministic) } -func (dst *Cart) XXX_Merge(src proto.Message) { - xxx_messageInfo_Cart.Merge(dst, src) +func (m *Cart) XXX_Merge(src proto.Message) { + xxx_messageInfo_Cart.Merge(m, src) } func (m *Cart) XXX_Size() int { return xxx_messageInfo_Cart.Size(m) @@ -247,16 +254,17 @@ func (m *Empty) Reset() { *m = Empty{} } func (m *Empty) String() string { return proto.CompactTextString(m) } func (*Empty) ProtoMessage() {} func (*Empty) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{5} + return fileDescriptor_ca53982754088a9d, []int{5} } + func (m *Empty) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Empty.Unmarshal(m, b) } func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Empty.Marshal(b, m, deterministic) } -func (dst *Empty) XXX_Merge(src proto.Message) { - xxx_messageInfo_Empty.Merge(dst, src) +func (m *Empty) XXX_Merge(src proto.Message) { + xxx_messageInfo_Empty.Merge(m, src) } func (m *Empty) XXX_Size() int { return xxx_messageInfo_Empty.Size(m) @@ -268,8 +276,8 @@ func (m *Empty) XXX_DiscardUnknown() { var xxx_messageInfo_Empty proto.InternalMessageInfo type ListRecommendationsRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - ProductIds []string `protobuf:"bytes,2,rep,name=product_ids,json=productIds" json:"product_ids,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ProductIds []string `protobuf:"bytes,2,rep,name=product_ids,json=productIds,proto3" json:"product_ids,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -279,16 +287,17 @@ func (m *ListRecommendationsRequest) Reset() { *m = ListRecommendationsR func (m *ListRecommendationsRequest) String() string { return proto.CompactTextString(m) } func (*ListRecommendationsRequest) ProtoMessage() {} func (*ListRecommendationsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{6} + return fileDescriptor_ca53982754088a9d, []int{6} } + func (m *ListRecommendationsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListRecommendationsRequest.Unmarshal(m, b) } func (m *ListRecommendationsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListRecommendationsRequest.Marshal(b, m, deterministic) } -func (dst *ListRecommendationsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListRecommendationsRequest.Merge(dst, src) +func (m *ListRecommendationsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListRecommendationsRequest.Merge(m, src) } func (m *ListRecommendationsRequest) XXX_Size() int { return xxx_messageInfo_ListRecommendationsRequest.Size(m) @@ -314,7 +323,7 @@ func (m *ListRecommendationsRequest) GetProductIds() []string { } type ListRecommendationsResponse struct { - ProductIds []string `protobuf:"bytes,1,rep,name=product_ids,json=productIds" json:"product_ids,omitempty"` + ProductIds []string `protobuf:"bytes,1,rep,name=product_ids,json=productIds,proto3" json:"product_ids,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -324,16 +333,17 @@ func (m *ListRecommendationsResponse) Reset() { *m = ListRecommendations func (m *ListRecommendationsResponse) String() string { return proto.CompactTextString(m) } func (*ListRecommendationsResponse) ProtoMessage() {} func (*ListRecommendationsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{7} + return fileDescriptor_ca53982754088a9d, []int{7} } + func (m *ListRecommendationsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListRecommendationsResponse.Unmarshal(m, b) } func (m *ListRecommendationsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListRecommendationsResponse.Marshal(b, m, deterministic) } -func (dst *ListRecommendationsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListRecommendationsResponse.Merge(dst, src) +func (m *ListRecommendationsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListRecommendationsResponse.Merge(m, src) } func (m *ListRecommendationsResponse) XXX_Size() int { return xxx_messageInfo_ListRecommendationsResponse.Size(m) @@ -352,11 +362,14 @@ func (m *ListRecommendationsResponse) GetProductIds() []string { } type Product struct { - Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` - Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` - Picture string `protobuf:"bytes,4,opt,name=picture" json:"picture,omitempty"` - PriceUsd *Money `protobuf:"bytes,5,opt,name=price_usd,json=priceUsd" json:"price_usd,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + Picture string `protobuf:"bytes,4,opt,name=picture,proto3" json:"picture,omitempty"` + PriceUsd *Money `protobuf:"bytes,5,opt,name=price_usd,json=priceUsd,proto3" json:"price_usd,omitempty"` + // Categories such as "vintage" or "gardening" that can be used to look up + // other related products. + Categories []string `protobuf:"bytes,6,rep,name=categories,proto3" json:"categories,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -366,16 +379,17 @@ func (m *Product) Reset() { *m = Product{} } func (m *Product) String() string { return proto.CompactTextString(m) } func (*Product) ProtoMessage() {} func (*Product) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{8} + return fileDescriptor_ca53982754088a9d, []int{8} } + func (m *Product) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Product.Unmarshal(m, b) } func (m *Product) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Product.Marshal(b, m, deterministic) } -func (dst *Product) XXX_Merge(src proto.Message) { - xxx_messageInfo_Product.Merge(dst, src) +func (m *Product) XXX_Merge(src proto.Message) { + xxx_messageInfo_Product.Merge(m, src) } func (m *Product) XXX_Size() int { return xxx_messageInfo_Product.Size(m) @@ -421,8 +435,15 @@ func (m *Product) GetPriceUsd() *Money { return nil } +func (m *Product) GetCategories() []string { + if m != nil { + return m.Categories + } + return nil +} + type ListProductsResponse struct { - Products []*Product `protobuf:"bytes,1,rep,name=products" json:"products,omitempty"` + Products []*Product `protobuf:"bytes,1,rep,name=products,proto3" json:"products,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -432,16 +453,17 @@ func (m *ListProductsResponse) Reset() { *m = ListProductsResponse{} } func (m *ListProductsResponse) String() string { return proto.CompactTextString(m) } func (*ListProductsResponse) ProtoMessage() {} func (*ListProductsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{9} + return fileDescriptor_ca53982754088a9d, []int{9} } + func (m *ListProductsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListProductsResponse.Unmarshal(m, b) } func (m *ListProductsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListProductsResponse.Marshal(b, m, deterministic) } -func (dst *ListProductsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListProductsResponse.Merge(dst, src) +func (m *ListProductsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListProductsResponse.Merge(m, src) } func (m *ListProductsResponse) XXX_Size() int { return xxx_messageInfo_ListProductsResponse.Size(m) @@ -460,7 +482,7 @@ func (m *ListProductsResponse) GetProducts() []*Product { } type GetProductRequest struct { - Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -470,16 +492,17 @@ func (m *GetProductRequest) Reset() { *m = GetProductRequest{} } func (m *GetProductRequest) String() string { return proto.CompactTextString(m) } func (*GetProductRequest) ProtoMessage() {} func (*GetProductRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{10} + return fileDescriptor_ca53982754088a9d, []int{10} } + func (m *GetProductRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetProductRequest.Unmarshal(m, b) } func (m *GetProductRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetProductRequest.Marshal(b, m, deterministic) } -func (dst *GetProductRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetProductRequest.Merge(dst, src) +func (m *GetProductRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetProductRequest.Merge(m, src) } func (m *GetProductRequest) XXX_Size() int { return xxx_messageInfo_GetProductRequest.Size(m) @@ -498,7 +521,7 @@ func (m *GetProductRequest) GetId() string { } type SearchProductsRequest struct { - Query string `protobuf:"bytes,1,opt,name=query" json:"query,omitempty"` + Query string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -508,16 +531,17 @@ func (m *SearchProductsRequest) Reset() { *m = SearchProductsRequest{} } func (m *SearchProductsRequest) String() string { return proto.CompactTextString(m) } func (*SearchProductsRequest) ProtoMessage() {} func (*SearchProductsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{11} + return fileDescriptor_ca53982754088a9d, []int{11} } + func (m *SearchProductsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SearchProductsRequest.Unmarshal(m, b) } func (m *SearchProductsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SearchProductsRequest.Marshal(b, m, deterministic) } -func (dst *SearchProductsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_SearchProductsRequest.Merge(dst, src) +func (m *SearchProductsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SearchProductsRequest.Merge(m, src) } func (m *SearchProductsRequest) XXX_Size() int { return xxx_messageInfo_SearchProductsRequest.Size(m) @@ -536,7 +560,7 @@ func (m *SearchProductsRequest) GetQuery() string { } type SearchProductsResponse struct { - Results []*Product `protobuf:"bytes,1,rep,name=results" json:"results,omitempty"` + Results []*Product `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -546,16 +570,17 @@ func (m *SearchProductsResponse) Reset() { *m = SearchProductsResponse{} func (m *SearchProductsResponse) String() string { return proto.CompactTextString(m) } func (*SearchProductsResponse) ProtoMessage() {} func (*SearchProductsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{12} + return fileDescriptor_ca53982754088a9d, []int{12} } + func (m *SearchProductsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SearchProductsResponse.Unmarshal(m, b) } func (m *SearchProductsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SearchProductsResponse.Marshal(b, m, deterministic) } -func (dst *SearchProductsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_SearchProductsResponse.Merge(dst, src) +func (m *SearchProductsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_SearchProductsResponse.Merge(m, src) } func (m *SearchProductsResponse) XXX_Size() int { return xxx_messageInfo_SearchProductsResponse.Size(m) @@ -574,8 +599,8 @@ func (m *SearchProductsResponse) GetResults() []*Product { } type GetQuoteRequest struct { - Address *Address `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"` + Address *Address `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -585,16 +610,17 @@ func (m *GetQuoteRequest) Reset() { *m = GetQuoteRequest{} } func (m *GetQuoteRequest) String() string { return proto.CompactTextString(m) } func (*GetQuoteRequest) ProtoMessage() {} func (*GetQuoteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{13} + return fileDescriptor_ca53982754088a9d, []int{13} } + func (m *GetQuoteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetQuoteRequest.Unmarshal(m, b) } func (m *GetQuoteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetQuoteRequest.Marshal(b, m, deterministic) } -func (dst *GetQuoteRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetQuoteRequest.Merge(dst, src) +func (m *GetQuoteRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetQuoteRequest.Merge(m, src) } func (m *GetQuoteRequest) XXX_Size() int { return xxx_messageInfo_GetQuoteRequest.Size(m) @@ -620,7 +646,7 @@ func (m *GetQuoteRequest) GetItems() []*CartItem { } type GetQuoteResponse struct { - CostUsd *Money `protobuf:"bytes,1,opt,name=cost_usd,json=costUsd" json:"cost_usd,omitempty"` + CostUsd *Money `protobuf:"bytes,1,opt,name=cost_usd,json=costUsd,proto3" json:"cost_usd,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -630,16 +656,17 @@ func (m *GetQuoteResponse) Reset() { *m = GetQuoteResponse{} } func (m *GetQuoteResponse) String() string { return proto.CompactTextString(m) } func (*GetQuoteResponse) ProtoMessage() {} func (*GetQuoteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{14} + return fileDescriptor_ca53982754088a9d, []int{14} } + func (m *GetQuoteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetQuoteResponse.Unmarshal(m, b) } func (m *GetQuoteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetQuoteResponse.Marshal(b, m, deterministic) } -func (dst *GetQuoteResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetQuoteResponse.Merge(dst, src) +func (m *GetQuoteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetQuoteResponse.Merge(m, src) } func (m *GetQuoteResponse) XXX_Size() int { return xxx_messageInfo_GetQuoteResponse.Size(m) @@ -658,8 +685,8 @@ func (m *GetQuoteResponse) GetCostUsd() *Money { } type ShipOrderRequest struct { - Address *Address `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"` + Address *Address `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -669,16 +696,17 @@ func (m *ShipOrderRequest) Reset() { *m = ShipOrderRequest{} } func (m *ShipOrderRequest) String() string { return proto.CompactTextString(m) } func (*ShipOrderRequest) ProtoMessage() {} func (*ShipOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{15} + return fileDescriptor_ca53982754088a9d, []int{15} } + func (m *ShipOrderRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShipOrderRequest.Unmarshal(m, b) } func (m *ShipOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ShipOrderRequest.Marshal(b, m, deterministic) } -func (dst *ShipOrderRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ShipOrderRequest.Merge(dst, src) +func (m *ShipOrderRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShipOrderRequest.Merge(m, src) } func (m *ShipOrderRequest) XXX_Size() int { return xxx_messageInfo_ShipOrderRequest.Size(m) @@ -704,7 +732,7 @@ func (m *ShipOrderRequest) GetItems() []*CartItem { } type ShipOrderResponse struct { - TrackingId string `protobuf:"bytes,1,opt,name=tracking_id,json=trackingId" json:"tracking_id,omitempty"` + TrackingId string `protobuf:"bytes,1,opt,name=tracking_id,json=trackingId,proto3" json:"tracking_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -714,16 +742,17 @@ func (m *ShipOrderResponse) Reset() { *m = ShipOrderResponse{} } func (m *ShipOrderResponse) String() string { return proto.CompactTextString(m) } func (*ShipOrderResponse) ProtoMessage() {} func (*ShipOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{16} + return fileDescriptor_ca53982754088a9d, []int{16} } + func (m *ShipOrderResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShipOrderResponse.Unmarshal(m, b) } func (m *ShipOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ShipOrderResponse.Marshal(b, m, deterministic) } -func (dst *ShipOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ShipOrderResponse.Merge(dst, src) +func (m *ShipOrderResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShipOrderResponse.Merge(m, src) } func (m *ShipOrderResponse) XXX_Size() int { return xxx_messageInfo_ShipOrderResponse.Size(m) @@ -742,11 +771,11 @@ func (m *ShipOrderResponse) GetTrackingId() string { } type Address struct { - StreetAddress string `protobuf:"bytes,1,opt,name=street_address,json=streetAddress" json:"street_address,omitempty"` - City string `protobuf:"bytes,2,opt,name=city" json:"city,omitempty"` - State string `protobuf:"bytes,3,opt,name=state" json:"state,omitempty"` - Country string `protobuf:"bytes,4,opt,name=country" json:"country,omitempty"` - ZipCode int32 `protobuf:"varint,5,opt,name=zip_code,json=zipCode" json:"zip_code,omitempty"` + StreetAddress string `protobuf:"bytes,1,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` + City string `protobuf:"bytes,2,opt,name=city,proto3" json:"city,omitempty"` + State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` + Country string `protobuf:"bytes,4,opt,name=country,proto3" json:"country,omitempty"` + ZipCode int32 `protobuf:"varint,5,opt,name=zip_code,json=zipCode,proto3" json:"zip_code,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -756,16 +785,17 @@ func (m *Address) Reset() { *m = Address{} } func (m *Address) String() string { return proto.CompactTextString(m) } func (*Address) ProtoMessage() {} func (*Address) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{17} + return fileDescriptor_ca53982754088a9d, []int{17} } + func (m *Address) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Address.Unmarshal(m, b) } func (m *Address) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Address.Marshal(b, m, deterministic) } -func (dst *Address) XXX_Merge(src proto.Message) { - xxx_messageInfo_Address.Merge(dst, src) +func (m *Address) XXX_Merge(src proto.Message) { + xxx_messageInfo_Address.Merge(m, src) } func (m *Address) XXX_Size() int { return xxx_messageInfo_Address.Size(m) @@ -814,17 +844,17 @@ func (m *Address) GetZipCode() int32 { // Represents an amount of money with its currency type. type Money struct { // The 3-letter currency code defined in ISO 4217. - CurrencyCode string `protobuf:"bytes,1,opt,name=currency_code,json=currencyCode" json:"currency_code,omitempty"` + CurrencyCode string `protobuf:"bytes,1,opt,name=currency_code,json=currencyCode,proto3" json:"currency_code,omitempty"` // The whole units of the amount. // For example if `currencyCode` is `"USD"`, then 1 unit is one US dollar. - Units int64 `protobuf:"varint,2,opt,name=units" json:"units,omitempty"` + Units int64 `protobuf:"varint,2,opt,name=units,proto3" json:"units,omitempty"` // Number of nano (10^-9) units of the amount. // The value must be between -999,999,999 and +999,999,999 inclusive. // If `units` is positive, `nanos` must be positive or zero. // If `units` is zero, `nanos` can be positive, zero, or negative. // If `units` is negative, `nanos` must be negative or zero. // For example $-1.75 is represented as `units`=-1 and `nanos`=-750,000,000. - Nanos int32 `protobuf:"varint,3,opt,name=nanos" json:"nanos,omitempty"` + Nanos int32 `protobuf:"varint,3,opt,name=nanos,proto3" json:"nanos,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -834,16 +864,17 @@ func (m *Money) Reset() { *m = Money{} } func (m *Money) String() string { return proto.CompactTextString(m) } func (*Money) ProtoMessage() {} func (*Money) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{18} + return fileDescriptor_ca53982754088a9d, []int{18} } + func (m *Money) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Money.Unmarshal(m, b) } func (m *Money) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Money.Marshal(b, m, deterministic) } -func (dst *Money) XXX_Merge(src proto.Message) { - xxx_messageInfo_Money.Merge(dst, src) +func (m *Money) XXX_Merge(src proto.Message) { + xxx_messageInfo_Money.Merge(m, src) } func (m *Money) XXX_Size() int { return xxx_messageInfo_Money.Size(m) @@ -877,7 +908,7 @@ func (m *Money) GetNanos() int32 { type GetSupportedCurrenciesResponse struct { // The 3-letter currency code defined in ISO 4217. - CurrencyCodes []string `protobuf:"bytes,1,rep,name=currency_codes,json=currencyCodes" json:"currency_codes,omitempty"` + CurrencyCodes []string `protobuf:"bytes,1,rep,name=currency_codes,json=currencyCodes,proto3" json:"currency_codes,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -887,16 +918,17 @@ func (m *GetSupportedCurrenciesResponse) Reset() { *m = GetSupportedCurr func (m *GetSupportedCurrenciesResponse) String() string { return proto.CompactTextString(m) } func (*GetSupportedCurrenciesResponse) ProtoMessage() {} func (*GetSupportedCurrenciesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{19} + return fileDescriptor_ca53982754088a9d, []int{19} } + func (m *GetSupportedCurrenciesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSupportedCurrenciesResponse.Unmarshal(m, b) } func (m *GetSupportedCurrenciesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetSupportedCurrenciesResponse.Marshal(b, m, deterministic) } -func (dst *GetSupportedCurrenciesResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetSupportedCurrenciesResponse.Merge(dst, src) +func (m *GetSupportedCurrenciesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetSupportedCurrenciesResponse.Merge(m, src) } func (m *GetSupportedCurrenciesResponse) XXX_Size() int { return xxx_messageInfo_GetSupportedCurrenciesResponse.Size(m) @@ -915,9 +947,9 @@ func (m *GetSupportedCurrenciesResponse) GetCurrencyCodes() []string { } type CurrencyConversionRequest struct { - From *Money `protobuf:"bytes,1,opt,name=from" json:"from,omitempty"` + From *Money `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` // The 3-letter currency code defined in ISO 4217. - ToCode string `protobuf:"bytes,2,opt,name=to_code,json=toCode" json:"to_code,omitempty"` + ToCode string `protobuf:"bytes,2,opt,name=to_code,json=toCode,proto3" json:"to_code,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -927,16 +959,17 @@ func (m *CurrencyConversionRequest) Reset() { *m = CurrencyConversionReq func (m *CurrencyConversionRequest) String() string { return proto.CompactTextString(m) } func (*CurrencyConversionRequest) ProtoMessage() {} func (*CurrencyConversionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{20} + return fileDescriptor_ca53982754088a9d, []int{20} } + func (m *CurrencyConversionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CurrencyConversionRequest.Unmarshal(m, b) } func (m *CurrencyConversionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CurrencyConversionRequest.Marshal(b, m, deterministic) } -func (dst *CurrencyConversionRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_CurrencyConversionRequest.Merge(dst, src) +func (m *CurrencyConversionRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CurrencyConversionRequest.Merge(m, src) } func (m *CurrencyConversionRequest) XXX_Size() int { return xxx_messageInfo_CurrencyConversionRequest.Size(m) @@ -962,10 +995,10 @@ func (m *CurrencyConversionRequest) GetToCode() string { } type CreditCardInfo struct { - CreditCardNumber string `protobuf:"bytes,1,opt,name=credit_card_number,json=creditCardNumber" json:"credit_card_number,omitempty"` - CreditCardCvv int32 `protobuf:"varint,2,opt,name=credit_card_cvv,json=creditCardCvv" json:"credit_card_cvv,omitempty"` - CreditCardExpirationYear int32 `protobuf:"varint,3,opt,name=credit_card_expiration_year,json=creditCardExpirationYear" json:"credit_card_expiration_year,omitempty"` - CreditCardExpirationMonth int32 `protobuf:"varint,4,opt,name=credit_card_expiration_month,json=creditCardExpirationMonth" json:"credit_card_expiration_month,omitempty"` + CreditCardNumber string `protobuf:"bytes,1,opt,name=credit_card_number,json=creditCardNumber,proto3" json:"credit_card_number,omitempty"` + CreditCardCvv int32 `protobuf:"varint,2,opt,name=credit_card_cvv,json=creditCardCvv,proto3" json:"credit_card_cvv,omitempty"` + CreditCardExpirationYear int32 `protobuf:"varint,3,opt,name=credit_card_expiration_year,json=creditCardExpirationYear,proto3" json:"credit_card_expiration_year,omitempty"` + CreditCardExpirationMonth int32 `protobuf:"varint,4,opt,name=credit_card_expiration_month,json=creditCardExpirationMonth,proto3" json:"credit_card_expiration_month,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -975,16 +1008,17 @@ func (m *CreditCardInfo) Reset() { *m = CreditCardInfo{} } func (m *CreditCardInfo) String() string { return proto.CompactTextString(m) } func (*CreditCardInfo) ProtoMessage() {} func (*CreditCardInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{21} + return fileDescriptor_ca53982754088a9d, []int{21} } + func (m *CreditCardInfo) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CreditCardInfo.Unmarshal(m, b) } func (m *CreditCardInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CreditCardInfo.Marshal(b, m, deterministic) } -func (dst *CreditCardInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_CreditCardInfo.Merge(dst, src) +func (m *CreditCardInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreditCardInfo.Merge(m, src) } func (m *CreditCardInfo) XXX_Size() int { return xxx_messageInfo_CreditCardInfo.Size(m) @@ -1024,8 +1058,8 @@ func (m *CreditCardInfo) GetCreditCardExpirationMonth() int32 { } type ChargeRequest struct { - Amount *Money `protobuf:"bytes,1,opt,name=amount" json:"amount,omitempty"` - CreditCard *CreditCardInfo `protobuf:"bytes,2,opt,name=credit_card,json=creditCard" json:"credit_card,omitempty"` + Amount *Money `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` + CreditCard *CreditCardInfo `protobuf:"bytes,2,opt,name=credit_card,json=creditCard,proto3" json:"credit_card,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1035,16 +1069,17 @@ func (m *ChargeRequest) Reset() { *m = ChargeRequest{} } func (m *ChargeRequest) String() string { return proto.CompactTextString(m) } func (*ChargeRequest) ProtoMessage() {} func (*ChargeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{22} + return fileDescriptor_ca53982754088a9d, []int{22} } + func (m *ChargeRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChargeRequest.Unmarshal(m, b) } func (m *ChargeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ChargeRequest.Marshal(b, m, deterministic) } -func (dst *ChargeRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ChargeRequest.Merge(dst, src) +func (m *ChargeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChargeRequest.Merge(m, src) } func (m *ChargeRequest) XXX_Size() int { return xxx_messageInfo_ChargeRequest.Size(m) @@ -1070,7 +1105,7 @@ func (m *ChargeRequest) GetCreditCard() *CreditCardInfo { } type ChargeResponse struct { - TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId" json:"transaction_id,omitempty"` + TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1080,16 +1115,17 @@ func (m *ChargeResponse) Reset() { *m = ChargeResponse{} } func (m *ChargeResponse) String() string { return proto.CompactTextString(m) } func (*ChargeResponse) ProtoMessage() {} func (*ChargeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{23} + return fileDescriptor_ca53982754088a9d, []int{23} } + func (m *ChargeResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChargeResponse.Unmarshal(m, b) } func (m *ChargeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ChargeResponse.Marshal(b, m, deterministic) } -func (dst *ChargeResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ChargeResponse.Merge(dst, src) +func (m *ChargeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChargeResponse.Merge(m, src) } func (m *ChargeResponse) XXX_Size() int { return xxx_messageInfo_ChargeResponse.Size(m) @@ -1108,8 +1144,8 @@ func (m *ChargeResponse) GetTransactionId() string { } type OrderItem struct { - Item *CartItem `protobuf:"bytes,1,opt,name=item" json:"item,omitempty"` - Cost *Money `protobuf:"bytes,2,opt,name=cost" json:"cost,omitempty"` + Item *CartItem `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` + Cost *Money `protobuf:"bytes,2,opt,name=cost,proto3" json:"cost,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1119,16 +1155,17 @@ func (m *OrderItem) Reset() { *m = OrderItem{} } func (m *OrderItem) String() string { return proto.CompactTextString(m) } func (*OrderItem) ProtoMessage() {} func (*OrderItem) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{24} + return fileDescriptor_ca53982754088a9d, []int{24} } + func (m *OrderItem) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OrderItem.Unmarshal(m, b) } func (m *OrderItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_OrderItem.Marshal(b, m, deterministic) } -func (dst *OrderItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrderItem.Merge(dst, src) +func (m *OrderItem) XXX_Merge(src proto.Message) { + xxx_messageInfo_OrderItem.Merge(m, src) } func (m *OrderItem) XXX_Size() int { return xxx_messageInfo_OrderItem.Size(m) @@ -1154,11 +1191,11 @@ func (m *OrderItem) GetCost() *Money { } type OrderResult struct { - OrderId string `protobuf:"bytes,1,opt,name=order_id,json=orderId" json:"order_id,omitempty"` - ShippingTrackingId string `protobuf:"bytes,2,opt,name=shipping_tracking_id,json=shippingTrackingId" json:"shipping_tracking_id,omitempty"` - ShippingCost *Money `protobuf:"bytes,3,opt,name=shipping_cost,json=shippingCost" json:"shipping_cost,omitempty"` - ShippingAddress *Address `protobuf:"bytes,4,opt,name=shipping_address,json=shippingAddress" json:"shipping_address,omitempty"` - Items []*OrderItem `protobuf:"bytes,5,rep,name=items" json:"items,omitempty"` + OrderId string `protobuf:"bytes,1,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"` + ShippingTrackingId string `protobuf:"bytes,2,opt,name=shipping_tracking_id,json=shippingTrackingId,proto3" json:"shipping_tracking_id,omitempty"` + ShippingCost *Money `protobuf:"bytes,3,opt,name=shipping_cost,json=shippingCost,proto3" json:"shipping_cost,omitempty"` + ShippingAddress *Address `protobuf:"bytes,4,opt,name=shipping_address,json=shippingAddress,proto3" json:"shipping_address,omitempty"` + Items []*OrderItem `protobuf:"bytes,5,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1168,16 +1205,17 @@ func (m *OrderResult) Reset() { *m = OrderResult{} } func (m *OrderResult) String() string { return proto.CompactTextString(m) } func (*OrderResult) ProtoMessage() {} func (*OrderResult) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{25} + return fileDescriptor_ca53982754088a9d, []int{25} } + func (m *OrderResult) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OrderResult.Unmarshal(m, b) } func (m *OrderResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_OrderResult.Marshal(b, m, deterministic) } -func (dst *OrderResult) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrderResult.Merge(dst, src) +func (m *OrderResult) XXX_Merge(src proto.Message) { + xxx_messageInfo_OrderResult.Merge(m, src) } func (m *OrderResult) XXX_Size() int { return xxx_messageInfo_OrderResult.Size(m) @@ -1224,8 +1262,8 @@ func (m *OrderResult) GetItems() []*OrderItem { } type SendOrderConfirmationRequest struct { - Email string `protobuf:"bytes,1,opt,name=email" json:"email,omitempty"` - Order *OrderResult `protobuf:"bytes,2,opt,name=order" json:"order,omitempty"` + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` + Order *OrderResult `protobuf:"bytes,2,opt,name=order,proto3" json:"order,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1235,16 +1273,17 @@ func (m *SendOrderConfirmationRequest) Reset() { *m = SendOrderConfirmat func (m *SendOrderConfirmationRequest) String() string { return proto.CompactTextString(m) } func (*SendOrderConfirmationRequest) ProtoMessage() {} func (*SendOrderConfirmationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{26} + return fileDescriptor_ca53982754088a9d, []int{26} } + func (m *SendOrderConfirmationRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SendOrderConfirmationRequest.Unmarshal(m, b) } func (m *SendOrderConfirmationRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SendOrderConfirmationRequest.Marshal(b, m, deterministic) } -func (dst *SendOrderConfirmationRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_SendOrderConfirmationRequest.Merge(dst, src) +func (m *SendOrderConfirmationRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SendOrderConfirmationRequest.Merge(m, src) } func (m *SendOrderConfirmationRequest) XXX_Size() int { return xxx_messageInfo_SendOrderConfirmationRequest.Size(m) @@ -1270,11 +1309,11 @@ func (m *SendOrderConfirmationRequest) GetOrder() *OrderResult { } type PlaceOrderRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - UserCurrency string `protobuf:"bytes,2,opt,name=user_currency,json=userCurrency" json:"user_currency,omitempty"` - Address *Address `protobuf:"bytes,3,opt,name=address" json:"address,omitempty"` - Email string `protobuf:"bytes,5,opt,name=email" json:"email,omitempty"` - CreditCard *CreditCardInfo `protobuf:"bytes,6,opt,name=credit_card,json=creditCard" json:"credit_card,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + UserCurrency string `protobuf:"bytes,2,opt,name=user_currency,json=userCurrency,proto3" json:"user_currency,omitempty"` + Address *Address `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` + Email string `protobuf:"bytes,5,opt,name=email,proto3" json:"email,omitempty"` + CreditCard *CreditCardInfo `protobuf:"bytes,6,opt,name=credit_card,json=creditCard,proto3" json:"credit_card,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1284,16 +1323,17 @@ func (m *PlaceOrderRequest) Reset() { *m = PlaceOrderRequest{} } func (m *PlaceOrderRequest) String() string { return proto.CompactTextString(m) } func (*PlaceOrderRequest) ProtoMessage() {} func (*PlaceOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{27} + return fileDescriptor_ca53982754088a9d, []int{27} } + func (m *PlaceOrderRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PlaceOrderRequest.Unmarshal(m, b) } func (m *PlaceOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_PlaceOrderRequest.Marshal(b, m, deterministic) } -func (dst *PlaceOrderRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_PlaceOrderRequest.Merge(dst, src) +func (m *PlaceOrderRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlaceOrderRequest.Merge(m, src) } func (m *PlaceOrderRequest) XXX_Size() int { return xxx_messageInfo_PlaceOrderRequest.Size(m) @@ -1340,7 +1380,7 @@ func (m *PlaceOrderRequest) GetCreditCard() *CreditCardInfo { } type PlaceOrderResponse struct { - Order *OrderResult `protobuf:"bytes,1,opt,name=order" json:"order,omitempty"` + Order *OrderResult `protobuf:"bytes,1,opt,name=order,proto3" json:"order,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1350,16 +1390,17 @@ func (m *PlaceOrderResponse) Reset() { *m = PlaceOrderResponse{} } func (m *PlaceOrderResponse) String() string { return proto.CompactTextString(m) } func (*PlaceOrderResponse) ProtoMessage() {} func (*PlaceOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{28} + return fileDescriptor_ca53982754088a9d, []int{28} } + func (m *PlaceOrderResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PlaceOrderResponse.Unmarshal(m, b) } func (m *PlaceOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_PlaceOrderResponse.Marshal(b, m, deterministic) } -func (dst *PlaceOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_PlaceOrderResponse.Merge(dst, src) +func (m *PlaceOrderResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlaceOrderResponse.Merge(m, src) } func (m *PlaceOrderResponse) XXX_Size() int { return xxx_messageInfo_PlaceOrderResponse.Size(m) @@ -1377,6 +1418,134 @@ func (m *PlaceOrderResponse) GetOrder() *OrderResult { return nil } +type AdRequest struct { + // List of important key words from the current page describing the context. + ContextKeys []string `protobuf:"bytes,1,rep,name=context_keys,json=contextKeys,proto3" json:"context_keys,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AdRequest) Reset() { *m = AdRequest{} } +func (m *AdRequest) String() string { return proto.CompactTextString(m) } +func (*AdRequest) ProtoMessage() {} +func (*AdRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_ca53982754088a9d, []int{29} +} + +func (m *AdRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AdRequest.Unmarshal(m, b) +} +func (m *AdRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AdRequest.Marshal(b, m, deterministic) +} +func (m *AdRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdRequest.Merge(m, src) +} +func (m *AdRequest) XXX_Size() int { + return xxx_messageInfo_AdRequest.Size(m) +} +func (m *AdRequest) XXX_DiscardUnknown() { + xxx_messageInfo_AdRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_AdRequest proto.InternalMessageInfo + +func (m *AdRequest) GetContextKeys() []string { + if m != nil { + return m.ContextKeys + } + return nil +} + +type AdResponse struct { + Ads []*Ad `protobuf:"bytes,1,rep,name=ads,proto3" json:"ads,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AdResponse) Reset() { *m = AdResponse{} } +func (m *AdResponse) String() string { return proto.CompactTextString(m) } +func (*AdResponse) ProtoMessage() {} +func (*AdResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_ca53982754088a9d, []int{30} +} + +func (m *AdResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AdResponse.Unmarshal(m, b) +} +func (m *AdResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AdResponse.Marshal(b, m, deterministic) +} +func (m *AdResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdResponse.Merge(m, src) +} +func (m *AdResponse) XXX_Size() int { + return xxx_messageInfo_AdResponse.Size(m) +} +func (m *AdResponse) XXX_DiscardUnknown() { + xxx_messageInfo_AdResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_AdResponse proto.InternalMessageInfo + +func (m *AdResponse) GetAds() []*Ad { + if m != nil { + return m.Ads + } + return nil +} + +type Ad struct { + // url to redirect to when an ad is clicked. + RedirectUrl string `protobuf:"bytes,1,opt,name=redirect_url,json=redirectUrl,proto3" json:"redirect_url,omitempty"` + // short advertisement text to display. + Text string `protobuf:"bytes,2,opt,name=text,proto3" json:"text,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Ad) Reset() { *m = Ad{} } +func (m *Ad) String() string { return proto.CompactTextString(m) } +func (*Ad) ProtoMessage() {} +func (*Ad) Descriptor() ([]byte, []int) { + return fileDescriptor_ca53982754088a9d, []int{31} +} + +func (m *Ad) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Ad.Unmarshal(m, b) +} +func (m *Ad) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Ad.Marshal(b, m, deterministic) +} +func (m *Ad) XXX_Merge(src proto.Message) { + xxx_messageInfo_Ad.Merge(m, src) +} +func (m *Ad) XXX_Size() int { + return xxx_messageInfo_Ad.Size(m) +} +func (m *Ad) XXX_DiscardUnknown() { + xxx_messageInfo_Ad.DiscardUnknown(m) +} + +var xxx_messageInfo_Ad proto.InternalMessageInfo + +func (m *Ad) GetRedirectUrl() string { + if m != nil { + return m.RedirectUrl + } + return "" +} + +func (m *Ad) GetText() string { + if m != nil { + return m.Text + } + return "" +} + func init() { proto.RegisterType((*CartItem)(nil), "hipstershop.CartItem") proto.RegisterType((*AddItemRequest)(nil), "hipstershop.AddItemRequest") @@ -1407,6 +1576,9 @@ func init() { proto.RegisterType((*SendOrderConfirmationRequest)(nil), "hipstershop.SendOrderConfirmationRequest") proto.RegisterType((*PlaceOrderRequest)(nil), "hipstershop.PlaceOrderRequest") proto.RegisterType((*PlaceOrderResponse)(nil), "hipstershop.PlaceOrderResponse") + proto.RegisterType((*AdRequest)(nil), "hipstershop.AdRequest") + proto.RegisterType((*AdResponse)(nil), "hipstershop.AdResponse") + proto.RegisterType((*Ad)(nil), "hipstershop.Ad") } // Reference imports to suppress errors if they are not otherwise used. @@ -2127,95 +2299,166 @@ var _CheckoutService_serviceDesc = grpc.ServiceDesc{ Metadata: "demo.proto", } -func init() { proto.RegisterFile("demo.proto", fileDescriptor_demo_e1d03823e14b5fb0) } - -var fileDescriptor_demo_e1d03823e14b5fb0 = []byte{ - // 1389 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xdd, 0x72, 0xd3, 0xc6, - 0x17, 0x8f, 0x12, 0x3b, 0xb6, 0x8f, 0x63, 0x27, 0xd9, 0x7f, 0xc2, 0xdf, 0x28, 0x7c, 0xa4, 0x9b, - 0x81, 0x42, 0x81, 0x94, 0x49, 0x3b, 0xc3, 0x45, 0x69, 0x29, 0x63, 0x32, 0xc6, 0x33, 0x50, 0xa8, - 0x02, 0x1d, 0x3a, 0x74, 0xea, 0x11, 0xda, 0x05, 0xab, 0x44, 0x5a, 0xb1, 0xbb, 0xca, 0xd4, 0x5c, - 0xb6, 0x0f, 0xd0, 0xfb, 0x3e, 0x42, 0x5f, 0xa0, 0xef, 0xd0, 0xfb, 0xbe, 0x42, 0x9f, 0xa3, 0xb3, - 0x2b, 0xad, 0xbe, 0x62, 0x25, 0xe1, 0xa6, 0x77, 0xda, 0xb3, 0xbf, 0x3d, 0xe7, 0x77, 0xce, 0x9e, - 0x73, 0xf6, 0x08, 0x80, 0xd0, 0x80, 0xed, 0x46, 0x9c, 0x49, 0x86, 0xba, 0x53, 0x3f, 0x12, 0x92, - 0x72, 0x31, 0x65, 0x11, 0xde, 0x87, 0xf6, 0xd0, 0xe5, 0x72, 0x2c, 0x69, 0x80, 0x2e, 0x02, 0x44, - 0x9c, 0x91, 0xd8, 0x93, 0x13, 0x9f, 0x0c, 0xac, 0x6d, 0xeb, 0x5a, 0xc7, 0xe9, 0xa4, 0x92, 0x31, - 0x41, 0x36, 0xb4, 0xdf, 0xc5, 0x6e, 0x28, 0x7d, 0x39, 0x1b, 0x2c, 0x6e, 0x5b, 0xd7, 0x9a, 0x4e, - 0xb6, 0xc6, 0xcf, 0xa0, 0x7f, 0x9f, 0x10, 0xa5, 0xc5, 0xa1, 0xef, 0x62, 0x2a, 0x24, 0xfa, 0x3f, - 0xb4, 0x62, 0x41, 0x79, 0xae, 0x69, 0x59, 0x2d, 0xc7, 0x04, 0x5d, 0x87, 0x86, 0x2f, 0x69, 0xa0, - 0x55, 0x74, 0xf7, 0x36, 0x77, 0x0b, 0x6c, 0x76, 0x0d, 0x15, 0x47, 0x43, 0xf0, 0x0d, 0x58, 0xdb, - 0x0f, 0x22, 0x39, 0x53, 0xe2, 0xd3, 0xf4, 0xe2, 0xeb, 0xd0, 0x1f, 0x51, 0x79, 0x26, 0xe8, 0x23, - 0x68, 0x28, 0x5c, 0x3d, 0xc7, 0x1b, 0xd0, 0x54, 0x04, 0xc4, 0x60, 0x71, 0x7b, 0xa9, 0x9e, 0x64, - 0x82, 0xc1, 0x2d, 0x68, 0x6a, 0x96, 0xf8, 0x3b, 0xb0, 0x1f, 0xf9, 0x42, 0x3a, 0xd4, 0x63, 0x41, - 0x40, 0x43, 0xe2, 0x4a, 0x9f, 0x85, 0xe2, 0xd4, 0x80, 0x5c, 0x86, 0x6e, 0x1e, 0xf6, 0xc4, 0x64, - 0xc7, 0x81, 0x2c, 0xee, 0x02, 0x7f, 0x05, 0x5b, 0x73, 0xf5, 0x8a, 0x88, 0x85, 0x82, 0x56, 0xcf, - 0x5b, 0xc7, 0xce, 0xff, 0x6e, 0x41, 0xeb, 0x69, 0xb2, 0x44, 0x7d, 0x58, 0xcc, 0x08, 0x2c, 0xfa, - 0x04, 0x21, 0x68, 0x84, 0x6e, 0x40, 0xf5, 0x6d, 0x74, 0x1c, 0xfd, 0x8d, 0xb6, 0xa1, 0x4b, 0xa8, - 0xf0, 0xb8, 0x1f, 0x29, 0x43, 0x83, 0x25, 0xbd, 0x55, 0x14, 0xa1, 0x01, 0xb4, 0x22, 0xdf, 0x93, - 0x31, 0xa7, 0x83, 0x86, 0xde, 0x35, 0x4b, 0xf4, 0x29, 0x74, 0x22, 0xee, 0x7b, 0x74, 0x12, 0x0b, - 0x32, 0x68, 0xea, 0x2b, 0x46, 0xa5, 0xe8, 0x3d, 0x66, 0x21, 0x9d, 0x39, 0x6d, 0x0d, 0x7a, 0x2e, - 0x08, 0x7e, 0x08, 0x1b, 0xca, 0xb9, 0x94, 0x5f, 0xee, 0xd5, 0x6d, 0x68, 0xa7, 0x2e, 0x24, 0x2e, - 0x75, 0xf7, 0x36, 0x4a, 0x7a, 0xd2, 0x03, 0x4e, 0x86, 0xc2, 0x3b, 0xb0, 0x3e, 0xa2, 0x46, 0x91, - 0x89, 0x7a, 0xc5, 0x5f, 0x7c, 0x0b, 0x36, 0x0f, 0xa8, 0xcb, 0xbd, 0x69, 0x6e, 0x30, 0x01, 0x6e, - 0x40, 0xf3, 0x5d, 0x4c, 0xf9, 0x2c, 0xc5, 0x26, 0x0b, 0xfc, 0x10, 0xce, 0x55, 0xe1, 0x29, 0xbf, - 0x5d, 0x68, 0x71, 0x2a, 0xe2, 0xc3, 0x53, 0xe8, 0x19, 0x10, 0x0e, 0x61, 0x75, 0x44, 0xe5, 0xb7, - 0x31, 0x93, 0xd4, 0x98, 0xdc, 0x85, 0x96, 0x4b, 0x08, 0xa7, 0x42, 0x68, 0xa3, 0x55, 0x15, 0xf7, - 0x93, 0x3d, 0xc7, 0x80, 0x3e, 0x2c, 0x2b, 0xef, 0xc3, 0x5a, 0x6e, 0x2f, 0xe5, 0x7c, 0x0b, 0xda, - 0x1e, 0x13, 0x52, 0xdf, 0x8d, 0x55, 0x7b, 0x37, 0x2d, 0x85, 0x51, 0x57, 0xc3, 0x60, 0xed, 0x60, - 0xea, 0x47, 0x4f, 0x38, 0xa1, 0xfc, 0x3f, 0xe1, 0xfc, 0x39, 0xac, 0x17, 0x0c, 0xe6, 0xe9, 0x2d, - 0xb9, 0xeb, 0xbd, 0xf5, 0xc3, 0x37, 0x79, 0xed, 0x80, 0x11, 0x8d, 0x09, 0xfe, 0xcd, 0x82, 0x56, - 0x6a, 0x17, 0x5d, 0x81, 0xbe, 0x90, 0x9c, 0x52, 0x39, 0x29, 0xb2, 0xec, 0x38, 0xbd, 0x44, 0x6a, - 0x60, 0x08, 0x1a, 0x9e, 0x69, 0x63, 0x1d, 0x47, 0x7f, 0xab, 0x04, 0x10, 0xd2, 0x95, 0x34, 0xcd, - 0xf7, 0x64, 0xa1, 0x32, 0xdd, 0x63, 0x71, 0x28, 0xf9, 0xcc, 0x64, 0x7a, 0xba, 0x44, 0xe7, 0xa1, - 0xfd, 0xde, 0x8f, 0x26, 0x1e, 0x23, 0x54, 0x27, 0x7a, 0xd3, 0x69, 0xbd, 0xf7, 0xa3, 0x21, 0x23, - 0x14, 0xbf, 0x80, 0xa6, 0x0e, 0x25, 0xda, 0x81, 0x9e, 0x17, 0x73, 0x4e, 0x43, 0x6f, 0x96, 0x00, - 0x13, 0x36, 0x2b, 0x46, 0xa8, 0xd0, 0xca, 0x70, 0x1c, 0xfa, 0x52, 0x68, 0x36, 0x4b, 0x4e, 0xb2, - 0x50, 0xd2, 0xd0, 0x0d, 0x99, 0xd0, 0x74, 0x9a, 0x4e, 0xb2, 0xc0, 0x23, 0xb8, 0x34, 0xa2, 0xf2, - 0x20, 0x8e, 0x22, 0xc6, 0x25, 0x25, 0xc3, 0x44, 0x8f, 0x4f, 0xf3, 0xbc, 0xbc, 0x02, 0xfd, 0x92, - 0x49, 0xd3, 0x10, 0x7a, 0x45, 0x9b, 0x02, 0xff, 0x00, 0xe7, 0x87, 0x99, 0x20, 0x3c, 0xa2, 0x5c, - 0xf8, 0x2c, 0x34, 0x97, 0x7c, 0x15, 0x1a, 0xaf, 0x39, 0x0b, 0x4e, 0xc8, 0x11, 0xbd, 0xaf, 0x5a, - 0x9a, 0x64, 0x89, 0x63, 0x49, 0x24, 0x97, 0x25, 0xd3, 0x01, 0xf8, 0xc7, 0x82, 0xfe, 0x90, 0x53, - 0xe2, 0xab, 0x7e, 0x4c, 0xc6, 0xe1, 0x6b, 0x86, 0x6e, 0x02, 0xf2, 0xb4, 0x64, 0xe2, 0xb9, 0x9c, - 0x4c, 0xc2, 0x38, 0x78, 0x45, 0x79, 0x1a, 0x8f, 0x35, 0x2f, 0xc3, 0x7e, 0xa3, 0xe5, 0xe8, 0x2a, - 0xac, 0x16, 0xd1, 0xde, 0xd1, 0x51, 0xfa, 0xe4, 0xf4, 0x72, 0xe8, 0xf0, 0xe8, 0x08, 0x7d, 0x09, - 0x5b, 0x45, 0x1c, 0xfd, 0x39, 0xf2, 0xb9, 0x6e, 0x8f, 0x93, 0x19, 0x75, 0x79, 0x1a, 0xbb, 0x41, - 0x7e, 0x66, 0x3f, 0x03, 0x7c, 0x4f, 0x5d, 0x8e, 0xee, 0xc1, 0x85, 0x9a, 0xe3, 0x01, 0x0b, 0xe5, - 0x54, 0x5f, 0x79, 0xd3, 0x39, 0x3f, 0xef, 0xfc, 0x63, 0x05, 0xc0, 0x33, 0xe8, 0x0d, 0xa7, 0x2e, - 0x7f, 0x93, 0xd5, 0xf4, 0x27, 0xb0, 0xec, 0x06, 0x2a, 0x43, 0x4e, 0x08, 0x5e, 0x8a, 0x40, 0x77, - 0xa1, 0x5b, 0xb0, 0x9e, 0x3e, 0x88, 0x5b, 0xe5, 0x0a, 0x29, 0x05, 0xd1, 0x81, 0x9c, 0x09, 0xbe, - 0x03, 0x7d, 0x63, 0x3a, 0xbf, 0x7a, 0xc9, 0xdd, 0x50, 0xb8, 0x9e, 0x76, 0x21, 0x2b, 0x96, 0x5e, - 0x41, 0x3a, 0x26, 0xf8, 0x47, 0xe8, 0xe8, 0x0a, 0xd3, 0x6f, 0xbe, 0x79, 0x8d, 0xad, 0x53, 0x5f, - 0x63, 0x95, 0x15, 0xaa, 0x33, 0xa4, 0x3c, 0xe7, 0x66, 0x85, 0xda, 0xc7, 0xbf, 0x2c, 0x42, 0xd7, - 0x94, 0x70, 0x7c, 0x28, 0x55, 0xa1, 0x30, 0xb5, 0xcc, 0x09, 0xb5, 0xf4, 0x7a, 0x4c, 0xd0, 0x6d, - 0xd8, 0x10, 0x53, 0x3f, 0x8a, 0x54, 0x6d, 0x17, 0x8b, 0x3c, 0xc9, 0x26, 0x64, 0xf6, 0x9e, 0x65, - 0xc5, 0x8e, 0xee, 0x40, 0x2f, 0x3b, 0xa1, 0xd9, 0x2c, 0xd5, 0xb2, 0x59, 0x31, 0xc0, 0x21, 0x13, - 0x12, 0xdd, 0x83, 0xb5, 0xec, 0xa0, 0xe9, 0x0d, 0x8d, 0x13, 0x3a, 0xd8, 0xaa, 0x41, 0x9b, 0x9e, - 0x71, 0xd3, 0x74, 0xb2, 0xa6, 0xee, 0x64, 0xe7, 0x4a, 0xa7, 0xb2, 0x80, 0x9a, 0x56, 0x46, 0xe0, - 0xc2, 0x01, 0x0d, 0x89, 0x96, 0x0f, 0x59, 0xf8, 0xda, 0xe7, 0x81, 0x4e, 0x9b, 0xc2, 0x73, 0x43, - 0x03, 0xd7, 0x3f, 0x34, 0xcf, 0x8d, 0x5e, 0xa0, 0x5d, 0x68, 0xea, 0xd0, 0xa4, 0x31, 0x1e, 0x1c, - 0xb7, 0x91, 0xc4, 0xd4, 0x49, 0x60, 0xf8, 0x6f, 0x0b, 0xd6, 0x9f, 0x1e, 0xba, 0x1e, 0x2d, 0xf5, - 0xe8, 0xda, 0x49, 0x63, 0x07, 0x7a, 0x7a, 0xc3, 0xb4, 0x82, 0x34, 0xce, 0x2b, 0x4a, 0x68, 0xba, - 0x41, 0xb1, 0xc3, 0x2f, 0x9d, 0xa5, 0xc3, 0x67, 0x9e, 0x34, 0x8b, 0x9e, 0x54, 0x72, 0x7b, 0xf9, - 0xc3, 0x72, 0xfb, 0x01, 0xa0, 0xa2, 0x5b, 0xd9, 0x93, 0x9b, 0x46, 0xc7, 0x3a, 0x53, 0x74, 0xf6, - 0xfe, 0xb2, 0xa0, 0xab, 0x72, 0xf8, 0x80, 0xf2, 0x23, 0xdf, 0xa3, 0xe8, 0xae, 0x7e, 0x27, 0x74, - 0xda, 0x6f, 0x55, 0x7d, 0x2a, 0x8c, 0xae, 0x76, 0x39, 0x99, 0x92, 0xd9, 0x6e, 0x01, 0x7d, 0x01, - 0xad, 0x74, 0xbe, 0xac, 0x9c, 0x2e, 0x4f, 0x9d, 0xf6, 0xfa, 0xb1, 0x1a, 0xc2, 0x0b, 0xe8, 0x6b, - 0xe8, 0x64, 0x93, 0x2c, 0xba, 0x78, 0x5c, 0x7f, 0x51, 0xc1, 0x5c, 0xf3, 0x7b, 0xbf, 0x5a, 0xb0, - 0x59, 0x9e, 0x00, 0x8d, 0x5b, 0x3f, 0xc1, 0xff, 0xe6, 0x8c, 0x87, 0xe8, 0xe3, 0x92, 0x9a, 0xfa, - 0xc1, 0xd4, 0xbe, 0x76, 0x3a, 0x30, 0xb9, 0x00, 0xc5, 0x62, 0x11, 0x36, 0xd3, 0xd1, 0x66, 0xe8, - 0x4a, 0xf7, 0x90, 0xbd, 0x31, 0x2c, 0x46, 0xb0, 0x52, 0x9c, 0xe3, 0xd0, 0x1c, 0x2f, 0xec, 0x8f, - 0x8e, 0x59, 0xaa, 0x8e, 0x55, 0x78, 0x01, 0x3d, 0x00, 0xc8, 0xc7, 0x38, 0x74, 0xa9, 0x1a, 0xea, - 0xf2, 0x7c, 0x67, 0xcf, 0x9d, 0xba, 0xf0, 0x02, 0x7a, 0x09, 0xfd, 0xf2, 0xe0, 0x86, 0x70, 0x09, - 0x39, 0x77, 0x08, 0xb4, 0x77, 0x4e, 0xc4, 0x64, 0x51, 0xf8, 0xc3, 0x82, 0xd5, 0x83, 0xb4, 0x3d, - 0x18, 0xff, 0xc7, 0xd0, 0x36, 0xf3, 0x16, 0xba, 0x50, 0x25, 0x5d, 0x1c, 0xfb, 0xec, 0x8b, 0x35, - 0xbb, 0x59, 0x04, 0x1e, 0x41, 0x27, 0x1b, 0x83, 0x2a, 0xc9, 0x52, 0x9d, 0xc7, 0xec, 0x4b, 0x75, - 0xdb, 0x19, 0xd9, 0x3f, 0x2d, 0x58, 0x35, 0xc5, 0x6d, 0xc8, 0xbe, 0x84, 0x73, 0xf3, 0xc7, 0x88, - 0xb9, 0xd7, 0x76, 0xa3, 0x4a, 0xf8, 0x84, 0xf9, 0x03, 0x2f, 0xa0, 0x11, 0xb4, 0x92, 0x91, 0x42, - 0xa2, 0xab, 0xe5, 0x5a, 0xa8, 0x1b, 0x38, 0xec, 0x39, 0xed, 0x1b, 0x2f, 0xec, 0x3d, 0x87, 0xfe, - 0x53, 0x77, 0x16, 0xd0, 0x30, 0xab, 0xe0, 0x21, 0x2c, 0x27, 0x6f, 0x1e, 0xb2, 0xcb, 0x9a, 0x8b, - 0x6f, 0xb0, 0xbd, 0x35, 0x77, 0x2f, 0x0b, 0xc8, 0x14, 0x56, 0xf6, 0x55, 0x8f, 0x32, 0x4a, 0x5f, - 0xa8, 0x5f, 0x82, 0x39, 0xad, 0x1a, 0x5d, 0xaf, 0x64, 0x43, 0x7d, 0x3b, 0xaf, 0xa9, 0xd9, 0x57, - 0xb0, 0x3a, 0x9c, 0x52, 0xef, 0x2d, 0x8b, 0x33, 0x0f, 0x9e, 0x00, 0xe4, 0x9d, 0xad, 0x92, 0xdd, - 0xc7, 0x3a, 0xb9, 0x7d, 0xb9, 0x76, 0xdf, 0x78, 0xf3, 0x6a, 0x59, 0xff, 0xd4, 0x7f, 0xf6, 0x6f, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x59, 0xab, 0x01, 0x43, 0xe2, 0x0f, 0x00, 0x00, +// AdServiceClient is the client API for AdService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type AdServiceClient interface { + GetAds(ctx context.Context, in *AdRequest, opts ...grpc.CallOption) (*AdResponse, error) +} + +type adServiceClient struct { + cc *grpc.ClientConn +} + +func NewAdServiceClient(cc *grpc.ClientConn) AdServiceClient { + return &adServiceClient{cc} +} + +func (c *adServiceClient) GetAds(ctx context.Context, in *AdRequest, opts ...grpc.CallOption) (*AdResponse, error) { + out := new(AdResponse) + err := c.cc.Invoke(ctx, "/hipstershop.AdService/GetAds", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AdServiceServer is the server API for AdService service. +type AdServiceServer interface { + GetAds(context.Context, *AdRequest) (*AdResponse, error) +} + +func RegisterAdServiceServer(s *grpc.Server, srv AdServiceServer) { + s.RegisterService(&_AdService_serviceDesc, srv) +} + +func _AdService_GetAds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdServiceServer).GetAds(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hipstershop.AdService/GetAds", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdServiceServer).GetAds(ctx, req.(*AdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _AdService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "hipstershop.AdService", + HandlerType: (*AdServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetAds", + Handler: _AdService_GetAds_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "demo.proto", +} + +func init() { proto.RegisterFile("demo.proto", fileDescriptor_ca53982754088a9d) } + +var fileDescriptor_ca53982754088a9d = []byte{ + // 1500 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xef, 0x72, 0x13, 0xb7, + 0x16, 0xcf, 0x26, 0xb1, 0x1d, 0x1f, 0xc7, 0x4e, 0xa2, 0x9b, 0x04, 0xb3, 0x81, 0x10, 0x94, 0x81, + 0x0b, 0x17, 0x08, 0x4c, 0xee, 0x9d, 0xe1, 0x03, 0xdc, 0xd2, 0x8c, 0xc9, 0x18, 0x4f, 0xa1, 0xd0, + 0x0d, 0xe9, 0xd0, 0xa1, 0x53, 0xcf, 0xb2, 0x12, 0xf1, 0x96, 0xec, 0x6a, 0x91, 0xb4, 0x19, 0xcc, + 0xc7, 0xf6, 0x01, 0xfa, 0x1e, 0x7d, 0x81, 0xce, 0xf4, 0x11, 0xfa, 0xbd, 0xaf, 0xd0, 0xe7, 0xe8, + 0x48, 0xbb, 0xda, 0x7f, 0xb1, 0x13, 0xf8, 0xd2, 0x6f, 0xab, 0xa3, 0x9f, 0xce, 0xf9, 0xe9, 0xe8, + 0xfc, 0xb3, 0x01, 0x08, 0x0d, 0xd8, 0x4e, 0xc4, 0x99, 0x64, 0xa8, 0x35, 0xf2, 0x23, 0x21, 0x29, + 0x17, 0x23, 0x16, 0xe1, 0x7d, 0x58, 0xe8, 0xb9, 0x5c, 0x0e, 0x24, 0x0d, 0xd0, 0x65, 0x80, 0x88, + 0x33, 0x12, 0x7b, 0x72, 0xe8, 0x93, 0xae, 0xb5, 0x65, 0xdd, 0x68, 0x3a, 0xcd, 0x54, 0x32, 0x20, + 0xc8, 0x86, 0x85, 0xf7, 0xb1, 0x1b, 0x4a, 0x5f, 0x8e, 0xbb, 0xb3, 0x5b, 0xd6, 0x8d, 0x9a, 0x93, + 0xad, 0xf1, 0x4b, 0xe8, 0xec, 0x11, 0xa2, 0xb4, 0x38, 0xf4, 0x7d, 0x4c, 0x85, 0x44, 0x17, 0xa0, + 0x11, 0x0b, 0xca, 0x73, 0x4d, 0x75, 0xb5, 0x1c, 0x10, 0x74, 0x13, 0xe6, 0x7d, 0x49, 0x03, 0xad, + 0xa2, 0xb5, 0xbb, 0xb6, 0x53, 0x60, 0xb3, 0x63, 0xa8, 0x38, 0x1a, 0x82, 0x6f, 0xc1, 0xf2, 0x7e, + 0x10, 0xc9, 0xb1, 0x12, 0x9f, 0xa7, 0x17, 0xdf, 0x84, 0x4e, 0x9f, 0xca, 0x4f, 0x82, 0x3e, 0x85, + 0x79, 0x85, 0x9b, 0xce, 0xf1, 0x16, 0xd4, 0x14, 0x01, 0xd1, 0x9d, 0xdd, 0x9a, 0x9b, 0x4e, 0x32, + 0xc1, 0xe0, 0x06, 0xd4, 0x34, 0x4b, 0xfc, 0x2d, 0xd8, 0x4f, 0x7d, 0x21, 0x1d, 0xea, 0xb1, 0x20, + 0xa0, 0x21, 0x71, 0xa5, 0xcf, 0x42, 0x71, 0xae, 0x43, 0xae, 0x40, 0x2b, 0x77, 0x7b, 0x62, 0xb2, + 0xe9, 0x40, 0xe6, 0x77, 0x81, 0xbf, 0x80, 0x8d, 0x89, 0x7a, 0x45, 0xc4, 0x42, 0x41, 0xab, 0xe7, + 0xad, 0x53, 0xe7, 0x7f, 0xb7, 0xa0, 0xf1, 0x22, 0x59, 0xa2, 0x0e, 0xcc, 0x66, 0x04, 0x66, 0x7d, + 0x82, 0x10, 0xcc, 0x87, 0x6e, 0x40, 0xf5, 0x6b, 0x34, 0x1d, 0xfd, 0x8d, 0xb6, 0xa0, 0x45, 0xa8, + 0xf0, 0xb8, 0x1f, 0x29, 0x43, 0xdd, 0x39, 0xbd, 0x55, 0x14, 0xa1, 0x2e, 0x34, 0x22, 0xdf, 0x93, + 0x31, 0xa7, 0xdd, 0x79, 0xbd, 0x6b, 0x96, 0xe8, 0x2e, 0x34, 0x23, 0xee, 0x7b, 0x74, 0x18, 0x0b, + 0xd2, 0xad, 0xe9, 0x27, 0x46, 0x25, 0xef, 0x3d, 0x63, 0x21, 0x1d, 0x3b, 0x0b, 0x1a, 0x74, 0x28, + 0x08, 0xda, 0x04, 0xf0, 0x5c, 0x49, 0x8f, 0x18, 0xf7, 0xa9, 0xe8, 0xd6, 0x13, 0xf2, 0xb9, 0x04, + 0x3f, 0x81, 0x55, 0x75, 0xf9, 0x94, 0x7f, 0x7e, 0xeb, 0x7b, 0xb0, 0x90, 0x5e, 0x31, 0xb9, 0x72, + 0x6b, 0x77, 0xb5, 0x64, 0x27, 0x3d, 0xe0, 0x64, 0x28, 0xbc, 0x0d, 0x2b, 0x7d, 0x6a, 0x14, 0x99, + 0x57, 0xa9, 0xf8, 0x03, 0xdf, 0x81, 0xb5, 0x03, 0xea, 0x72, 0x6f, 0x94, 0x1b, 0x4c, 0x80, 0xab, + 0x50, 0x7b, 0x1f, 0x53, 0x3e, 0x4e, 0xb1, 0xc9, 0x02, 0x3f, 0x81, 0xf5, 0x2a, 0x3c, 0xe5, 0xb7, + 0x03, 0x0d, 0x4e, 0x45, 0x7c, 0x7c, 0x0e, 0x3d, 0x03, 0xc2, 0x21, 0x2c, 0xf5, 0xa9, 0xfc, 0x26, + 0x66, 0x92, 0x1a, 0x93, 0x3b, 0xd0, 0x70, 0x09, 0xe1, 0x54, 0x08, 0x6d, 0xb4, 0xaa, 0x62, 0x2f, + 0xd9, 0x73, 0x0c, 0xe8, 0xf3, 0xa2, 0x76, 0x0f, 0x96, 0x73, 0x7b, 0x29, 0xe7, 0x3b, 0xb0, 0xe0, + 0x31, 0x21, 0xf5, 0xdb, 0x59, 0x53, 0xdf, 0xae, 0xa1, 0x30, 0x87, 0x82, 0x60, 0x06, 0xcb, 0x07, + 0x23, 0x3f, 0x7a, 0xce, 0x09, 0xe5, 0xff, 0x08, 0xe7, 0xff, 0xc1, 0x4a, 0xc1, 0x60, 0x1e, 0xfe, + 0x92, 0xbb, 0xde, 0x3b, 0x3f, 0x3c, 0xca, 0x73, 0x0b, 0x8c, 0x68, 0x40, 0xf0, 0x2f, 0x16, 0x34, + 0x52, 0xbb, 0xe8, 0x1a, 0x74, 0x84, 0xe4, 0x94, 0xca, 0x61, 0x91, 0x65, 0xd3, 0x69, 0x27, 0x52, + 0x03, 0x43, 0x30, 0xef, 0x99, 0x32, 0xd7, 0x74, 0xf4, 0xb7, 0x0a, 0x00, 0x21, 0x5d, 0x49, 0xd3, + 0x7c, 0x48, 0x16, 0x2a, 0x13, 0x3c, 0x16, 0x87, 0x92, 0x8f, 0x4d, 0x26, 0xa4, 0x4b, 0x74, 0x11, + 0x16, 0x3e, 0xfa, 0xd1, 0xd0, 0x63, 0x84, 0xea, 0x44, 0xa8, 0x39, 0x8d, 0x8f, 0x7e, 0xd4, 0x63, + 0x84, 0xe2, 0x57, 0x50, 0xd3, 0xae, 0x44, 0xdb, 0xd0, 0xf6, 0x62, 0xce, 0x69, 0xe8, 0x8d, 0x13, + 0x60, 0xc2, 0x66, 0xd1, 0x08, 0x15, 0x5a, 0x19, 0x8e, 0x43, 0x5f, 0x0a, 0xcd, 0x66, 0xce, 0x49, + 0x16, 0x4a, 0x1a, 0xba, 0x21, 0x13, 0x9a, 0x4e, 0xcd, 0x49, 0x16, 0xb8, 0x0f, 0x9b, 0x7d, 0x2a, + 0x0f, 0xe2, 0x28, 0x62, 0x5c, 0x52, 0xd2, 0x4b, 0xf4, 0xf8, 0x34, 0x8f, 0xcb, 0x6b, 0xd0, 0x29, + 0x99, 0x34, 0x05, 0xa3, 0x5d, 0xb4, 0x29, 0xf0, 0xf7, 0x70, 0xb1, 0x97, 0x09, 0xc2, 0x13, 0xca, + 0x85, 0xcf, 0x42, 0xf3, 0xc8, 0xd7, 0x61, 0xfe, 0x2d, 0x67, 0xc1, 0x19, 0x31, 0xa2, 0xf7, 0x55, + 0xc9, 0x93, 0x2c, 0xb9, 0x58, 0xe2, 0xc9, 0xba, 0x64, 0xda, 0x01, 0x7f, 0x59, 0xd0, 0xe9, 0x71, + 0x4a, 0x7c, 0x55, 0xaf, 0xc9, 0x20, 0x7c, 0xcb, 0xd0, 0x6d, 0x40, 0x9e, 0x96, 0x0c, 0x3d, 0x97, + 0x93, 0x61, 0x18, 0x07, 0x6f, 0x28, 0x4f, 0xfd, 0xb1, 0xec, 0x65, 0xd8, 0xaf, 0xb5, 0x1c, 0x5d, + 0x87, 0xa5, 0x22, 0xda, 0x3b, 0x39, 0x49, 0x5b, 0x52, 0x3b, 0x87, 0xf6, 0x4e, 0x4e, 0xd0, 0xff, + 0x61, 0xa3, 0x88, 0xa3, 0x1f, 0x22, 0x9f, 0xeb, 0xf2, 0x39, 0x1c, 0x53, 0x97, 0xa7, 0xbe, 0xeb, + 0xe6, 0x67, 0xf6, 0x33, 0xc0, 0x77, 0xd4, 0xe5, 0xe8, 0x11, 0x5c, 0x9a, 0x72, 0x3c, 0x60, 0xa1, + 0x1c, 0xe9, 0x27, 0xaf, 0x39, 0x17, 0x27, 0x9d, 0x7f, 0xa6, 0x00, 0x78, 0x0c, 0xed, 0xde, 0xc8, + 0xe5, 0x47, 0x59, 0x4e, 0xff, 0x07, 0xea, 0x6e, 0xa0, 0x22, 0xe4, 0x0c, 0xe7, 0xa5, 0x08, 0xf4, + 0x10, 0x5a, 0x05, 0xeb, 0x69, 0xc3, 0xdc, 0x28, 0x67, 0x48, 0xc9, 0x89, 0x0e, 0xe4, 0x4c, 0xf0, + 0x7d, 0xe8, 0x18, 0xd3, 0xf9, 0xd3, 0x4b, 0xee, 0x86, 0xc2, 0xf5, 0xf4, 0x15, 0xb2, 0x64, 0x69, + 0x17, 0xa4, 0x03, 0x82, 0x7f, 0x80, 0xa6, 0xce, 0x30, 0x3d, 0x13, 0x98, 0x6e, 0x6d, 0x9d, 0xdb, + 0xad, 0x55, 0x54, 0xa8, 0xca, 0x90, 0xf2, 0x9c, 0x18, 0x15, 0x6a, 0x1f, 0xff, 0x34, 0x0b, 0x2d, + 0x93, 0xc2, 0xf1, 0xb1, 0x54, 0x89, 0xc2, 0xd4, 0x32, 0x27, 0xd4, 0xd0, 0xeb, 0x01, 0x41, 0xf7, + 0x60, 0x55, 0x8c, 0xfc, 0x28, 0x52, 0xb9, 0x5d, 0x4c, 0xf2, 0x24, 0x9a, 0x90, 0xd9, 0x7b, 0x99, + 0x25, 0x3b, 0xba, 0x0f, 0xed, 0xec, 0x84, 0x66, 0x33, 0x37, 0x95, 0xcd, 0xa2, 0x01, 0xf6, 0x98, + 0x90, 0xe8, 0x11, 0x2c, 0x67, 0x07, 0x4d, 0x6d, 0x98, 0x3f, 0xa3, 0x82, 0x2d, 0x19, 0xb4, 0xa9, + 0x19, 0xb7, 0x4d, 0x25, 0xab, 0xe9, 0x4a, 0xb6, 0x5e, 0x3a, 0x95, 0x39, 0xd4, 0x94, 0x32, 0x02, + 0x97, 0x0e, 0x68, 0x48, 0xb4, 0xbc, 0xc7, 0xc2, 0xb7, 0x3e, 0x0f, 0x74, 0xd8, 0x14, 0xda, 0x0d, + 0x0d, 0x5c, 0xff, 0xd8, 0xb4, 0x1b, 0xbd, 0x40, 0x3b, 0x50, 0xd3, 0xae, 0x49, 0x7d, 0xdc, 0x3d, + 0x6d, 0x23, 0xf1, 0xa9, 0x93, 0xc0, 0xf0, 0x9f, 0x16, 0xac, 0xbc, 0x38, 0x76, 0x3d, 0x5a, 0xaa, + 0xd1, 0x53, 0x27, 0x91, 0x6d, 0x68, 0xeb, 0x0d, 0x53, 0x0a, 0x52, 0x3f, 0x2f, 0x2a, 0xa1, 0xa9, + 0x06, 0xc5, 0x0a, 0x3f, 0xf7, 0x29, 0x15, 0x3e, 0xbb, 0x49, 0xad, 0x78, 0x93, 0x4a, 0x6c, 0xd7, + 0x3f, 0x2f, 0xb6, 0x1f, 0x03, 0x2a, 0x5e, 0x2b, 0x6b, 0xb9, 0xa9, 0x77, 0xac, 0x4f, 0xf3, 0xce, + 0x0e, 0x34, 0xf7, 0x88, 0x71, 0xca, 0x55, 0x58, 0xf4, 0x58, 0x28, 0xe9, 0x07, 0x39, 0x7c, 0x47, + 0xc7, 0xa6, 0x2a, 0xb6, 0x52, 0xd9, 0x57, 0x74, 0x2c, 0xf0, 0x5d, 0x00, 0x85, 0x4f, 0xad, 0x5d, + 0x85, 0x39, 0x97, 0x98, 0xe6, 0xbe, 0x54, 0xf1, 0x81, 0xa3, 0xf6, 0xf0, 0x03, 0x98, 0xdd, 0x23, + 0x4a, 0xb3, 0x62, 0xce, 0xa9, 0x27, 0x87, 0x31, 0x37, 0x2f, 0xda, 0x32, 0xb2, 0x43, 0x7e, 0xac, + 0xfa, 0x8d, 0xb2, 0x62, 0xfa, 0x8d, 0xfa, 0xde, 0xfd, 0xc3, 0x82, 0x96, 0xca, 0xb0, 0x03, 0xca, + 0x4f, 0x7c, 0x8f, 0xa2, 0x87, 0xba, 0x8b, 0xe9, 0xa4, 0xdc, 0xa8, 0x7a, 0xbc, 0x30, 0x78, 0xdb, + 0xe5, 0x50, 0x4f, 0x26, 0xd3, 0x19, 0xf4, 0x00, 0x1a, 0xe9, 0x74, 0x5c, 0x39, 0x5d, 0x9e, 0x99, + 0xed, 0x95, 0x53, 0x19, 0x8e, 0x67, 0xd0, 0x97, 0xd0, 0xcc, 0xe6, 0x70, 0x74, 0xf9, 0xb4, 0xfe, + 0xa2, 0x82, 0x89, 0xe6, 0x77, 0x7f, 0xb6, 0x60, 0xad, 0x3c, 0xbf, 0x9a, 0x6b, 0xfd, 0x08, 0xff, + 0x9a, 0x30, 0xdc, 0xa2, 0x7f, 0x97, 0xd4, 0x4c, 0x1f, 0xab, 0xed, 0x1b, 0xe7, 0x03, 0x93, 0x07, + 0x53, 0x2c, 0x66, 0x61, 0x2d, 0x1d, 0xbc, 0x7a, 0xae, 0x74, 0x8f, 0xd9, 0x91, 0x61, 0xd1, 0x87, + 0xc5, 0xe2, 0x94, 0x89, 0x26, 0xdc, 0xc2, 0xbe, 0x7a, 0xca, 0x52, 0x75, 0xe8, 0xc3, 0x33, 0xe8, + 0x31, 0x40, 0x3e, 0x64, 0xa2, 0xcd, 0xaa, 0xab, 0xcb, 0xd3, 0xa7, 0x3d, 0x71, 0x26, 0xc4, 0x33, + 0xe8, 0x35, 0x74, 0xca, 0x63, 0x25, 0xc2, 0x25, 0xe4, 0xc4, 0x11, 0xd5, 0xde, 0x3e, 0x13, 0x93, + 0x79, 0xe1, 0x57, 0x0b, 0x96, 0x0e, 0xd2, 0xe2, 0x65, 0xee, 0x3f, 0x80, 0x05, 0x33, 0x0d, 0xa2, + 0x4b, 0x55, 0xd2, 0xc5, 0xa1, 0xd4, 0xbe, 0x3c, 0x65, 0x37, 0xf3, 0xc0, 0x53, 0x68, 0x66, 0x43, + 0x5a, 0x25, 0x58, 0xaa, 0xd3, 0xa2, 0xbd, 0x39, 0x6d, 0x3b, 0x23, 0xfb, 0x9b, 0x05, 0x4b, 0xa6, + 0xf4, 0x18, 0xb2, 0xaf, 0x61, 0x7d, 0xf2, 0x90, 0x33, 0xf1, 0xd9, 0x6e, 0x55, 0x09, 0x9f, 0x31, + 0x1d, 0xe1, 0x19, 0xd4, 0x87, 0x46, 0x32, 0xf0, 0x48, 0x74, 0xbd, 0x9c, 0x0b, 0xd3, 0xc6, 0x21, + 0x7b, 0x42, 0x73, 0xc1, 0x33, 0xbb, 0x87, 0xd0, 0x79, 0xe1, 0x8e, 0x03, 0x1a, 0x66, 0x19, 0xdc, + 0x83, 0x7a, 0xd2, 0x91, 0x91, 0x5d, 0xd6, 0x5c, 0x9c, 0x10, 0xec, 0x8d, 0x89, 0x7b, 0x99, 0x43, + 0x46, 0xb0, 0xb8, 0xaf, 0x2a, 0xa8, 0x51, 0xfa, 0x4a, 0xfd, 0x60, 0x99, 0xd0, 0x48, 0xd0, 0xcd, + 0x4a, 0x34, 0x4c, 0x6f, 0x36, 0x53, 0x72, 0xf6, 0x0d, 0x2c, 0xf5, 0x46, 0xd4, 0x7b, 0xc7, 0xe2, + 0xec, 0x06, 0xcf, 0x01, 0xf2, 0xba, 0x5b, 0x89, 0xee, 0x53, 0x7d, 0xc6, 0xbe, 0x32, 0x75, 0x3f, + 0xbb, 0xcd, 0x13, 0x55, 0x82, 0x8d, 0xf6, 0x07, 0x50, 0xef, 0xab, 0x19, 0x5c, 0xa0, 0xf5, 0x6a, + 0x39, 0x4d, 0x35, 0x5e, 0x38, 0x25, 0x37, 0x9a, 0xde, 0xd4, 0xf5, 0x9f, 0x1b, 0xff, 0xfd, 0x3b, + 0x00, 0x00, 0xff, 0xff, 0xb2, 0xa0, 0x6e, 0x6c, 0xea, 0x10, 0x00, 0x00, } diff --git a/src/checkoutservice/genproto/demo.pb.go b/src/checkoutservice/genproto/demo.pb.go index 4fdb7f0..f59af20 100644 --- a/src/checkoutservice/genproto/demo.pb.go +++ b/src/checkoutservice/genproto/demo.pb.go @@ -3,9 +3,11 @@ package hipstershop -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) import ( context "golang.org/x/net/context" @@ -24,8 +26,8 @@ var _ = math.Inf const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package type CartItem struct { - ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId" json:"product_id,omitempty"` - Quantity int32 `protobuf:"varint,2,opt,name=quantity" json:"quantity,omitempty"` + ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` + Quantity int32 `protobuf:"varint,2,opt,name=quantity,proto3" json:"quantity,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -35,16 +37,17 @@ func (m *CartItem) Reset() { *m = CartItem{} } func (m *CartItem) String() string { return proto.CompactTextString(m) } func (*CartItem) ProtoMessage() {} func (*CartItem) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{0} + return fileDescriptor_ca53982754088a9d, []int{0} } + func (m *CartItem) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CartItem.Unmarshal(m, b) } func (m *CartItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CartItem.Marshal(b, m, deterministic) } -func (dst *CartItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_CartItem.Merge(dst, src) +func (m *CartItem) XXX_Merge(src proto.Message) { + xxx_messageInfo_CartItem.Merge(m, src) } func (m *CartItem) XXX_Size() int { return xxx_messageInfo_CartItem.Size(m) @@ -70,8 +73,8 @@ func (m *CartItem) GetQuantity() int32 { } type AddItemRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - Item *CartItem `protobuf:"bytes,2,opt,name=item" json:"item,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Item *CartItem `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -81,16 +84,17 @@ func (m *AddItemRequest) Reset() { *m = AddItemRequest{} } func (m *AddItemRequest) String() string { return proto.CompactTextString(m) } func (*AddItemRequest) ProtoMessage() {} func (*AddItemRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{1} + return fileDescriptor_ca53982754088a9d, []int{1} } + func (m *AddItemRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AddItemRequest.Unmarshal(m, b) } func (m *AddItemRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_AddItemRequest.Marshal(b, m, deterministic) } -func (dst *AddItemRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_AddItemRequest.Merge(dst, src) +func (m *AddItemRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddItemRequest.Merge(m, src) } func (m *AddItemRequest) XXX_Size() int { return xxx_messageInfo_AddItemRequest.Size(m) @@ -116,7 +120,7 @@ func (m *AddItemRequest) GetItem() *CartItem { } type EmptyCartRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -126,16 +130,17 @@ func (m *EmptyCartRequest) Reset() { *m = EmptyCartRequest{} } func (m *EmptyCartRequest) String() string { return proto.CompactTextString(m) } func (*EmptyCartRequest) ProtoMessage() {} func (*EmptyCartRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{2} + return fileDescriptor_ca53982754088a9d, []int{2} } + func (m *EmptyCartRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EmptyCartRequest.Unmarshal(m, b) } func (m *EmptyCartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_EmptyCartRequest.Marshal(b, m, deterministic) } -func (dst *EmptyCartRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_EmptyCartRequest.Merge(dst, src) +func (m *EmptyCartRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_EmptyCartRequest.Merge(m, src) } func (m *EmptyCartRequest) XXX_Size() int { return xxx_messageInfo_EmptyCartRequest.Size(m) @@ -154,7 +159,7 @@ func (m *EmptyCartRequest) GetUserId() string { } type GetCartRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -164,16 +169,17 @@ func (m *GetCartRequest) Reset() { *m = GetCartRequest{} } func (m *GetCartRequest) String() string { return proto.CompactTextString(m) } func (*GetCartRequest) ProtoMessage() {} func (*GetCartRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{3} + return fileDescriptor_ca53982754088a9d, []int{3} } + func (m *GetCartRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetCartRequest.Unmarshal(m, b) } func (m *GetCartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetCartRequest.Marshal(b, m, deterministic) } -func (dst *GetCartRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetCartRequest.Merge(dst, src) +func (m *GetCartRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetCartRequest.Merge(m, src) } func (m *GetCartRequest) XXX_Size() int { return xxx_messageInfo_GetCartRequest.Size(m) @@ -192,8 +198,8 @@ func (m *GetCartRequest) GetUserId() string { } type Cart struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -203,16 +209,17 @@ func (m *Cart) Reset() { *m = Cart{} } func (m *Cart) String() string { return proto.CompactTextString(m) } func (*Cart) ProtoMessage() {} func (*Cart) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{4} + return fileDescriptor_ca53982754088a9d, []int{4} } + func (m *Cart) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Cart.Unmarshal(m, b) } func (m *Cart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Cart.Marshal(b, m, deterministic) } -func (dst *Cart) XXX_Merge(src proto.Message) { - xxx_messageInfo_Cart.Merge(dst, src) +func (m *Cart) XXX_Merge(src proto.Message) { + xxx_messageInfo_Cart.Merge(m, src) } func (m *Cart) XXX_Size() int { return xxx_messageInfo_Cart.Size(m) @@ -247,16 +254,17 @@ func (m *Empty) Reset() { *m = Empty{} } func (m *Empty) String() string { return proto.CompactTextString(m) } func (*Empty) ProtoMessage() {} func (*Empty) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{5} + return fileDescriptor_ca53982754088a9d, []int{5} } + func (m *Empty) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Empty.Unmarshal(m, b) } func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Empty.Marshal(b, m, deterministic) } -func (dst *Empty) XXX_Merge(src proto.Message) { - xxx_messageInfo_Empty.Merge(dst, src) +func (m *Empty) XXX_Merge(src proto.Message) { + xxx_messageInfo_Empty.Merge(m, src) } func (m *Empty) XXX_Size() int { return xxx_messageInfo_Empty.Size(m) @@ -268,8 +276,8 @@ func (m *Empty) XXX_DiscardUnknown() { var xxx_messageInfo_Empty proto.InternalMessageInfo type ListRecommendationsRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - ProductIds []string `protobuf:"bytes,2,rep,name=product_ids,json=productIds" json:"product_ids,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ProductIds []string `protobuf:"bytes,2,rep,name=product_ids,json=productIds,proto3" json:"product_ids,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -279,16 +287,17 @@ func (m *ListRecommendationsRequest) Reset() { *m = ListRecommendationsR func (m *ListRecommendationsRequest) String() string { return proto.CompactTextString(m) } func (*ListRecommendationsRequest) ProtoMessage() {} func (*ListRecommendationsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{6} + return fileDescriptor_ca53982754088a9d, []int{6} } + func (m *ListRecommendationsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListRecommendationsRequest.Unmarshal(m, b) } func (m *ListRecommendationsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListRecommendationsRequest.Marshal(b, m, deterministic) } -func (dst *ListRecommendationsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListRecommendationsRequest.Merge(dst, src) +func (m *ListRecommendationsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListRecommendationsRequest.Merge(m, src) } func (m *ListRecommendationsRequest) XXX_Size() int { return xxx_messageInfo_ListRecommendationsRequest.Size(m) @@ -314,7 +323,7 @@ func (m *ListRecommendationsRequest) GetProductIds() []string { } type ListRecommendationsResponse struct { - ProductIds []string `protobuf:"bytes,1,rep,name=product_ids,json=productIds" json:"product_ids,omitempty"` + ProductIds []string `protobuf:"bytes,1,rep,name=product_ids,json=productIds,proto3" json:"product_ids,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -324,16 +333,17 @@ func (m *ListRecommendationsResponse) Reset() { *m = ListRecommendations func (m *ListRecommendationsResponse) String() string { return proto.CompactTextString(m) } func (*ListRecommendationsResponse) ProtoMessage() {} func (*ListRecommendationsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{7} + return fileDescriptor_ca53982754088a9d, []int{7} } + func (m *ListRecommendationsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListRecommendationsResponse.Unmarshal(m, b) } func (m *ListRecommendationsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListRecommendationsResponse.Marshal(b, m, deterministic) } -func (dst *ListRecommendationsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListRecommendationsResponse.Merge(dst, src) +func (m *ListRecommendationsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListRecommendationsResponse.Merge(m, src) } func (m *ListRecommendationsResponse) XXX_Size() int { return xxx_messageInfo_ListRecommendationsResponse.Size(m) @@ -352,11 +362,14 @@ func (m *ListRecommendationsResponse) GetProductIds() []string { } type Product struct { - Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` - Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` - Picture string `protobuf:"bytes,4,opt,name=picture" json:"picture,omitempty"` - PriceUsd *Money `protobuf:"bytes,5,opt,name=price_usd,json=priceUsd" json:"price_usd,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + Picture string `protobuf:"bytes,4,opt,name=picture,proto3" json:"picture,omitempty"` + PriceUsd *Money `protobuf:"bytes,5,opt,name=price_usd,json=priceUsd,proto3" json:"price_usd,omitempty"` + // Categories such as "vintage" or "gardening" that can be used to look up + // other related products. + Categories []string `protobuf:"bytes,6,rep,name=categories,proto3" json:"categories,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -366,16 +379,17 @@ func (m *Product) Reset() { *m = Product{} } func (m *Product) String() string { return proto.CompactTextString(m) } func (*Product) ProtoMessage() {} func (*Product) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{8} + return fileDescriptor_ca53982754088a9d, []int{8} } + func (m *Product) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Product.Unmarshal(m, b) } func (m *Product) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Product.Marshal(b, m, deterministic) } -func (dst *Product) XXX_Merge(src proto.Message) { - xxx_messageInfo_Product.Merge(dst, src) +func (m *Product) XXX_Merge(src proto.Message) { + xxx_messageInfo_Product.Merge(m, src) } func (m *Product) XXX_Size() int { return xxx_messageInfo_Product.Size(m) @@ -421,8 +435,15 @@ func (m *Product) GetPriceUsd() *Money { return nil } +func (m *Product) GetCategories() []string { + if m != nil { + return m.Categories + } + return nil +} + type ListProductsResponse struct { - Products []*Product `protobuf:"bytes,1,rep,name=products" json:"products,omitempty"` + Products []*Product `protobuf:"bytes,1,rep,name=products,proto3" json:"products,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -432,16 +453,17 @@ func (m *ListProductsResponse) Reset() { *m = ListProductsResponse{} } func (m *ListProductsResponse) String() string { return proto.CompactTextString(m) } func (*ListProductsResponse) ProtoMessage() {} func (*ListProductsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{9} + return fileDescriptor_ca53982754088a9d, []int{9} } + func (m *ListProductsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListProductsResponse.Unmarshal(m, b) } func (m *ListProductsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListProductsResponse.Marshal(b, m, deterministic) } -func (dst *ListProductsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListProductsResponse.Merge(dst, src) +func (m *ListProductsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListProductsResponse.Merge(m, src) } func (m *ListProductsResponse) XXX_Size() int { return xxx_messageInfo_ListProductsResponse.Size(m) @@ -460,7 +482,7 @@ func (m *ListProductsResponse) GetProducts() []*Product { } type GetProductRequest struct { - Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -470,16 +492,17 @@ func (m *GetProductRequest) Reset() { *m = GetProductRequest{} } func (m *GetProductRequest) String() string { return proto.CompactTextString(m) } func (*GetProductRequest) ProtoMessage() {} func (*GetProductRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{10} + return fileDescriptor_ca53982754088a9d, []int{10} } + func (m *GetProductRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetProductRequest.Unmarshal(m, b) } func (m *GetProductRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetProductRequest.Marshal(b, m, deterministic) } -func (dst *GetProductRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetProductRequest.Merge(dst, src) +func (m *GetProductRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetProductRequest.Merge(m, src) } func (m *GetProductRequest) XXX_Size() int { return xxx_messageInfo_GetProductRequest.Size(m) @@ -498,7 +521,7 @@ func (m *GetProductRequest) GetId() string { } type SearchProductsRequest struct { - Query string `protobuf:"bytes,1,opt,name=query" json:"query,omitempty"` + Query string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -508,16 +531,17 @@ func (m *SearchProductsRequest) Reset() { *m = SearchProductsRequest{} } func (m *SearchProductsRequest) String() string { return proto.CompactTextString(m) } func (*SearchProductsRequest) ProtoMessage() {} func (*SearchProductsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{11} + return fileDescriptor_ca53982754088a9d, []int{11} } + func (m *SearchProductsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SearchProductsRequest.Unmarshal(m, b) } func (m *SearchProductsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SearchProductsRequest.Marshal(b, m, deterministic) } -func (dst *SearchProductsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_SearchProductsRequest.Merge(dst, src) +func (m *SearchProductsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SearchProductsRequest.Merge(m, src) } func (m *SearchProductsRequest) XXX_Size() int { return xxx_messageInfo_SearchProductsRequest.Size(m) @@ -536,7 +560,7 @@ func (m *SearchProductsRequest) GetQuery() string { } type SearchProductsResponse struct { - Results []*Product `protobuf:"bytes,1,rep,name=results" json:"results,omitempty"` + Results []*Product `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -546,16 +570,17 @@ func (m *SearchProductsResponse) Reset() { *m = SearchProductsResponse{} func (m *SearchProductsResponse) String() string { return proto.CompactTextString(m) } func (*SearchProductsResponse) ProtoMessage() {} func (*SearchProductsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{12} + return fileDescriptor_ca53982754088a9d, []int{12} } + func (m *SearchProductsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SearchProductsResponse.Unmarshal(m, b) } func (m *SearchProductsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SearchProductsResponse.Marshal(b, m, deterministic) } -func (dst *SearchProductsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_SearchProductsResponse.Merge(dst, src) +func (m *SearchProductsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_SearchProductsResponse.Merge(m, src) } func (m *SearchProductsResponse) XXX_Size() int { return xxx_messageInfo_SearchProductsResponse.Size(m) @@ -574,8 +599,8 @@ func (m *SearchProductsResponse) GetResults() []*Product { } type GetQuoteRequest struct { - Address *Address `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"` + Address *Address `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -585,16 +610,17 @@ func (m *GetQuoteRequest) Reset() { *m = GetQuoteRequest{} } func (m *GetQuoteRequest) String() string { return proto.CompactTextString(m) } func (*GetQuoteRequest) ProtoMessage() {} func (*GetQuoteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{13} + return fileDescriptor_ca53982754088a9d, []int{13} } + func (m *GetQuoteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetQuoteRequest.Unmarshal(m, b) } func (m *GetQuoteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetQuoteRequest.Marshal(b, m, deterministic) } -func (dst *GetQuoteRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetQuoteRequest.Merge(dst, src) +func (m *GetQuoteRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetQuoteRequest.Merge(m, src) } func (m *GetQuoteRequest) XXX_Size() int { return xxx_messageInfo_GetQuoteRequest.Size(m) @@ -620,7 +646,7 @@ func (m *GetQuoteRequest) GetItems() []*CartItem { } type GetQuoteResponse struct { - CostUsd *Money `protobuf:"bytes,1,opt,name=cost_usd,json=costUsd" json:"cost_usd,omitempty"` + CostUsd *Money `protobuf:"bytes,1,opt,name=cost_usd,json=costUsd,proto3" json:"cost_usd,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -630,16 +656,17 @@ func (m *GetQuoteResponse) Reset() { *m = GetQuoteResponse{} } func (m *GetQuoteResponse) String() string { return proto.CompactTextString(m) } func (*GetQuoteResponse) ProtoMessage() {} func (*GetQuoteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{14} + return fileDescriptor_ca53982754088a9d, []int{14} } + func (m *GetQuoteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetQuoteResponse.Unmarshal(m, b) } func (m *GetQuoteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetQuoteResponse.Marshal(b, m, deterministic) } -func (dst *GetQuoteResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetQuoteResponse.Merge(dst, src) +func (m *GetQuoteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetQuoteResponse.Merge(m, src) } func (m *GetQuoteResponse) XXX_Size() int { return xxx_messageInfo_GetQuoteResponse.Size(m) @@ -658,8 +685,8 @@ func (m *GetQuoteResponse) GetCostUsd() *Money { } type ShipOrderRequest struct { - Address *Address `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"` + Address *Address `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -669,16 +696,17 @@ func (m *ShipOrderRequest) Reset() { *m = ShipOrderRequest{} } func (m *ShipOrderRequest) String() string { return proto.CompactTextString(m) } func (*ShipOrderRequest) ProtoMessage() {} func (*ShipOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{15} + return fileDescriptor_ca53982754088a9d, []int{15} } + func (m *ShipOrderRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShipOrderRequest.Unmarshal(m, b) } func (m *ShipOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ShipOrderRequest.Marshal(b, m, deterministic) } -func (dst *ShipOrderRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ShipOrderRequest.Merge(dst, src) +func (m *ShipOrderRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShipOrderRequest.Merge(m, src) } func (m *ShipOrderRequest) XXX_Size() int { return xxx_messageInfo_ShipOrderRequest.Size(m) @@ -704,7 +732,7 @@ func (m *ShipOrderRequest) GetItems() []*CartItem { } type ShipOrderResponse struct { - TrackingId string `protobuf:"bytes,1,opt,name=tracking_id,json=trackingId" json:"tracking_id,omitempty"` + TrackingId string `protobuf:"bytes,1,opt,name=tracking_id,json=trackingId,proto3" json:"tracking_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -714,16 +742,17 @@ func (m *ShipOrderResponse) Reset() { *m = ShipOrderResponse{} } func (m *ShipOrderResponse) String() string { return proto.CompactTextString(m) } func (*ShipOrderResponse) ProtoMessage() {} func (*ShipOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{16} + return fileDescriptor_ca53982754088a9d, []int{16} } + func (m *ShipOrderResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShipOrderResponse.Unmarshal(m, b) } func (m *ShipOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ShipOrderResponse.Marshal(b, m, deterministic) } -func (dst *ShipOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ShipOrderResponse.Merge(dst, src) +func (m *ShipOrderResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShipOrderResponse.Merge(m, src) } func (m *ShipOrderResponse) XXX_Size() int { return xxx_messageInfo_ShipOrderResponse.Size(m) @@ -742,11 +771,11 @@ func (m *ShipOrderResponse) GetTrackingId() string { } type Address struct { - StreetAddress string `protobuf:"bytes,1,opt,name=street_address,json=streetAddress" json:"street_address,omitempty"` - City string `protobuf:"bytes,2,opt,name=city" json:"city,omitempty"` - State string `protobuf:"bytes,3,opt,name=state" json:"state,omitempty"` - Country string `protobuf:"bytes,4,opt,name=country" json:"country,omitempty"` - ZipCode int32 `protobuf:"varint,5,opt,name=zip_code,json=zipCode" json:"zip_code,omitempty"` + StreetAddress string `protobuf:"bytes,1,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` + City string `protobuf:"bytes,2,opt,name=city,proto3" json:"city,omitempty"` + State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` + Country string `protobuf:"bytes,4,opt,name=country,proto3" json:"country,omitempty"` + ZipCode int32 `protobuf:"varint,5,opt,name=zip_code,json=zipCode,proto3" json:"zip_code,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -756,16 +785,17 @@ func (m *Address) Reset() { *m = Address{} } func (m *Address) String() string { return proto.CompactTextString(m) } func (*Address) ProtoMessage() {} func (*Address) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{17} + return fileDescriptor_ca53982754088a9d, []int{17} } + func (m *Address) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Address.Unmarshal(m, b) } func (m *Address) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Address.Marshal(b, m, deterministic) } -func (dst *Address) XXX_Merge(src proto.Message) { - xxx_messageInfo_Address.Merge(dst, src) +func (m *Address) XXX_Merge(src proto.Message) { + xxx_messageInfo_Address.Merge(m, src) } func (m *Address) XXX_Size() int { return xxx_messageInfo_Address.Size(m) @@ -814,17 +844,17 @@ func (m *Address) GetZipCode() int32 { // Represents an amount of money with its currency type. type Money struct { // The 3-letter currency code defined in ISO 4217. - CurrencyCode string `protobuf:"bytes,1,opt,name=currency_code,json=currencyCode" json:"currency_code,omitempty"` + CurrencyCode string `protobuf:"bytes,1,opt,name=currency_code,json=currencyCode,proto3" json:"currency_code,omitempty"` // The whole units of the amount. // For example if `currencyCode` is `"USD"`, then 1 unit is one US dollar. - Units int64 `protobuf:"varint,2,opt,name=units" json:"units,omitempty"` + Units int64 `protobuf:"varint,2,opt,name=units,proto3" json:"units,omitempty"` // Number of nano (10^-9) units of the amount. // The value must be between -999,999,999 and +999,999,999 inclusive. // If `units` is positive, `nanos` must be positive or zero. // If `units` is zero, `nanos` can be positive, zero, or negative. // If `units` is negative, `nanos` must be negative or zero. // For example $-1.75 is represented as `units`=-1 and `nanos`=-750,000,000. - Nanos int32 `protobuf:"varint,3,opt,name=nanos" json:"nanos,omitempty"` + Nanos int32 `protobuf:"varint,3,opt,name=nanos,proto3" json:"nanos,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -834,16 +864,17 @@ func (m *Money) Reset() { *m = Money{} } func (m *Money) String() string { return proto.CompactTextString(m) } func (*Money) ProtoMessage() {} func (*Money) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{18} + return fileDescriptor_ca53982754088a9d, []int{18} } + func (m *Money) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Money.Unmarshal(m, b) } func (m *Money) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Money.Marshal(b, m, deterministic) } -func (dst *Money) XXX_Merge(src proto.Message) { - xxx_messageInfo_Money.Merge(dst, src) +func (m *Money) XXX_Merge(src proto.Message) { + xxx_messageInfo_Money.Merge(m, src) } func (m *Money) XXX_Size() int { return xxx_messageInfo_Money.Size(m) @@ -877,7 +908,7 @@ func (m *Money) GetNanos() int32 { type GetSupportedCurrenciesResponse struct { // The 3-letter currency code defined in ISO 4217. - CurrencyCodes []string `protobuf:"bytes,1,rep,name=currency_codes,json=currencyCodes" json:"currency_codes,omitempty"` + CurrencyCodes []string `protobuf:"bytes,1,rep,name=currency_codes,json=currencyCodes,proto3" json:"currency_codes,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -887,16 +918,17 @@ func (m *GetSupportedCurrenciesResponse) Reset() { *m = GetSupportedCurr func (m *GetSupportedCurrenciesResponse) String() string { return proto.CompactTextString(m) } func (*GetSupportedCurrenciesResponse) ProtoMessage() {} func (*GetSupportedCurrenciesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{19} + return fileDescriptor_ca53982754088a9d, []int{19} } + func (m *GetSupportedCurrenciesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSupportedCurrenciesResponse.Unmarshal(m, b) } func (m *GetSupportedCurrenciesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetSupportedCurrenciesResponse.Marshal(b, m, deterministic) } -func (dst *GetSupportedCurrenciesResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetSupportedCurrenciesResponse.Merge(dst, src) +func (m *GetSupportedCurrenciesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetSupportedCurrenciesResponse.Merge(m, src) } func (m *GetSupportedCurrenciesResponse) XXX_Size() int { return xxx_messageInfo_GetSupportedCurrenciesResponse.Size(m) @@ -915,9 +947,9 @@ func (m *GetSupportedCurrenciesResponse) GetCurrencyCodes() []string { } type CurrencyConversionRequest struct { - From *Money `protobuf:"bytes,1,opt,name=from" json:"from,omitempty"` + From *Money `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` // The 3-letter currency code defined in ISO 4217. - ToCode string `protobuf:"bytes,2,opt,name=to_code,json=toCode" json:"to_code,omitempty"` + ToCode string `protobuf:"bytes,2,opt,name=to_code,json=toCode,proto3" json:"to_code,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -927,16 +959,17 @@ func (m *CurrencyConversionRequest) Reset() { *m = CurrencyConversionReq func (m *CurrencyConversionRequest) String() string { return proto.CompactTextString(m) } func (*CurrencyConversionRequest) ProtoMessage() {} func (*CurrencyConversionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{20} + return fileDescriptor_ca53982754088a9d, []int{20} } + func (m *CurrencyConversionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CurrencyConversionRequest.Unmarshal(m, b) } func (m *CurrencyConversionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CurrencyConversionRequest.Marshal(b, m, deterministic) } -func (dst *CurrencyConversionRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_CurrencyConversionRequest.Merge(dst, src) +func (m *CurrencyConversionRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CurrencyConversionRequest.Merge(m, src) } func (m *CurrencyConversionRequest) XXX_Size() int { return xxx_messageInfo_CurrencyConversionRequest.Size(m) @@ -962,10 +995,10 @@ func (m *CurrencyConversionRequest) GetToCode() string { } type CreditCardInfo struct { - CreditCardNumber string `protobuf:"bytes,1,opt,name=credit_card_number,json=creditCardNumber" json:"credit_card_number,omitempty"` - CreditCardCvv int32 `protobuf:"varint,2,opt,name=credit_card_cvv,json=creditCardCvv" json:"credit_card_cvv,omitempty"` - CreditCardExpirationYear int32 `protobuf:"varint,3,opt,name=credit_card_expiration_year,json=creditCardExpirationYear" json:"credit_card_expiration_year,omitempty"` - CreditCardExpirationMonth int32 `protobuf:"varint,4,opt,name=credit_card_expiration_month,json=creditCardExpirationMonth" json:"credit_card_expiration_month,omitempty"` + CreditCardNumber string `protobuf:"bytes,1,opt,name=credit_card_number,json=creditCardNumber,proto3" json:"credit_card_number,omitempty"` + CreditCardCvv int32 `protobuf:"varint,2,opt,name=credit_card_cvv,json=creditCardCvv,proto3" json:"credit_card_cvv,omitempty"` + CreditCardExpirationYear int32 `protobuf:"varint,3,opt,name=credit_card_expiration_year,json=creditCardExpirationYear,proto3" json:"credit_card_expiration_year,omitempty"` + CreditCardExpirationMonth int32 `protobuf:"varint,4,opt,name=credit_card_expiration_month,json=creditCardExpirationMonth,proto3" json:"credit_card_expiration_month,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -975,16 +1008,17 @@ func (m *CreditCardInfo) Reset() { *m = CreditCardInfo{} } func (m *CreditCardInfo) String() string { return proto.CompactTextString(m) } func (*CreditCardInfo) ProtoMessage() {} func (*CreditCardInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{21} + return fileDescriptor_ca53982754088a9d, []int{21} } + func (m *CreditCardInfo) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CreditCardInfo.Unmarshal(m, b) } func (m *CreditCardInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CreditCardInfo.Marshal(b, m, deterministic) } -func (dst *CreditCardInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_CreditCardInfo.Merge(dst, src) +func (m *CreditCardInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreditCardInfo.Merge(m, src) } func (m *CreditCardInfo) XXX_Size() int { return xxx_messageInfo_CreditCardInfo.Size(m) @@ -1024,8 +1058,8 @@ func (m *CreditCardInfo) GetCreditCardExpirationMonth() int32 { } type ChargeRequest struct { - Amount *Money `protobuf:"bytes,1,opt,name=amount" json:"amount,omitempty"` - CreditCard *CreditCardInfo `protobuf:"bytes,2,opt,name=credit_card,json=creditCard" json:"credit_card,omitempty"` + Amount *Money `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` + CreditCard *CreditCardInfo `protobuf:"bytes,2,opt,name=credit_card,json=creditCard,proto3" json:"credit_card,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1035,16 +1069,17 @@ func (m *ChargeRequest) Reset() { *m = ChargeRequest{} } func (m *ChargeRequest) String() string { return proto.CompactTextString(m) } func (*ChargeRequest) ProtoMessage() {} func (*ChargeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{22} + return fileDescriptor_ca53982754088a9d, []int{22} } + func (m *ChargeRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChargeRequest.Unmarshal(m, b) } func (m *ChargeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ChargeRequest.Marshal(b, m, deterministic) } -func (dst *ChargeRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ChargeRequest.Merge(dst, src) +func (m *ChargeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChargeRequest.Merge(m, src) } func (m *ChargeRequest) XXX_Size() int { return xxx_messageInfo_ChargeRequest.Size(m) @@ -1070,7 +1105,7 @@ func (m *ChargeRequest) GetCreditCard() *CreditCardInfo { } type ChargeResponse struct { - TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId" json:"transaction_id,omitempty"` + TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1080,16 +1115,17 @@ func (m *ChargeResponse) Reset() { *m = ChargeResponse{} } func (m *ChargeResponse) String() string { return proto.CompactTextString(m) } func (*ChargeResponse) ProtoMessage() {} func (*ChargeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{23} + return fileDescriptor_ca53982754088a9d, []int{23} } + func (m *ChargeResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChargeResponse.Unmarshal(m, b) } func (m *ChargeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ChargeResponse.Marshal(b, m, deterministic) } -func (dst *ChargeResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ChargeResponse.Merge(dst, src) +func (m *ChargeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChargeResponse.Merge(m, src) } func (m *ChargeResponse) XXX_Size() int { return xxx_messageInfo_ChargeResponse.Size(m) @@ -1108,8 +1144,8 @@ func (m *ChargeResponse) GetTransactionId() string { } type OrderItem struct { - Item *CartItem `protobuf:"bytes,1,opt,name=item" json:"item,omitempty"` - Cost *Money `protobuf:"bytes,2,opt,name=cost" json:"cost,omitempty"` + Item *CartItem `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` + Cost *Money `protobuf:"bytes,2,opt,name=cost,proto3" json:"cost,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1119,16 +1155,17 @@ func (m *OrderItem) Reset() { *m = OrderItem{} } func (m *OrderItem) String() string { return proto.CompactTextString(m) } func (*OrderItem) ProtoMessage() {} func (*OrderItem) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{24} + return fileDescriptor_ca53982754088a9d, []int{24} } + func (m *OrderItem) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OrderItem.Unmarshal(m, b) } func (m *OrderItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_OrderItem.Marshal(b, m, deterministic) } -func (dst *OrderItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrderItem.Merge(dst, src) +func (m *OrderItem) XXX_Merge(src proto.Message) { + xxx_messageInfo_OrderItem.Merge(m, src) } func (m *OrderItem) XXX_Size() int { return xxx_messageInfo_OrderItem.Size(m) @@ -1154,11 +1191,11 @@ func (m *OrderItem) GetCost() *Money { } type OrderResult struct { - OrderId string `protobuf:"bytes,1,opt,name=order_id,json=orderId" json:"order_id,omitempty"` - ShippingTrackingId string `protobuf:"bytes,2,opt,name=shipping_tracking_id,json=shippingTrackingId" json:"shipping_tracking_id,omitempty"` - ShippingCost *Money `protobuf:"bytes,3,opt,name=shipping_cost,json=shippingCost" json:"shipping_cost,omitempty"` - ShippingAddress *Address `protobuf:"bytes,4,opt,name=shipping_address,json=shippingAddress" json:"shipping_address,omitempty"` - Items []*OrderItem `protobuf:"bytes,5,rep,name=items" json:"items,omitempty"` + OrderId string `protobuf:"bytes,1,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"` + ShippingTrackingId string `protobuf:"bytes,2,opt,name=shipping_tracking_id,json=shippingTrackingId,proto3" json:"shipping_tracking_id,omitempty"` + ShippingCost *Money `protobuf:"bytes,3,opt,name=shipping_cost,json=shippingCost,proto3" json:"shipping_cost,omitempty"` + ShippingAddress *Address `protobuf:"bytes,4,opt,name=shipping_address,json=shippingAddress,proto3" json:"shipping_address,omitempty"` + Items []*OrderItem `protobuf:"bytes,5,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1168,16 +1205,17 @@ func (m *OrderResult) Reset() { *m = OrderResult{} } func (m *OrderResult) String() string { return proto.CompactTextString(m) } func (*OrderResult) ProtoMessage() {} func (*OrderResult) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{25} + return fileDescriptor_ca53982754088a9d, []int{25} } + func (m *OrderResult) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OrderResult.Unmarshal(m, b) } func (m *OrderResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_OrderResult.Marshal(b, m, deterministic) } -func (dst *OrderResult) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrderResult.Merge(dst, src) +func (m *OrderResult) XXX_Merge(src proto.Message) { + xxx_messageInfo_OrderResult.Merge(m, src) } func (m *OrderResult) XXX_Size() int { return xxx_messageInfo_OrderResult.Size(m) @@ -1224,8 +1262,8 @@ func (m *OrderResult) GetItems() []*OrderItem { } type SendOrderConfirmationRequest struct { - Email string `protobuf:"bytes,1,opt,name=email" json:"email,omitempty"` - Order *OrderResult `protobuf:"bytes,2,opt,name=order" json:"order,omitempty"` + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` + Order *OrderResult `protobuf:"bytes,2,opt,name=order,proto3" json:"order,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1235,16 +1273,17 @@ func (m *SendOrderConfirmationRequest) Reset() { *m = SendOrderConfirmat func (m *SendOrderConfirmationRequest) String() string { return proto.CompactTextString(m) } func (*SendOrderConfirmationRequest) ProtoMessage() {} func (*SendOrderConfirmationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{26} + return fileDescriptor_ca53982754088a9d, []int{26} } + func (m *SendOrderConfirmationRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SendOrderConfirmationRequest.Unmarshal(m, b) } func (m *SendOrderConfirmationRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SendOrderConfirmationRequest.Marshal(b, m, deterministic) } -func (dst *SendOrderConfirmationRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_SendOrderConfirmationRequest.Merge(dst, src) +func (m *SendOrderConfirmationRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SendOrderConfirmationRequest.Merge(m, src) } func (m *SendOrderConfirmationRequest) XXX_Size() int { return xxx_messageInfo_SendOrderConfirmationRequest.Size(m) @@ -1270,11 +1309,11 @@ func (m *SendOrderConfirmationRequest) GetOrder() *OrderResult { } type PlaceOrderRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - UserCurrency string `protobuf:"bytes,2,opt,name=user_currency,json=userCurrency" json:"user_currency,omitempty"` - Address *Address `protobuf:"bytes,3,opt,name=address" json:"address,omitempty"` - Email string `protobuf:"bytes,5,opt,name=email" json:"email,omitempty"` - CreditCard *CreditCardInfo `protobuf:"bytes,6,opt,name=credit_card,json=creditCard" json:"credit_card,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + UserCurrency string `protobuf:"bytes,2,opt,name=user_currency,json=userCurrency,proto3" json:"user_currency,omitempty"` + Address *Address `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` + Email string `protobuf:"bytes,5,opt,name=email,proto3" json:"email,omitempty"` + CreditCard *CreditCardInfo `protobuf:"bytes,6,opt,name=credit_card,json=creditCard,proto3" json:"credit_card,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1284,16 +1323,17 @@ func (m *PlaceOrderRequest) Reset() { *m = PlaceOrderRequest{} } func (m *PlaceOrderRequest) String() string { return proto.CompactTextString(m) } func (*PlaceOrderRequest) ProtoMessage() {} func (*PlaceOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{27} + return fileDescriptor_ca53982754088a9d, []int{27} } + func (m *PlaceOrderRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PlaceOrderRequest.Unmarshal(m, b) } func (m *PlaceOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_PlaceOrderRequest.Marshal(b, m, deterministic) } -func (dst *PlaceOrderRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_PlaceOrderRequest.Merge(dst, src) +func (m *PlaceOrderRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlaceOrderRequest.Merge(m, src) } func (m *PlaceOrderRequest) XXX_Size() int { return xxx_messageInfo_PlaceOrderRequest.Size(m) @@ -1340,7 +1380,7 @@ func (m *PlaceOrderRequest) GetCreditCard() *CreditCardInfo { } type PlaceOrderResponse struct { - Order *OrderResult `protobuf:"bytes,1,opt,name=order" json:"order,omitempty"` + Order *OrderResult `protobuf:"bytes,1,opt,name=order,proto3" json:"order,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1350,16 +1390,17 @@ func (m *PlaceOrderResponse) Reset() { *m = PlaceOrderResponse{} } func (m *PlaceOrderResponse) String() string { return proto.CompactTextString(m) } func (*PlaceOrderResponse) ProtoMessage() {} func (*PlaceOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_e1d03823e14b5fb0, []int{28} + return fileDescriptor_ca53982754088a9d, []int{28} } + func (m *PlaceOrderResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PlaceOrderResponse.Unmarshal(m, b) } func (m *PlaceOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_PlaceOrderResponse.Marshal(b, m, deterministic) } -func (dst *PlaceOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_PlaceOrderResponse.Merge(dst, src) +func (m *PlaceOrderResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlaceOrderResponse.Merge(m, src) } func (m *PlaceOrderResponse) XXX_Size() int { return xxx_messageInfo_PlaceOrderResponse.Size(m) @@ -1377,6 +1418,134 @@ func (m *PlaceOrderResponse) GetOrder() *OrderResult { return nil } +type AdRequest struct { + // List of important key words from the current page describing the context. + ContextKeys []string `protobuf:"bytes,1,rep,name=context_keys,json=contextKeys,proto3" json:"context_keys,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AdRequest) Reset() { *m = AdRequest{} } +func (m *AdRequest) String() string { return proto.CompactTextString(m) } +func (*AdRequest) ProtoMessage() {} +func (*AdRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_ca53982754088a9d, []int{29} +} + +func (m *AdRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AdRequest.Unmarshal(m, b) +} +func (m *AdRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AdRequest.Marshal(b, m, deterministic) +} +func (m *AdRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdRequest.Merge(m, src) +} +func (m *AdRequest) XXX_Size() int { + return xxx_messageInfo_AdRequest.Size(m) +} +func (m *AdRequest) XXX_DiscardUnknown() { + xxx_messageInfo_AdRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_AdRequest proto.InternalMessageInfo + +func (m *AdRequest) GetContextKeys() []string { + if m != nil { + return m.ContextKeys + } + return nil +} + +type AdResponse struct { + Ads []*Ad `protobuf:"bytes,1,rep,name=ads,proto3" json:"ads,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AdResponse) Reset() { *m = AdResponse{} } +func (m *AdResponse) String() string { return proto.CompactTextString(m) } +func (*AdResponse) ProtoMessage() {} +func (*AdResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_ca53982754088a9d, []int{30} +} + +func (m *AdResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AdResponse.Unmarshal(m, b) +} +func (m *AdResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AdResponse.Marshal(b, m, deterministic) +} +func (m *AdResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdResponse.Merge(m, src) +} +func (m *AdResponse) XXX_Size() int { + return xxx_messageInfo_AdResponse.Size(m) +} +func (m *AdResponse) XXX_DiscardUnknown() { + xxx_messageInfo_AdResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_AdResponse proto.InternalMessageInfo + +func (m *AdResponse) GetAds() []*Ad { + if m != nil { + return m.Ads + } + return nil +} + +type Ad struct { + // url to redirect to when an ad is clicked. + RedirectUrl string `protobuf:"bytes,1,opt,name=redirect_url,json=redirectUrl,proto3" json:"redirect_url,omitempty"` + // short advertisement text to display. + Text string `protobuf:"bytes,2,opt,name=text,proto3" json:"text,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Ad) Reset() { *m = Ad{} } +func (m *Ad) String() string { return proto.CompactTextString(m) } +func (*Ad) ProtoMessage() {} +func (*Ad) Descriptor() ([]byte, []int) { + return fileDescriptor_ca53982754088a9d, []int{31} +} + +func (m *Ad) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Ad.Unmarshal(m, b) +} +func (m *Ad) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Ad.Marshal(b, m, deterministic) +} +func (m *Ad) XXX_Merge(src proto.Message) { + xxx_messageInfo_Ad.Merge(m, src) +} +func (m *Ad) XXX_Size() int { + return xxx_messageInfo_Ad.Size(m) +} +func (m *Ad) XXX_DiscardUnknown() { + xxx_messageInfo_Ad.DiscardUnknown(m) +} + +var xxx_messageInfo_Ad proto.InternalMessageInfo + +func (m *Ad) GetRedirectUrl() string { + if m != nil { + return m.RedirectUrl + } + return "" +} + +func (m *Ad) GetText() string { + if m != nil { + return m.Text + } + return "" +} + func init() { proto.RegisterType((*CartItem)(nil), "hipstershop.CartItem") proto.RegisterType((*AddItemRequest)(nil), "hipstershop.AddItemRequest") @@ -1407,6 +1576,9 @@ func init() { proto.RegisterType((*SendOrderConfirmationRequest)(nil), "hipstershop.SendOrderConfirmationRequest") proto.RegisterType((*PlaceOrderRequest)(nil), "hipstershop.PlaceOrderRequest") proto.RegisterType((*PlaceOrderResponse)(nil), "hipstershop.PlaceOrderResponse") + proto.RegisterType((*AdRequest)(nil), "hipstershop.AdRequest") + proto.RegisterType((*AdResponse)(nil), "hipstershop.AdResponse") + proto.RegisterType((*Ad)(nil), "hipstershop.Ad") } // Reference imports to suppress errors if they are not otherwise used. @@ -2127,95 +2299,166 @@ var _CheckoutService_serviceDesc = grpc.ServiceDesc{ Metadata: "demo.proto", } -func init() { proto.RegisterFile("demo.proto", fileDescriptor_demo_e1d03823e14b5fb0) } - -var fileDescriptor_demo_e1d03823e14b5fb0 = []byte{ - // 1389 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xdd, 0x72, 0xd3, 0xc6, - 0x17, 0x8f, 0x12, 0x3b, 0xb6, 0x8f, 0x63, 0x27, 0xd9, 0x7f, 0xc2, 0xdf, 0x28, 0x7c, 0xa4, 0x9b, - 0x81, 0x42, 0x81, 0x94, 0x49, 0x3b, 0xc3, 0x45, 0x69, 0x29, 0x63, 0x32, 0xc6, 0x33, 0x50, 0xa8, - 0x02, 0x1d, 0x3a, 0x74, 0xea, 0x11, 0xda, 0x05, 0xab, 0x44, 0x5a, 0xb1, 0xbb, 0xca, 0xd4, 0x5c, - 0xb6, 0x0f, 0xd0, 0xfb, 0x3e, 0x42, 0x5f, 0xa0, 0xef, 0xd0, 0xfb, 0xbe, 0x42, 0x9f, 0xa3, 0xb3, - 0x2b, 0xad, 0xbe, 0x62, 0x25, 0xe1, 0xa6, 0x77, 0xda, 0xb3, 0xbf, 0x3d, 0xe7, 0x77, 0xce, 0x9e, - 0x73, 0xf6, 0x08, 0x80, 0xd0, 0x80, 0xed, 0x46, 0x9c, 0x49, 0x86, 0xba, 0x53, 0x3f, 0x12, 0x92, - 0x72, 0x31, 0x65, 0x11, 0xde, 0x87, 0xf6, 0xd0, 0xe5, 0x72, 0x2c, 0x69, 0x80, 0x2e, 0x02, 0x44, - 0x9c, 0x91, 0xd8, 0x93, 0x13, 0x9f, 0x0c, 0xac, 0x6d, 0xeb, 0x5a, 0xc7, 0xe9, 0xa4, 0x92, 0x31, - 0x41, 0x36, 0xb4, 0xdf, 0xc5, 0x6e, 0x28, 0x7d, 0x39, 0x1b, 0x2c, 0x6e, 0x5b, 0xd7, 0x9a, 0x4e, - 0xb6, 0xc6, 0xcf, 0xa0, 0x7f, 0x9f, 0x10, 0xa5, 0xc5, 0xa1, 0xef, 0x62, 0x2a, 0x24, 0xfa, 0x3f, - 0xb4, 0x62, 0x41, 0x79, 0xae, 0x69, 0x59, 0x2d, 0xc7, 0x04, 0x5d, 0x87, 0x86, 0x2f, 0x69, 0xa0, - 0x55, 0x74, 0xf7, 0x36, 0x77, 0x0b, 0x6c, 0x76, 0x0d, 0x15, 0x47, 0x43, 0xf0, 0x0d, 0x58, 0xdb, - 0x0f, 0x22, 0x39, 0x53, 0xe2, 0xd3, 0xf4, 0xe2, 0xeb, 0xd0, 0x1f, 0x51, 0x79, 0x26, 0xe8, 0x23, - 0x68, 0x28, 0x5c, 0x3d, 0xc7, 0x1b, 0xd0, 0x54, 0x04, 0xc4, 0x60, 0x71, 0x7b, 0xa9, 0x9e, 0x64, - 0x82, 0xc1, 0x2d, 0x68, 0x6a, 0x96, 0xf8, 0x3b, 0xb0, 0x1f, 0xf9, 0x42, 0x3a, 0xd4, 0x63, 0x41, - 0x40, 0x43, 0xe2, 0x4a, 0x9f, 0x85, 0xe2, 0xd4, 0x80, 0x5c, 0x86, 0x6e, 0x1e, 0xf6, 0xc4, 0x64, - 0xc7, 0x81, 0x2c, 0xee, 0x02, 0x7f, 0x05, 0x5b, 0x73, 0xf5, 0x8a, 0x88, 0x85, 0x82, 0x56, 0xcf, - 0x5b, 0xc7, 0xce, 0xff, 0x6e, 0x41, 0xeb, 0x69, 0xb2, 0x44, 0x7d, 0x58, 0xcc, 0x08, 0x2c, 0xfa, - 0x04, 0x21, 0x68, 0x84, 0x6e, 0x40, 0xf5, 0x6d, 0x74, 0x1c, 0xfd, 0x8d, 0xb6, 0xa1, 0x4b, 0xa8, - 0xf0, 0xb8, 0x1f, 0x29, 0x43, 0x83, 0x25, 0xbd, 0x55, 0x14, 0xa1, 0x01, 0xb4, 0x22, 0xdf, 0x93, - 0x31, 0xa7, 0x83, 0x86, 0xde, 0x35, 0x4b, 0xf4, 0x29, 0x74, 0x22, 0xee, 0x7b, 0x74, 0x12, 0x0b, - 0x32, 0x68, 0xea, 0x2b, 0x46, 0xa5, 0xe8, 0x3d, 0x66, 0x21, 0x9d, 0x39, 0x6d, 0x0d, 0x7a, 0x2e, - 0x08, 0x7e, 0x08, 0x1b, 0xca, 0xb9, 0x94, 0x5f, 0xee, 0xd5, 0x6d, 0x68, 0xa7, 0x2e, 0x24, 0x2e, - 0x75, 0xf7, 0x36, 0x4a, 0x7a, 0xd2, 0x03, 0x4e, 0x86, 0xc2, 0x3b, 0xb0, 0x3e, 0xa2, 0x46, 0x91, - 0x89, 0x7a, 0xc5, 0x5f, 0x7c, 0x0b, 0x36, 0x0f, 0xa8, 0xcb, 0xbd, 0x69, 0x6e, 0x30, 0x01, 0x6e, - 0x40, 0xf3, 0x5d, 0x4c, 0xf9, 0x2c, 0xc5, 0x26, 0x0b, 0xfc, 0x10, 0xce, 0x55, 0xe1, 0x29, 0xbf, - 0x5d, 0x68, 0x71, 0x2a, 0xe2, 0xc3, 0x53, 0xe8, 0x19, 0x10, 0x0e, 0x61, 0x75, 0x44, 0xe5, 0xb7, - 0x31, 0x93, 0xd4, 0x98, 0xdc, 0x85, 0x96, 0x4b, 0x08, 0xa7, 0x42, 0x68, 0xa3, 0x55, 0x15, 0xf7, - 0x93, 0x3d, 0xc7, 0x80, 0x3e, 0x2c, 0x2b, 0xef, 0xc3, 0x5a, 0x6e, 0x2f, 0xe5, 0x7c, 0x0b, 0xda, - 0x1e, 0x13, 0x52, 0xdf, 0x8d, 0x55, 0x7b, 0x37, 0x2d, 0x85, 0x51, 0x57, 0xc3, 0x60, 0xed, 0x60, - 0xea, 0x47, 0x4f, 0x38, 0xa1, 0xfc, 0x3f, 0xe1, 0xfc, 0x39, 0xac, 0x17, 0x0c, 0xe6, 0xe9, 0x2d, - 0xb9, 0xeb, 0xbd, 0xf5, 0xc3, 0x37, 0x79, 0xed, 0x80, 0x11, 0x8d, 0x09, 0xfe, 0xcd, 0x82, 0x56, - 0x6a, 0x17, 0x5d, 0x81, 0xbe, 0x90, 0x9c, 0x52, 0x39, 0x29, 0xb2, 0xec, 0x38, 0xbd, 0x44, 0x6a, - 0x60, 0x08, 0x1a, 0x9e, 0x69, 0x63, 0x1d, 0x47, 0x7f, 0xab, 0x04, 0x10, 0xd2, 0x95, 0x34, 0xcd, - 0xf7, 0x64, 0xa1, 0x32, 0xdd, 0x63, 0x71, 0x28, 0xf9, 0xcc, 0x64, 0x7a, 0xba, 0x44, 0xe7, 0xa1, - 0xfd, 0xde, 0x8f, 0x26, 0x1e, 0x23, 0x54, 0x27, 0x7a, 0xd3, 0x69, 0xbd, 0xf7, 0xa3, 0x21, 0x23, - 0x14, 0xbf, 0x80, 0xa6, 0x0e, 0x25, 0xda, 0x81, 0x9e, 0x17, 0x73, 0x4e, 0x43, 0x6f, 0x96, 0x00, - 0x13, 0x36, 0x2b, 0x46, 0xa8, 0xd0, 0xca, 0x70, 0x1c, 0xfa, 0x52, 0x68, 0x36, 0x4b, 0x4e, 0xb2, - 0x50, 0xd2, 0xd0, 0x0d, 0x99, 0xd0, 0x74, 0x9a, 0x4e, 0xb2, 0xc0, 0x23, 0xb8, 0x34, 0xa2, 0xf2, - 0x20, 0x8e, 0x22, 0xc6, 0x25, 0x25, 0xc3, 0x44, 0x8f, 0x4f, 0xf3, 0xbc, 0xbc, 0x02, 0xfd, 0x92, - 0x49, 0xd3, 0x10, 0x7a, 0x45, 0x9b, 0x02, 0xff, 0x00, 0xe7, 0x87, 0x99, 0x20, 0x3c, 0xa2, 0x5c, - 0xf8, 0x2c, 0x34, 0x97, 0x7c, 0x15, 0x1a, 0xaf, 0x39, 0x0b, 0x4e, 0xc8, 0x11, 0xbd, 0xaf, 0x5a, - 0x9a, 0x64, 0x89, 0x63, 0x49, 0x24, 0x97, 0x25, 0xd3, 0x01, 0xf8, 0xc7, 0x82, 0xfe, 0x90, 0x53, - 0xe2, 0xab, 0x7e, 0x4c, 0xc6, 0xe1, 0x6b, 0x86, 0x6e, 0x02, 0xf2, 0xb4, 0x64, 0xe2, 0xb9, 0x9c, - 0x4c, 0xc2, 0x38, 0x78, 0x45, 0x79, 0x1a, 0x8f, 0x35, 0x2f, 0xc3, 0x7e, 0xa3, 0xe5, 0xe8, 0x2a, - 0xac, 0x16, 0xd1, 0xde, 0xd1, 0x51, 0xfa, 0xe4, 0xf4, 0x72, 0xe8, 0xf0, 0xe8, 0x08, 0x7d, 0x09, - 0x5b, 0x45, 0x1c, 0xfd, 0x39, 0xf2, 0xb9, 0x6e, 0x8f, 0x93, 0x19, 0x75, 0x79, 0x1a, 0xbb, 0x41, - 0x7e, 0x66, 0x3f, 0x03, 0x7c, 0x4f, 0x5d, 0x8e, 0xee, 0xc1, 0x85, 0x9a, 0xe3, 0x01, 0x0b, 0xe5, - 0x54, 0x5f, 0x79, 0xd3, 0x39, 0x3f, 0xef, 0xfc, 0x63, 0x05, 0xc0, 0x33, 0xe8, 0x0d, 0xa7, 0x2e, - 0x7f, 0x93, 0xd5, 0xf4, 0x27, 0xb0, 0xec, 0x06, 0x2a, 0x43, 0x4e, 0x08, 0x5e, 0x8a, 0x40, 0x77, - 0xa1, 0x5b, 0xb0, 0x9e, 0x3e, 0x88, 0x5b, 0xe5, 0x0a, 0x29, 0x05, 0xd1, 0x81, 0x9c, 0x09, 0xbe, - 0x03, 0x7d, 0x63, 0x3a, 0xbf, 0x7a, 0xc9, 0xdd, 0x50, 0xb8, 0x9e, 0x76, 0x21, 0x2b, 0x96, 0x5e, - 0x41, 0x3a, 0x26, 0xf8, 0x47, 0xe8, 0xe8, 0x0a, 0xd3, 0x6f, 0xbe, 0x79, 0x8d, 0xad, 0x53, 0x5f, - 0x63, 0x95, 0x15, 0xaa, 0x33, 0xa4, 0x3c, 0xe7, 0x66, 0x85, 0xda, 0xc7, 0xbf, 0x2c, 0x42, 0xd7, - 0x94, 0x70, 0x7c, 0x28, 0x55, 0xa1, 0x30, 0xb5, 0xcc, 0x09, 0xb5, 0xf4, 0x7a, 0x4c, 0xd0, 0x6d, - 0xd8, 0x10, 0x53, 0x3f, 0x8a, 0x54, 0x6d, 0x17, 0x8b, 0x3c, 0xc9, 0x26, 0x64, 0xf6, 0x9e, 0x65, - 0xc5, 0x8e, 0xee, 0x40, 0x2f, 0x3b, 0xa1, 0xd9, 0x2c, 0xd5, 0xb2, 0x59, 0x31, 0xc0, 0x21, 0x13, - 0x12, 0xdd, 0x83, 0xb5, 0xec, 0xa0, 0xe9, 0x0d, 0x8d, 0x13, 0x3a, 0xd8, 0xaa, 0x41, 0x9b, 0x9e, - 0x71, 0xd3, 0x74, 0xb2, 0xa6, 0xee, 0x64, 0xe7, 0x4a, 0xa7, 0xb2, 0x80, 0x9a, 0x56, 0x46, 0xe0, - 0xc2, 0x01, 0x0d, 0x89, 0x96, 0x0f, 0x59, 0xf8, 0xda, 0xe7, 0x81, 0x4e, 0x9b, 0xc2, 0x73, 0x43, - 0x03, 0xd7, 0x3f, 0x34, 0xcf, 0x8d, 0x5e, 0xa0, 0x5d, 0x68, 0xea, 0xd0, 0xa4, 0x31, 0x1e, 0x1c, - 0xb7, 0x91, 0xc4, 0xd4, 0x49, 0x60, 0xf8, 0x6f, 0x0b, 0xd6, 0x9f, 0x1e, 0xba, 0x1e, 0x2d, 0xf5, - 0xe8, 0xda, 0x49, 0x63, 0x07, 0x7a, 0x7a, 0xc3, 0xb4, 0x82, 0x34, 0xce, 0x2b, 0x4a, 0x68, 0xba, - 0x41, 0xb1, 0xc3, 0x2f, 0x9d, 0xa5, 0xc3, 0x67, 0x9e, 0x34, 0x8b, 0x9e, 0x54, 0x72, 0x7b, 0xf9, - 0xc3, 0x72, 0xfb, 0x01, 0xa0, 0xa2, 0x5b, 0xd9, 0x93, 0x9b, 0x46, 0xc7, 0x3a, 0x53, 0x74, 0xf6, - 0xfe, 0xb2, 0xa0, 0xab, 0x72, 0xf8, 0x80, 0xf2, 0x23, 0xdf, 0xa3, 0xe8, 0xae, 0x7e, 0x27, 0x74, - 0xda, 0x6f, 0x55, 0x7d, 0x2a, 0x8c, 0xae, 0x76, 0x39, 0x99, 0x92, 0xd9, 0x6e, 0x01, 0x7d, 0x01, - 0xad, 0x74, 0xbe, 0xac, 0x9c, 0x2e, 0x4f, 0x9d, 0xf6, 0xfa, 0xb1, 0x1a, 0xc2, 0x0b, 0xe8, 0x6b, - 0xe8, 0x64, 0x93, 0x2c, 0xba, 0x78, 0x5c, 0x7f, 0x51, 0xc1, 0x5c, 0xf3, 0x7b, 0xbf, 0x5a, 0xb0, - 0x59, 0x9e, 0x00, 0x8d, 0x5b, 0x3f, 0xc1, 0xff, 0xe6, 0x8c, 0x87, 0xe8, 0xe3, 0x92, 0x9a, 0xfa, - 0xc1, 0xd4, 0xbe, 0x76, 0x3a, 0x30, 0xb9, 0x00, 0xc5, 0x62, 0x11, 0x36, 0xd3, 0xd1, 0x66, 0xe8, - 0x4a, 0xf7, 0x90, 0xbd, 0x31, 0x2c, 0x46, 0xb0, 0x52, 0x9c, 0xe3, 0xd0, 0x1c, 0x2f, 0xec, 0x8f, - 0x8e, 0x59, 0xaa, 0x8e, 0x55, 0x78, 0x01, 0x3d, 0x00, 0xc8, 0xc7, 0x38, 0x74, 0xa9, 0x1a, 0xea, - 0xf2, 0x7c, 0x67, 0xcf, 0x9d, 0xba, 0xf0, 0x02, 0x7a, 0x09, 0xfd, 0xf2, 0xe0, 0x86, 0x70, 0x09, - 0x39, 0x77, 0x08, 0xb4, 0x77, 0x4e, 0xc4, 0x64, 0x51, 0xf8, 0xc3, 0x82, 0xd5, 0x83, 0xb4, 0x3d, - 0x18, 0xff, 0xc7, 0xd0, 0x36, 0xf3, 0x16, 0xba, 0x50, 0x25, 0x5d, 0x1c, 0xfb, 0xec, 0x8b, 0x35, - 0xbb, 0x59, 0x04, 0x1e, 0x41, 0x27, 0x1b, 0x83, 0x2a, 0xc9, 0x52, 0x9d, 0xc7, 0xec, 0x4b, 0x75, - 0xdb, 0x19, 0xd9, 0x3f, 0x2d, 0x58, 0x35, 0xc5, 0x6d, 0xc8, 0xbe, 0x84, 0x73, 0xf3, 0xc7, 0x88, - 0xb9, 0xd7, 0x76, 0xa3, 0x4a, 0xf8, 0x84, 0xf9, 0x03, 0x2f, 0xa0, 0x11, 0xb4, 0x92, 0x91, 0x42, - 0xa2, 0xab, 0xe5, 0x5a, 0xa8, 0x1b, 0x38, 0xec, 0x39, 0xed, 0x1b, 0x2f, 0xec, 0x3d, 0x87, 0xfe, - 0x53, 0x77, 0x16, 0xd0, 0x30, 0xab, 0xe0, 0x21, 0x2c, 0x27, 0x6f, 0x1e, 0xb2, 0xcb, 0x9a, 0x8b, - 0x6f, 0xb0, 0xbd, 0x35, 0x77, 0x2f, 0x0b, 0xc8, 0x14, 0x56, 0xf6, 0x55, 0x8f, 0x32, 0x4a, 0x5f, - 0xa8, 0x5f, 0x82, 0x39, 0xad, 0x1a, 0x5d, 0xaf, 0x64, 0x43, 0x7d, 0x3b, 0xaf, 0xa9, 0xd9, 0x57, - 0xb0, 0x3a, 0x9c, 0x52, 0xef, 0x2d, 0x8b, 0x33, 0x0f, 0x9e, 0x00, 0xe4, 0x9d, 0xad, 0x92, 0xdd, - 0xc7, 0x3a, 0xb9, 0x7d, 0xb9, 0x76, 0xdf, 0x78, 0xf3, 0x6a, 0x59, 0xff, 0xd4, 0x7f, 0xf6, 0x6f, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x59, 0xab, 0x01, 0x43, 0xe2, 0x0f, 0x00, 0x00, +// AdServiceClient is the client API for AdService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type AdServiceClient interface { + GetAds(ctx context.Context, in *AdRequest, opts ...grpc.CallOption) (*AdResponse, error) +} + +type adServiceClient struct { + cc *grpc.ClientConn +} + +func NewAdServiceClient(cc *grpc.ClientConn) AdServiceClient { + return &adServiceClient{cc} +} + +func (c *adServiceClient) GetAds(ctx context.Context, in *AdRequest, opts ...grpc.CallOption) (*AdResponse, error) { + out := new(AdResponse) + err := c.cc.Invoke(ctx, "/hipstershop.AdService/GetAds", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AdServiceServer is the server API for AdService service. +type AdServiceServer interface { + GetAds(context.Context, *AdRequest) (*AdResponse, error) +} + +func RegisterAdServiceServer(s *grpc.Server, srv AdServiceServer) { + s.RegisterService(&_AdService_serviceDesc, srv) +} + +func _AdService_GetAds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdServiceServer).GetAds(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hipstershop.AdService/GetAds", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdServiceServer).GetAds(ctx, req.(*AdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _AdService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "hipstershop.AdService", + HandlerType: (*AdServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetAds", + Handler: _AdService_GetAds_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "demo.proto", +} + +func init() { proto.RegisterFile("demo.proto", fileDescriptor_ca53982754088a9d) } + +var fileDescriptor_ca53982754088a9d = []byte{ + // 1500 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xef, 0x72, 0x13, 0xb7, + 0x16, 0xcf, 0x26, 0xb1, 0x1d, 0x1f, 0xc7, 0x4e, 0xa2, 0x9b, 0x04, 0xb3, 0x81, 0x10, 0x94, 0x81, + 0x0b, 0x17, 0x08, 0x4c, 0xee, 0x9d, 0xe1, 0x03, 0xdc, 0xd2, 0x8c, 0xc9, 0x18, 0x4f, 0xa1, 0xd0, + 0x0d, 0xe9, 0xd0, 0xa1, 0x53, 0xcf, 0xb2, 0x12, 0xf1, 0x96, 0xec, 0x6a, 0x91, 0xb4, 0x19, 0xcc, + 0xc7, 0xf6, 0x01, 0xfa, 0x1e, 0x7d, 0x81, 0xce, 0xf4, 0x11, 0xfa, 0xbd, 0xaf, 0xd0, 0xe7, 0xe8, + 0x48, 0xbb, 0xda, 0x7f, 0xb1, 0x13, 0xf8, 0xd2, 0x6f, 0xab, 0xa3, 0x9f, 0xce, 0xf9, 0xe9, 0xe8, + 0xfc, 0xb3, 0x01, 0x08, 0x0d, 0xd8, 0x4e, 0xc4, 0x99, 0x64, 0xa8, 0x35, 0xf2, 0x23, 0x21, 0x29, + 0x17, 0x23, 0x16, 0xe1, 0x7d, 0x58, 0xe8, 0xb9, 0x5c, 0x0e, 0x24, 0x0d, 0xd0, 0x65, 0x80, 0x88, + 0x33, 0x12, 0x7b, 0x72, 0xe8, 0x93, 0xae, 0xb5, 0x65, 0xdd, 0x68, 0x3a, 0xcd, 0x54, 0x32, 0x20, + 0xc8, 0x86, 0x85, 0xf7, 0xb1, 0x1b, 0x4a, 0x5f, 0x8e, 0xbb, 0xb3, 0x5b, 0xd6, 0x8d, 0x9a, 0x93, + 0xad, 0xf1, 0x4b, 0xe8, 0xec, 0x11, 0xa2, 0xb4, 0x38, 0xf4, 0x7d, 0x4c, 0x85, 0x44, 0x17, 0xa0, + 0x11, 0x0b, 0xca, 0x73, 0x4d, 0x75, 0xb5, 0x1c, 0x10, 0x74, 0x13, 0xe6, 0x7d, 0x49, 0x03, 0xad, + 0xa2, 0xb5, 0xbb, 0xb6, 0x53, 0x60, 0xb3, 0x63, 0xa8, 0x38, 0x1a, 0x82, 0x6f, 0xc1, 0xf2, 0x7e, + 0x10, 0xc9, 0xb1, 0x12, 0x9f, 0xa7, 0x17, 0xdf, 0x84, 0x4e, 0x9f, 0xca, 0x4f, 0x82, 0x3e, 0x85, + 0x79, 0x85, 0x9b, 0xce, 0xf1, 0x16, 0xd4, 0x14, 0x01, 0xd1, 0x9d, 0xdd, 0x9a, 0x9b, 0x4e, 0x32, + 0xc1, 0xe0, 0x06, 0xd4, 0x34, 0x4b, 0xfc, 0x2d, 0xd8, 0x4f, 0x7d, 0x21, 0x1d, 0xea, 0xb1, 0x20, + 0xa0, 0x21, 0x71, 0xa5, 0xcf, 0x42, 0x71, 0xae, 0x43, 0xae, 0x40, 0x2b, 0x77, 0x7b, 0x62, 0xb2, + 0xe9, 0x40, 0xe6, 0x77, 0x81, 0xbf, 0x80, 0x8d, 0x89, 0x7a, 0x45, 0xc4, 0x42, 0x41, 0xab, 0xe7, + 0xad, 0x53, 0xe7, 0x7f, 0xb7, 0xa0, 0xf1, 0x22, 0x59, 0xa2, 0x0e, 0xcc, 0x66, 0x04, 0x66, 0x7d, + 0x82, 0x10, 0xcc, 0x87, 0x6e, 0x40, 0xf5, 0x6b, 0x34, 0x1d, 0xfd, 0x8d, 0xb6, 0xa0, 0x45, 0xa8, + 0xf0, 0xb8, 0x1f, 0x29, 0x43, 0xdd, 0x39, 0xbd, 0x55, 0x14, 0xa1, 0x2e, 0x34, 0x22, 0xdf, 0x93, + 0x31, 0xa7, 0xdd, 0x79, 0xbd, 0x6b, 0x96, 0xe8, 0x2e, 0x34, 0x23, 0xee, 0x7b, 0x74, 0x18, 0x0b, + 0xd2, 0xad, 0xe9, 0x27, 0x46, 0x25, 0xef, 0x3d, 0x63, 0x21, 0x1d, 0x3b, 0x0b, 0x1a, 0x74, 0x28, + 0x08, 0xda, 0x04, 0xf0, 0x5c, 0x49, 0x8f, 0x18, 0xf7, 0xa9, 0xe8, 0xd6, 0x13, 0xf2, 0xb9, 0x04, + 0x3f, 0x81, 0x55, 0x75, 0xf9, 0x94, 0x7f, 0x7e, 0xeb, 0x7b, 0xb0, 0x90, 0x5e, 0x31, 0xb9, 0x72, + 0x6b, 0x77, 0xb5, 0x64, 0x27, 0x3d, 0xe0, 0x64, 0x28, 0xbc, 0x0d, 0x2b, 0x7d, 0x6a, 0x14, 0x99, + 0x57, 0xa9, 0xf8, 0x03, 0xdf, 0x81, 0xb5, 0x03, 0xea, 0x72, 0x6f, 0x94, 0x1b, 0x4c, 0x80, 0xab, + 0x50, 0x7b, 0x1f, 0x53, 0x3e, 0x4e, 0xb1, 0xc9, 0x02, 0x3f, 0x81, 0xf5, 0x2a, 0x3c, 0xe5, 0xb7, + 0x03, 0x0d, 0x4e, 0x45, 0x7c, 0x7c, 0x0e, 0x3d, 0x03, 0xc2, 0x21, 0x2c, 0xf5, 0xa9, 0xfc, 0x26, + 0x66, 0x92, 0x1a, 0x93, 0x3b, 0xd0, 0x70, 0x09, 0xe1, 0x54, 0x08, 0x6d, 0xb4, 0xaa, 0x62, 0x2f, + 0xd9, 0x73, 0x0c, 0xe8, 0xf3, 0xa2, 0x76, 0x0f, 0x96, 0x73, 0x7b, 0x29, 0xe7, 0x3b, 0xb0, 0xe0, + 0x31, 0x21, 0xf5, 0xdb, 0x59, 0x53, 0xdf, 0xae, 0xa1, 0x30, 0x87, 0x82, 0x60, 0x06, 0xcb, 0x07, + 0x23, 0x3f, 0x7a, 0xce, 0x09, 0xe5, 0xff, 0x08, 0xe7, 0xff, 0xc1, 0x4a, 0xc1, 0x60, 0x1e, 0xfe, + 0x92, 0xbb, 0xde, 0x3b, 0x3f, 0x3c, 0xca, 0x73, 0x0b, 0x8c, 0x68, 0x40, 0xf0, 0x2f, 0x16, 0x34, + 0x52, 0xbb, 0xe8, 0x1a, 0x74, 0x84, 0xe4, 0x94, 0xca, 0x61, 0x91, 0x65, 0xd3, 0x69, 0x27, 0x52, + 0x03, 0x43, 0x30, 0xef, 0x99, 0x32, 0xd7, 0x74, 0xf4, 0xb7, 0x0a, 0x00, 0x21, 0x5d, 0x49, 0xd3, + 0x7c, 0x48, 0x16, 0x2a, 0x13, 0x3c, 0x16, 0x87, 0x92, 0x8f, 0x4d, 0x26, 0xa4, 0x4b, 0x74, 0x11, + 0x16, 0x3e, 0xfa, 0xd1, 0xd0, 0x63, 0x84, 0xea, 0x44, 0xa8, 0x39, 0x8d, 0x8f, 0x7e, 0xd4, 0x63, + 0x84, 0xe2, 0x57, 0x50, 0xd3, 0xae, 0x44, 0xdb, 0xd0, 0xf6, 0x62, 0xce, 0x69, 0xe8, 0x8d, 0x13, + 0x60, 0xc2, 0x66, 0xd1, 0x08, 0x15, 0x5a, 0x19, 0x8e, 0x43, 0x5f, 0x0a, 0xcd, 0x66, 0xce, 0x49, + 0x16, 0x4a, 0x1a, 0xba, 0x21, 0x13, 0x9a, 0x4e, 0xcd, 0x49, 0x16, 0xb8, 0x0f, 0x9b, 0x7d, 0x2a, + 0x0f, 0xe2, 0x28, 0x62, 0x5c, 0x52, 0xd2, 0x4b, 0xf4, 0xf8, 0x34, 0x8f, 0xcb, 0x6b, 0xd0, 0x29, + 0x99, 0x34, 0x05, 0xa3, 0x5d, 0xb4, 0x29, 0xf0, 0xf7, 0x70, 0xb1, 0x97, 0x09, 0xc2, 0x13, 0xca, + 0x85, 0xcf, 0x42, 0xf3, 0xc8, 0xd7, 0x61, 0xfe, 0x2d, 0x67, 0xc1, 0x19, 0x31, 0xa2, 0xf7, 0x55, + 0xc9, 0x93, 0x2c, 0xb9, 0x58, 0xe2, 0xc9, 0xba, 0x64, 0xda, 0x01, 0x7f, 0x59, 0xd0, 0xe9, 0x71, + 0x4a, 0x7c, 0x55, 0xaf, 0xc9, 0x20, 0x7c, 0xcb, 0xd0, 0x6d, 0x40, 0x9e, 0x96, 0x0c, 0x3d, 0x97, + 0x93, 0x61, 0x18, 0x07, 0x6f, 0x28, 0x4f, 0xfd, 0xb1, 0xec, 0x65, 0xd8, 0xaf, 0xb5, 0x1c, 0x5d, + 0x87, 0xa5, 0x22, 0xda, 0x3b, 0x39, 0x49, 0x5b, 0x52, 0x3b, 0x87, 0xf6, 0x4e, 0x4e, 0xd0, 0xff, + 0x61, 0xa3, 0x88, 0xa3, 0x1f, 0x22, 0x9f, 0xeb, 0xf2, 0x39, 0x1c, 0x53, 0x97, 0xa7, 0xbe, 0xeb, + 0xe6, 0x67, 0xf6, 0x33, 0xc0, 0x77, 0xd4, 0xe5, 0xe8, 0x11, 0x5c, 0x9a, 0x72, 0x3c, 0x60, 0xa1, + 0x1c, 0xe9, 0x27, 0xaf, 0x39, 0x17, 0x27, 0x9d, 0x7f, 0xa6, 0x00, 0x78, 0x0c, 0xed, 0xde, 0xc8, + 0xe5, 0x47, 0x59, 0x4e, 0xff, 0x07, 0xea, 0x6e, 0xa0, 0x22, 0xe4, 0x0c, 0xe7, 0xa5, 0x08, 0xf4, + 0x10, 0x5a, 0x05, 0xeb, 0x69, 0xc3, 0xdc, 0x28, 0x67, 0x48, 0xc9, 0x89, 0x0e, 0xe4, 0x4c, 0xf0, + 0x7d, 0xe8, 0x18, 0xd3, 0xf9, 0xd3, 0x4b, 0xee, 0x86, 0xc2, 0xf5, 0xf4, 0x15, 0xb2, 0x64, 0x69, + 0x17, 0xa4, 0x03, 0x82, 0x7f, 0x80, 0xa6, 0xce, 0x30, 0x3d, 0x13, 0x98, 0x6e, 0x6d, 0x9d, 0xdb, + 0xad, 0x55, 0x54, 0xa8, 0xca, 0x90, 0xf2, 0x9c, 0x18, 0x15, 0x6a, 0x1f, 0xff, 0x34, 0x0b, 0x2d, + 0x93, 0xc2, 0xf1, 0xb1, 0x54, 0x89, 0xc2, 0xd4, 0x32, 0x27, 0xd4, 0xd0, 0xeb, 0x01, 0x41, 0xf7, + 0x60, 0x55, 0x8c, 0xfc, 0x28, 0x52, 0xb9, 0x5d, 0x4c, 0xf2, 0x24, 0x9a, 0x90, 0xd9, 0x7b, 0x99, + 0x25, 0x3b, 0xba, 0x0f, 0xed, 0xec, 0x84, 0x66, 0x33, 0x37, 0x95, 0xcd, 0xa2, 0x01, 0xf6, 0x98, + 0x90, 0xe8, 0x11, 0x2c, 0x67, 0x07, 0x4d, 0x6d, 0x98, 0x3f, 0xa3, 0x82, 0x2d, 0x19, 0xb4, 0xa9, + 0x19, 0xb7, 0x4d, 0x25, 0xab, 0xe9, 0x4a, 0xb6, 0x5e, 0x3a, 0x95, 0x39, 0xd4, 0x94, 0x32, 0x02, + 0x97, 0x0e, 0x68, 0x48, 0xb4, 0xbc, 0xc7, 0xc2, 0xb7, 0x3e, 0x0f, 0x74, 0xd8, 0x14, 0xda, 0x0d, + 0x0d, 0x5c, 0xff, 0xd8, 0xb4, 0x1b, 0xbd, 0x40, 0x3b, 0x50, 0xd3, 0xae, 0x49, 0x7d, 0xdc, 0x3d, + 0x6d, 0x23, 0xf1, 0xa9, 0x93, 0xc0, 0xf0, 0x9f, 0x16, 0xac, 0xbc, 0x38, 0x76, 0x3d, 0x5a, 0xaa, + 0xd1, 0x53, 0x27, 0x91, 0x6d, 0x68, 0xeb, 0x0d, 0x53, 0x0a, 0x52, 0x3f, 0x2f, 0x2a, 0xa1, 0xa9, + 0x06, 0xc5, 0x0a, 0x3f, 0xf7, 0x29, 0x15, 0x3e, 0xbb, 0x49, 0xad, 0x78, 0x93, 0x4a, 0x6c, 0xd7, + 0x3f, 0x2f, 0xb6, 0x1f, 0x03, 0x2a, 0x5e, 0x2b, 0x6b, 0xb9, 0xa9, 0x77, 0xac, 0x4f, 0xf3, 0xce, + 0x0e, 0x34, 0xf7, 0x88, 0x71, 0xca, 0x55, 0x58, 0xf4, 0x58, 0x28, 0xe9, 0x07, 0x39, 0x7c, 0x47, + 0xc7, 0xa6, 0x2a, 0xb6, 0x52, 0xd9, 0x57, 0x74, 0x2c, 0xf0, 0x5d, 0x00, 0x85, 0x4f, 0xad, 0x5d, + 0x85, 0x39, 0x97, 0x98, 0xe6, 0xbe, 0x54, 0xf1, 0x81, 0xa3, 0xf6, 0xf0, 0x03, 0x98, 0xdd, 0x23, + 0x4a, 0xb3, 0x62, 0xce, 0xa9, 0x27, 0x87, 0x31, 0x37, 0x2f, 0xda, 0x32, 0xb2, 0x43, 0x7e, 0xac, + 0xfa, 0x8d, 0xb2, 0x62, 0xfa, 0x8d, 0xfa, 0xde, 0xfd, 0xc3, 0x82, 0x96, 0xca, 0xb0, 0x03, 0xca, + 0x4f, 0x7c, 0x8f, 0xa2, 0x87, 0xba, 0x8b, 0xe9, 0xa4, 0xdc, 0xa8, 0x7a, 0xbc, 0x30, 0x78, 0xdb, + 0xe5, 0x50, 0x4f, 0x26, 0xd3, 0x19, 0xf4, 0x00, 0x1a, 0xe9, 0x74, 0x5c, 0x39, 0x5d, 0x9e, 0x99, + 0xed, 0x95, 0x53, 0x19, 0x8e, 0x67, 0xd0, 0x97, 0xd0, 0xcc, 0xe6, 0x70, 0x74, 0xf9, 0xb4, 0xfe, + 0xa2, 0x82, 0x89, 0xe6, 0x77, 0x7f, 0xb6, 0x60, 0xad, 0x3c, 0xbf, 0x9a, 0x6b, 0xfd, 0x08, 0xff, + 0x9a, 0x30, 0xdc, 0xa2, 0x7f, 0x97, 0xd4, 0x4c, 0x1f, 0xab, 0xed, 0x1b, 0xe7, 0x03, 0x93, 0x07, + 0x53, 0x2c, 0x66, 0x61, 0x2d, 0x1d, 0xbc, 0x7a, 0xae, 0x74, 0x8f, 0xd9, 0x91, 0x61, 0xd1, 0x87, + 0xc5, 0xe2, 0x94, 0x89, 0x26, 0xdc, 0xc2, 0xbe, 0x7a, 0xca, 0x52, 0x75, 0xe8, 0xc3, 0x33, 0xe8, + 0x31, 0x40, 0x3e, 0x64, 0xa2, 0xcd, 0xaa, 0xab, 0xcb, 0xd3, 0xa7, 0x3d, 0x71, 0x26, 0xc4, 0x33, + 0xe8, 0x35, 0x74, 0xca, 0x63, 0x25, 0xc2, 0x25, 0xe4, 0xc4, 0x11, 0xd5, 0xde, 0x3e, 0x13, 0x93, + 0x79, 0xe1, 0x57, 0x0b, 0x96, 0x0e, 0xd2, 0xe2, 0x65, 0xee, 0x3f, 0x80, 0x05, 0x33, 0x0d, 0xa2, + 0x4b, 0x55, 0xd2, 0xc5, 0xa1, 0xd4, 0xbe, 0x3c, 0x65, 0x37, 0xf3, 0xc0, 0x53, 0x68, 0x66, 0x43, + 0x5a, 0x25, 0x58, 0xaa, 0xd3, 0xa2, 0xbd, 0x39, 0x6d, 0x3b, 0x23, 0xfb, 0x9b, 0x05, 0x4b, 0xa6, + 0xf4, 0x18, 0xb2, 0xaf, 0x61, 0x7d, 0xf2, 0x90, 0x33, 0xf1, 0xd9, 0x6e, 0x55, 0x09, 0x9f, 0x31, + 0x1d, 0xe1, 0x19, 0xd4, 0x87, 0x46, 0x32, 0xf0, 0x48, 0x74, 0xbd, 0x9c, 0x0b, 0xd3, 0xc6, 0x21, + 0x7b, 0x42, 0x73, 0xc1, 0x33, 0xbb, 0x87, 0xd0, 0x79, 0xe1, 0x8e, 0x03, 0x1a, 0x66, 0x19, 0xdc, + 0x83, 0x7a, 0xd2, 0x91, 0x91, 0x5d, 0xd6, 0x5c, 0x9c, 0x10, 0xec, 0x8d, 0x89, 0x7b, 0x99, 0x43, + 0x46, 0xb0, 0xb8, 0xaf, 0x2a, 0xa8, 0x51, 0xfa, 0x4a, 0xfd, 0x60, 0x99, 0xd0, 0x48, 0xd0, 0xcd, + 0x4a, 0x34, 0x4c, 0x6f, 0x36, 0x53, 0x72, 0xf6, 0x0d, 0x2c, 0xf5, 0x46, 0xd4, 0x7b, 0xc7, 0xe2, + 0xec, 0x06, 0xcf, 0x01, 0xf2, 0xba, 0x5b, 0x89, 0xee, 0x53, 0x7d, 0xc6, 0xbe, 0x32, 0x75, 0x3f, + 0xbb, 0xcd, 0x13, 0x55, 0x82, 0x8d, 0xf6, 0x07, 0x50, 0xef, 0xab, 0x19, 0x5c, 0xa0, 0xf5, 0x6a, + 0x39, 0x4d, 0x35, 0x5e, 0x38, 0x25, 0x37, 0x9a, 0xde, 0xd4, 0xf5, 0x9f, 0x1b, 0xff, 0xfd, 0x3b, + 0x00, 0x00, 0xff, 0xff, 0xb2, 0xa0, 0x6e, 0x6c, 0xea, 0x10, 0x00, 0x00, } diff --git a/src/currencyservice/proto/demo.proto b/src/currencyservice/proto/demo.proto index 11b8c29..46e6b7c 100644 --- a/src/currencyservice/proto/demo.proto +++ b/src/currencyservice/proto/demo.proto @@ -64,6 +64,10 @@ message Product { string description = 3; string picture = 4; Money price_usd = 5; + + // Categories such as "vintage" or "gardening" that can be used to look up + // other related products. + repeated string categories = 6; } message ListProductsResponse { @@ -218,18 +222,18 @@ message PlaceOrderResponse { OrderResult order = 1; } -// ------------Ads service------------------ +// ------------Ad service------------------ -service AdsService { - rpc GetAds(AdsRequest) returns (AdsResponse) {} +service AdService { + rpc GetAds(AdRequest) returns (AdResponse) {} } -message AdsRequest { +message AdRequest { // List of important key words from the current page describing the context. repeated string context_keys = 1; } -message AdsResponse { +message AdResponse { repeated Ad ads = 1; } diff --git a/src/frontend/Gopkg.lock b/src/frontend/Gopkg.lock index 52f77b9..fa48498 100644 --- a/src/frontend/Gopkg.lock +++ b/src/frontend/Gopkg.lock @@ -26,17 +26,6 @@ revision = "37aa2801fbf0205003e15636096ebf0373510288" version = "v0.5.0" -[[projects]] - branch = "master" - digest = "1:3ef905a7059a17712b7b27315692992f84f356e828d38f6ff0624e04103ec675" - name = "github.com/GoogleCloudPlatform/microservices-demo" - packages = [ - "src/frontend/genproto", - "src/frontend/money", - ] - pruneopts = "UT" - revision = "6d969441585ade8c91c235115c7cdb12ac61354f" - [[projects]] digest = "1:72856926f8208767b837bf51e3373f49139f61889b67dc7fd3c2a0fd711e3f7a" name = "github.com/golang/protobuf" diff --git a/src/frontend/Gopkg.toml b/src/frontend/Gopkg.toml index b90cfbb..8e53d73 100644 --- a/src/frontend/Gopkg.toml +++ b/src/frontend/Gopkg.toml @@ -33,10 +33,6 @@ name = "contrib.go.opencensus.io/exporter/stackdriver" version = "0.5.0" -[[constraint]] - branch = "master" - name = "github.com/GoogleCloudPlatform/microservices-demo" - [[constraint]] name = "github.com/golang/protobuf" version = "1.2.0" diff --git a/src/frontend/handlers.go b/src/frontend/handlers.go index 10bc2ff..d7e8765 100644 --- a/src/frontend/handlers.go +++ b/src/frontend/handlers.go @@ -80,7 +80,7 @@ func (fe *frontendServer) homeHandler(w http.ResponseWriter, r *http.Request) { "products": ps, "cart_size": len(cart), "banner_color": os.Getenv("BANNER_COLOR"), // illustrates canary deployments - "ad": fe.chooseAd(r.Context(), log), + "ad": fe.chooseAd(r.Context(), []string{}, log), }); err != nil { log.Error(err) } @@ -133,7 +133,7 @@ func (fe *frontendServer) productHandler(w http.ResponseWriter, r *http.Request) if err := templates.ExecuteTemplate(w, "product", map[string]interface{}{ "session_id": sessionID(r), "request_id": r.Context().Value(ctxKeyRequestID{}), - "ad": fe.chooseAd(r.Context(), log), + "ad": fe.chooseAd(r.Context(), p.Categories, log), "user_currency": currentCurrency(r), "currencies": currencies, "product": product, @@ -346,8 +346,8 @@ func (fe *frontendServer) setCurrencyHandler(w http.ResponseWriter, r *http.Requ // chooseAd queries for advertisements available and randomly chooses one, if // available. It ignores the error retrieving the ad since it is not critical. -func (fe *frontendServer) chooseAd(ctx context.Context, log logrus.FieldLogger) *pb.Ad { - ads, err := fe.getAd(ctx) +func (fe *frontendServer) chooseAd(ctx context.Context, ctxKeys []string, log logrus.FieldLogger) *pb.Ad { + ads, err := fe.getAd(ctx, ctxKeys) if err != nil { log.WithField("error", err).Warn("failed to retrieve ads") return nil diff --git a/src/frontend/rpc.go b/src/frontend/rpc.go index 05c99b2..a1dd313 100644 --- a/src/frontend/rpc.go +++ b/src/frontend/rpc.go @@ -116,12 +116,12 @@ func (fe *frontendServer) getRecommendations(ctx context.Context, userID string, return out, err } -func (fe *frontendServer) getAd(ctx context.Context) ([]*pb.Ad, error) { +func (fe *frontendServer) getAd(ctx context.Context, ctxKeys []string) ([]*pb.Ad, error) { ctx, cancel := context.WithTimeout(ctx, time.Millisecond*100) defer cancel() resp, err := pb.NewAdServiceClient(fe.adSvcConn).GetAds(ctx, &pb.AdRequest{ - ContextKeys: nil, + ContextKeys: ctxKeys, }) return resp.GetAds(), errors.Wrap(err, "failed to get ads") } diff --git a/src/paymentservice/proto/demo.proto b/src/paymentservice/proto/demo.proto index 11b8c29..46e6b7c 100644 --- a/src/paymentservice/proto/demo.proto +++ b/src/paymentservice/proto/demo.proto @@ -64,6 +64,10 @@ message Product { string description = 3; string picture = 4; Money price_usd = 5; + + // Categories such as "vintage" or "gardening" that can be used to look up + // other related products. + repeated string categories = 6; } message ListProductsResponse { @@ -218,18 +222,18 @@ message PlaceOrderResponse { OrderResult order = 1; } -// ------------Ads service------------------ +// ------------Ad service------------------ -service AdsService { - rpc GetAds(AdsRequest) returns (AdsResponse) {} +service AdService { + rpc GetAds(AdRequest) returns (AdResponse) {} } -message AdsRequest { +message AdRequest { // List of important key words from the current page describing the context. repeated string context_keys = 1; } -message AdsResponse { +message AdResponse { repeated Ad ads = 1; } diff --git a/src/productcatalogservice/products.json b/src/productcatalogservice/products.json index be0825b..f41b2d9 100644 --- a/src/productcatalogservice/products.json +++ b/src/productcatalogservice/products.json @@ -9,7 +9,8 @@ "currencyCode": "USD", "units": 67, "nanos": 990000000 - } + }, + "categories": ["vintage"] }, { "id": "66VCHSJNUP", @@ -20,7 +21,8 @@ "currencyCode": "USD", "units": 12, "nanos": 490000000 - } + }, + "categories": ["photography", "vintage"] }, { "id": "1YMWWN1N4O", @@ -30,7 +32,8 @@ "priceUsd": { "currencyCode": "USD", "units": 124 - } + }, + "categories": ["cookware"] }, { "id": "L9ECAV7KIM", @@ -41,7 +44,8 @@ "currencyCode": "USD", "units": 36, "nanos": 450000000 - } + }, + "categories": ["gardening"] }, { "id": "2ZYFJ3GM2N", @@ -51,7 +55,8 @@ "priceUsd": { "currencyCode": "USD", "units": 2245 - } + }, + "categories": ["photography", "vintage"] }, { "id": "0PUK6V6EV0", @@ -62,7 +67,8 @@ "currencyCode": "USD", "units": 65, "nanos": 500000000 - } + }, + "categories": ["music", "vintage"] }, { "id": "LS4PSXUNUM", @@ -73,7 +79,8 @@ "currencyCode": "USD", "units": 24, "nanos": 330000000 - } + }, + "categories": ["cookware"] }, { "id": "9SIQT8TOJO", @@ -84,7 +91,8 @@ "currencyCode": "USD", "units": 789, "nanos": 500000000 - } + }, + "categories": ["cycling"] }, { "id": "6E92ZMYYFZ", @@ -95,7 +103,8 @@ "currencyCode": "USD", "units": 12, "nanos": 300000000 - } + }, + "categories": ["gardening"] } ] } diff --git a/src/shippingservice/genproto/demo.pb.go b/src/shippingservice/genproto/demo.pb.go index d548416..f59af20 100644 --- a/src/shippingservice/genproto/demo.pb.go +++ b/src/shippingservice/genproto/demo.pb.go @@ -3,9 +3,11 @@ package hipstershop -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) import ( context "golang.org/x/net/context" @@ -24,8 +26,8 @@ var _ = math.Inf const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package type CartItem struct { - ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId" json:"product_id,omitempty"` - Quantity int32 `protobuf:"varint,2,opt,name=quantity" json:"quantity,omitempty"` + ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` + Quantity int32 `protobuf:"varint,2,opt,name=quantity,proto3" json:"quantity,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -35,16 +37,17 @@ func (m *CartItem) Reset() { *m = CartItem{} } func (m *CartItem) String() string { return proto.CompactTextString(m) } func (*CartItem) ProtoMessage() {} func (*CartItem) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{0} + return fileDescriptor_ca53982754088a9d, []int{0} } + func (m *CartItem) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CartItem.Unmarshal(m, b) } func (m *CartItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CartItem.Marshal(b, m, deterministic) } -func (dst *CartItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_CartItem.Merge(dst, src) +func (m *CartItem) XXX_Merge(src proto.Message) { + xxx_messageInfo_CartItem.Merge(m, src) } func (m *CartItem) XXX_Size() int { return xxx_messageInfo_CartItem.Size(m) @@ -70,8 +73,8 @@ func (m *CartItem) GetQuantity() int32 { } type AddItemRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - Item *CartItem `protobuf:"bytes,2,opt,name=item" json:"item,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Item *CartItem `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -81,16 +84,17 @@ func (m *AddItemRequest) Reset() { *m = AddItemRequest{} } func (m *AddItemRequest) String() string { return proto.CompactTextString(m) } func (*AddItemRequest) ProtoMessage() {} func (*AddItemRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{1} + return fileDescriptor_ca53982754088a9d, []int{1} } + func (m *AddItemRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AddItemRequest.Unmarshal(m, b) } func (m *AddItemRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_AddItemRequest.Marshal(b, m, deterministic) } -func (dst *AddItemRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_AddItemRequest.Merge(dst, src) +func (m *AddItemRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddItemRequest.Merge(m, src) } func (m *AddItemRequest) XXX_Size() int { return xxx_messageInfo_AddItemRequest.Size(m) @@ -116,7 +120,7 @@ func (m *AddItemRequest) GetItem() *CartItem { } type EmptyCartRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -126,16 +130,17 @@ func (m *EmptyCartRequest) Reset() { *m = EmptyCartRequest{} } func (m *EmptyCartRequest) String() string { return proto.CompactTextString(m) } func (*EmptyCartRequest) ProtoMessage() {} func (*EmptyCartRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{2} + return fileDescriptor_ca53982754088a9d, []int{2} } + func (m *EmptyCartRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EmptyCartRequest.Unmarshal(m, b) } func (m *EmptyCartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_EmptyCartRequest.Marshal(b, m, deterministic) } -func (dst *EmptyCartRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_EmptyCartRequest.Merge(dst, src) +func (m *EmptyCartRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_EmptyCartRequest.Merge(m, src) } func (m *EmptyCartRequest) XXX_Size() int { return xxx_messageInfo_EmptyCartRequest.Size(m) @@ -154,7 +159,7 @@ func (m *EmptyCartRequest) GetUserId() string { } type GetCartRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -164,16 +169,17 @@ func (m *GetCartRequest) Reset() { *m = GetCartRequest{} } func (m *GetCartRequest) String() string { return proto.CompactTextString(m) } func (*GetCartRequest) ProtoMessage() {} func (*GetCartRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{3} + return fileDescriptor_ca53982754088a9d, []int{3} } + func (m *GetCartRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetCartRequest.Unmarshal(m, b) } func (m *GetCartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetCartRequest.Marshal(b, m, deterministic) } -func (dst *GetCartRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetCartRequest.Merge(dst, src) +func (m *GetCartRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetCartRequest.Merge(m, src) } func (m *GetCartRequest) XXX_Size() int { return xxx_messageInfo_GetCartRequest.Size(m) @@ -192,8 +198,8 @@ func (m *GetCartRequest) GetUserId() string { } type Cart struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -203,16 +209,17 @@ func (m *Cart) Reset() { *m = Cart{} } func (m *Cart) String() string { return proto.CompactTextString(m) } func (*Cart) ProtoMessage() {} func (*Cart) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{4} + return fileDescriptor_ca53982754088a9d, []int{4} } + func (m *Cart) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Cart.Unmarshal(m, b) } func (m *Cart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Cart.Marshal(b, m, deterministic) } -func (dst *Cart) XXX_Merge(src proto.Message) { - xxx_messageInfo_Cart.Merge(dst, src) +func (m *Cart) XXX_Merge(src proto.Message) { + xxx_messageInfo_Cart.Merge(m, src) } func (m *Cart) XXX_Size() int { return xxx_messageInfo_Cart.Size(m) @@ -247,16 +254,17 @@ func (m *Empty) Reset() { *m = Empty{} } func (m *Empty) String() string { return proto.CompactTextString(m) } func (*Empty) ProtoMessage() {} func (*Empty) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{5} + return fileDescriptor_ca53982754088a9d, []int{5} } + func (m *Empty) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Empty.Unmarshal(m, b) } func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Empty.Marshal(b, m, deterministic) } -func (dst *Empty) XXX_Merge(src proto.Message) { - xxx_messageInfo_Empty.Merge(dst, src) +func (m *Empty) XXX_Merge(src proto.Message) { + xxx_messageInfo_Empty.Merge(m, src) } func (m *Empty) XXX_Size() int { return xxx_messageInfo_Empty.Size(m) @@ -268,8 +276,8 @@ func (m *Empty) XXX_DiscardUnknown() { var xxx_messageInfo_Empty proto.InternalMessageInfo type ListRecommendationsRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - ProductIds []string `protobuf:"bytes,2,rep,name=product_ids,json=productIds" json:"product_ids,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ProductIds []string `protobuf:"bytes,2,rep,name=product_ids,json=productIds,proto3" json:"product_ids,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -279,16 +287,17 @@ func (m *ListRecommendationsRequest) Reset() { *m = ListRecommendationsR func (m *ListRecommendationsRequest) String() string { return proto.CompactTextString(m) } func (*ListRecommendationsRequest) ProtoMessage() {} func (*ListRecommendationsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{6} + return fileDescriptor_ca53982754088a9d, []int{6} } + func (m *ListRecommendationsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListRecommendationsRequest.Unmarshal(m, b) } func (m *ListRecommendationsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListRecommendationsRequest.Marshal(b, m, deterministic) } -func (dst *ListRecommendationsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListRecommendationsRequest.Merge(dst, src) +func (m *ListRecommendationsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListRecommendationsRequest.Merge(m, src) } func (m *ListRecommendationsRequest) XXX_Size() int { return xxx_messageInfo_ListRecommendationsRequest.Size(m) @@ -314,7 +323,7 @@ func (m *ListRecommendationsRequest) GetProductIds() []string { } type ListRecommendationsResponse struct { - ProductIds []string `protobuf:"bytes,1,rep,name=product_ids,json=productIds" json:"product_ids,omitempty"` + ProductIds []string `protobuf:"bytes,1,rep,name=product_ids,json=productIds,proto3" json:"product_ids,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -324,16 +333,17 @@ func (m *ListRecommendationsResponse) Reset() { *m = ListRecommendations func (m *ListRecommendationsResponse) String() string { return proto.CompactTextString(m) } func (*ListRecommendationsResponse) ProtoMessage() {} func (*ListRecommendationsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{7} + return fileDescriptor_ca53982754088a9d, []int{7} } + func (m *ListRecommendationsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListRecommendationsResponse.Unmarshal(m, b) } func (m *ListRecommendationsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListRecommendationsResponse.Marshal(b, m, deterministic) } -func (dst *ListRecommendationsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListRecommendationsResponse.Merge(dst, src) +func (m *ListRecommendationsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListRecommendationsResponse.Merge(m, src) } func (m *ListRecommendationsResponse) XXX_Size() int { return xxx_messageInfo_ListRecommendationsResponse.Size(m) @@ -352,11 +362,14 @@ func (m *ListRecommendationsResponse) GetProductIds() []string { } type Product struct { - Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` - Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` - Picture string `protobuf:"bytes,4,opt,name=picture" json:"picture,omitempty"` - PriceUsd *Money `protobuf:"bytes,5,opt,name=price_usd,json=priceUsd" json:"price_usd,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + Picture string `protobuf:"bytes,4,opt,name=picture,proto3" json:"picture,omitempty"` + PriceUsd *Money `protobuf:"bytes,5,opt,name=price_usd,json=priceUsd,proto3" json:"price_usd,omitempty"` + // Categories such as "vintage" or "gardening" that can be used to look up + // other related products. + Categories []string `protobuf:"bytes,6,rep,name=categories,proto3" json:"categories,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -366,16 +379,17 @@ func (m *Product) Reset() { *m = Product{} } func (m *Product) String() string { return proto.CompactTextString(m) } func (*Product) ProtoMessage() {} func (*Product) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{8} + return fileDescriptor_ca53982754088a9d, []int{8} } + func (m *Product) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Product.Unmarshal(m, b) } func (m *Product) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Product.Marshal(b, m, deterministic) } -func (dst *Product) XXX_Merge(src proto.Message) { - xxx_messageInfo_Product.Merge(dst, src) +func (m *Product) XXX_Merge(src proto.Message) { + xxx_messageInfo_Product.Merge(m, src) } func (m *Product) XXX_Size() int { return xxx_messageInfo_Product.Size(m) @@ -421,8 +435,15 @@ func (m *Product) GetPriceUsd() *Money { return nil } +func (m *Product) GetCategories() []string { + if m != nil { + return m.Categories + } + return nil +} + type ListProductsResponse struct { - Products []*Product `protobuf:"bytes,1,rep,name=products" json:"products,omitempty"` + Products []*Product `protobuf:"bytes,1,rep,name=products,proto3" json:"products,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -432,16 +453,17 @@ func (m *ListProductsResponse) Reset() { *m = ListProductsResponse{} } func (m *ListProductsResponse) String() string { return proto.CompactTextString(m) } func (*ListProductsResponse) ProtoMessage() {} func (*ListProductsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{9} + return fileDescriptor_ca53982754088a9d, []int{9} } + func (m *ListProductsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ListProductsResponse.Unmarshal(m, b) } func (m *ListProductsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ListProductsResponse.Marshal(b, m, deterministic) } -func (dst *ListProductsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListProductsResponse.Merge(dst, src) +func (m *ListProductsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListProductsResponse.Merge(m, src) } func (m *ListProductsResponse) XXX_Size() int { return xxx_messageInfo_ListProductsResponse.Size(m) @@ -460,7 +482,7 @@ func (m *ListProductsResponse) GetProducts() []*Product { } type GetProductRequest struct { - Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -470,16 +492,17 @@ func (m *GetProductRequest) Reset() { *m = GetProductRequest{} } func (m *GetProductRequest) String() string { return proto.CompactTextString(m) } func (*GetProductRequest) ProtoMessage() {} func (*GetProductRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{10} + return fileDescriptor_ca53982754088a9d, []int{10} } + func (m *GetProductRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetProductRequest.Unmarshal(m, b) } func (m *GetProductRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetProductRequest.Marshal(b, m, deterministic) } -func (dst *GetProductRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetProductRequest.Merge(dst, src) +func (m *GetProductRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetProductRequest.Merge(m, src) } func (m *GetProductRequest) XXX_Size() int { return xxx_messageInfo_GetProductRequest.Size(m) @@ -498,7 +521,7 @@ func (m *GetProductRequest) GetId() string { } type SearchProductsRequest struct { - Query string `protobuf:"bytes,1,opt,name=query" json:"query,omitempty"` + Query string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -508,16 +531,17 @@ func (m *SearchProductsRequest) Reset() { *m = SearchProductsRequest{} } func (m *SearchProductsRequest) String() string { return proto.CompactTextString(m) } func (*SearchProductsRequest) ProtoMessage() {} func (*SearchProductsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{11} + return fileDescriptor_ca53982754088a9d, []int{11} } + func (m *SearchProductsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SearchProductsRequest.Unmarshal(m, b) } func (m *SearchProductsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SearchProductsRequest.Marshal(b, m, deterministic) } -func (dst *SearchProductsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_SearchProductsRequest.Merge(dst, src) +func (m *SearchProductsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SearchProductsRequest.Merge(m, src) } func (m *SearchProductsRequest) XXX_Size() int { return xxx_messageInfo_SearchProductsRequest.Size(m) @@ -536,7 +560,7 @@ func (m *SearchProductsRequest) GetQuery() string { } type SearchProductsResponse struct { - Results []*Product `protobuf:"bytes,1,rep,name=results" json:"results,omitempty"` + Results []*Product `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -546,16 +570,17 @@ func (m *SearchProductsResponse) Reset() { *m = SearchProductsResponse{} func (m *SearchProductsResponse) String() string { return proto.CompactTextString(m) } func (*SearchProductsResponse) ProtoMessage() {} func (*SearchProductsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{12} + return fileDescriptor_ca53982754088a9d, []int{12} } + func (m *SearchProductsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SearchProductsResponse.Unmarshal(m, b) } func (m *SearchProductsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SearchProductsResponse.Marshal(b, m, deterministic) } -func (dst *SearchProductsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_SearchProductsResponse.Merge(dst, src) +func (m *SearchProductsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_SearchProductsResponse.Merge(m, src) } func (m *SearchProductsResponse) XXX_Size() int { return xxx_messageInfo_SearchProductsResponse.Size(m) @@ -574,8 +599,8 @@ func (m *SearchProductsResponse) GetResults() []*Product { } type GetQuoteRequest struct { - Address *Address `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"` + Address *Address `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -585,16 +610,17 @@ func (m *GetQuoteRequest) Reset() { *m = GetQuoteRequest{} } func (m *GetQuoteRequest) String() string { return proto.CompactTextString(m) } func (*GetQuoteRequest) ProtoMessage() {} func (*GetQuoteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{13} + return fileDescriptor_ca53982754088a9d, []int{13} } + func (m *GetQuoteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetQuoteRequest.Unmarshal(m, b) } func (m *GetQuoteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetQuoteRequest.Marshal(b, m, deterministic) } -func (dst *GetQuoteRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetQuoteRequest.Merge(dst, src) +func (m *GetQuoteRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetQuoteRequest.Merge(m, src) } func (m *GetQuoteRequest) XXX_Size() int { return xxx_messageInfo_GetQuoteRequest.Size(m) @@ -620,7 +646,7 @@ func (m *GetQuoteRequest) GetItems() []*CartItem { } type GetQuoteResponse struct { - CostUsd *Money `protobuf:"bytes,1,opt,name=cost_usd,json=costUsd" json:"cost_usd,omitempty"` + CostUsd *Money `protobuf:"bytes,1,opt,name=cost_usd,json=costUsd,proto3" json:"cost_usd,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -630,16 +656,17 @@ func (m *GetQuoteResponse) Reset() { *m = GetQuoteResponse{} } func (m *GetQuoteResponse) String() string { return proto.CompactTextString(m) } func (*GetQuoteResponse) ProtoMessage() {} func (*GetQuoteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{14} + return fileDescriptor_ca53982754088a9d, []int{14} } + func (m *GetQuoteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetQuoteResponse.Unmarshal(m, b) } func (m *GetQuoteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetQuoteResponse.Marshal(b, m, deterministic) } -func (dst *GetQuoteResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetQuoteResponse.Merge(dst, src) +func (m *GetQuoteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetQuoteResponse.Merge(m, src) } func (m *GetQuoteResponse) XXX_Size() int { return xxx_messageInfo_GetQuoteResponse.Size(m) @@ -658,8 +685,8 @@ func (m *GetQuoteResponse) GetCostUsd() *Money { } type ShipOrderRequest struct { - Address *Address `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"` + Address *Address `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -669,16 +696,17 @@ func (m *ShipOrderRequest) Reset() { *m = ShipOrderRequest{} } func (m *ShipOrderRequest) String() string { return proto.CompactTextString(m) } func (*ShipOrderRequest) ProtoMessage() {} func (*ShipOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{15} + return fileDescriptor_ca53982754088a9d, []int{15} } + func (m *ShipOrderRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShipOrderRequest.Unmarshal(m, b) } func (m *ShipOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ShipOrderRequest.Marshal(b, m, deterministic) } -func (dst *ShipOrderRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ShipOrderRequest.Merge(dst, src) +func (m *ShipOrderRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShipOrderRequest.Merge(m, src) } func (m *ShipOrderRequest) XXX_Size() int { return xxx_messageInfo_ShipOrderRequest.Size(m) @@ -704,7 +732,7 @@ func (m *ShipOrderRequest) GetItems() []*CartItem { } type ShipOrderResponse struct { - TrackingId string `protobuf:"bytes,1,opt,name=tracking_id,json=trackingId" json:"tracking_id,omitempty"` + TrackingId string `protobuf:"bytes,1,opt,name=tracking_id,json=trackingId,proto3" json:"tracking_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -714,16 +742,17 @@ func (m *ShipOrderResponse) Reset() { *m = ShipOrderResponse{} } func (m *ShipOrderResponse) String() string { return proto.CompactTextString(m) } func (*ShipOrderResponse) ProtoMessage() {} func (*ShipOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{16} + return fileDescriptor_ca53982754088a9d, []int{16} } + func (m *ShipOrderResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShipOrderResponse.Unmarshal(m, b) } func (m *ShipOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ShipOrderResponse.Marshal(b, m, deterministic) } -func (dst *ShipOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ShipOrderResponse.Merge(dst, src) +func (m *ShipOrderResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShipOrderResponse.Merge(m, src) } func (m *ShipOrderResponse) XXX_Size() int { return xxx_messageInfo_ShipOrderResponse.Size(m) @@ -742,11 +771,11 @@ func (m *ShipOrderResponse) GetTrackingId() string { } type Address struct { - StreetAddress string `protobuf:"bytes,1,opt,name=street_address,json=streetAddress" json:"street_address,omitempty"` - City string `protobuf:"bytes,2,opt,name=city" json:"city,omitempty"` - State string `protobuf:"bytes,3,opt,name=state" json:"state,omitempty"` - Country string `protobuf:"bytes,4,opt,name=country" json:"country,omitempty"` - ZipCode int32 `protobuf:"varint,5,opt,name=zip_code,json=zipCode" json:"zip_code,omitempty"` + StreetAddress string `protobuf:"bytes,1,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` + City string `protobuf:"bytes,2,opt,name=city,proto3" json:"city,omitempty"` + State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` + Country string `protobuf:"bytes,4,opt,name=country,proto3" json:"country,omitempty"` + ZipCode int32 `protobuf:"varint,5,opt,name=zip_code,json=zipCode,proto3" json:"zip_code,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -756,16 +785,17 @@ func (m *Address) Reset() { *m = Address{} } func (m *Address) String() string { return proto.CompactTextString(m) } func (*Address) ProtoMessage() {} func (*Address) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{17} + return fileDescriptor_ca53982754088a9d, []int{17} } + func (m *Address) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Address.Unmarshal(m, b) } func (m *Address) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Address.Marshal(b, m, deterministic) } -func (dst *Address) XXX_Merge(src proto.Message) { - xxx_messageInfo_Address.Merge(dst, src) +func (m *Address) XXX_Merge(src proto.Message) { + xxx_messageInfo_Address.Merge(m, src) } func (m *Address) XXX_Size() int { return xxx_messageInfo_Address.Size(m) @@ -814,17 +844,17 @@ func (m *Address) GetZipCode() int32 { // Represents an amount of money with its currency type. type Money struct { // The 3-letter currency code defined in ISO 4217. - CurrencyCode string `protobuf:"bytes,1,opt,name=currency_code,json=currencyCode" json:"currency_code,omitempty"` + CurrencyCode string `protobuf:"bytes,1,opt,name=currency_code,json=currencyCode,proto3" json:"currency_code,omitempty"` // The whole units of the amount. // For example if `currencyCode` is `"USD"`, then 1 unit is one US dollar. - Units int64 `protobuf:"varint,2,opt,name=units" json:"units,omitempty"` + Units int64 `protobuf:"varint,2,opt,name=units,proto3" json:"units,omitempty"` // Number of nano (10^-9) units of the amount. // The value must be between -999,999,999 and +999,999,999 inclusive. // If `units` is positive, `nanos` must be positive or zero. // If `units` is zero, `nanos` can be positive, zero, or negative. // If `units` is negative, `nanos` must be negative or zero. // For example $-1.75 is represented as `units`=-1 and `nanos`=-750,000,000. - Nanos int32 `protobuf:"varint,3,opt,name=nanos" json:"nanos,omitempty"` + Nanos int32 `protobuf:"varint,3,opt,name=nanos,proto3" json:"nanos,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -834,16 +864,17 @@ func (m *Money) Reset() { *m = Money{} } func (m *Money) String() string { return proto.CompactTextString(m) } func (*Money) ProtoMessage() {} func (*Money) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{18} + return fileDescriptor_ca53982754088a9d, []int{18} } + func (m *Money) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Money.Unmarshal(m, b) } func (m *Money) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Money.Marshal(b, m, deterministic) } -func (dst *Money) XXX_Merge(src proto.Message) { - xxx_messageInfo_Money.Merge(dst, src) +func (m *Money) XXX_Merge(src proto.Message) { + xxx_messageInfo_Money.Merge(m, src) } func (m *Money) XXX_Size() int { return xxx_messageInfo_Money.Size(m) @@ -877,7 +908,7 @@ func (m *Money) GetNanos() int32 { type GetSupportedCurrenciesResponse struct { // The 3-letter currency code defined in ISO 4217. - CurrencyCodes []string `protobuf:"bytes,1,rep,name=currency_codes,json=currencyCodes" json:"currency_codes,omitempty"` + CurrencyCodes []string `protobuf:"bytes,1,rep,name=currency_codes,json=currencyCodes,proto3" json:"currency_codes,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -887,16 +918,17 @@ func (m *GetSupportedCurrenciesResponse) Reset() { *m = GetSupportedCurr func (m *GetSupportedCurrenciesResponse) String() string { return proto.CompactTextString(m) } func (*GetSupportedCurrenciesResponse) ProtoMessage() {} func (*GetSupportedCurrenciesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{19} + return fileDescriptor_ca53982754088a9d, []int{19} } + func (m *GetSupportedCurrenciesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSupportedCurrenciesResponse.Unmarshal(m, b) } func (m *GetSupportedCurrenciesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_GetSupportedCurrenciesResponse.Marshal(b, m, deterministic) } -func (dst *GetSupportedCurrenciesResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetSupportedCurrenciesResponse.Merge(dst, src) +func (m *GetSupportedCurrenciesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetSupportedCurrenciesResponse.Merge(m, src) } func (m *GetSupportedCurrenciesResponse) XXX_Size() int { return xxx_messageInfo_GetSupportedCurrenciesResponse.Size(m) @@ -915,9 +947,9 @@ func (m *GetSupportedCurrenciesResponse) GetCurrencyCodes() []string { } type CurrencyConversionRequest struct { - From *Money `protobuf:"bytes,1,opt,name=from" json:"from,omitempty"` + From *Money `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` // The 3-letter currency code defined in ISO 4217. - ToCode string `protobuf:"bytes,2,opt,name=to_code,json=toCode" json:"to_code,omitempty"` + ToCode string `protobuf:"bytes,2,opt,name=to_code,json=toCode,proto3" json:"to_code,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -927,16 +959,17 @@ func (m *CurrencyConversionRequest) Reset() { *m = CurrencyConversionReq func (m *CurrencyConversionRequest) String() string { return proto.CompactTextString(m) } func (*CurrencyConversionRequest) ProtoMessage() {} func (*CurrencyConversionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{20} + return fileDescriptor_ca53982754088a9d, []int{20} } + func (m *CurrencyConversionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CurrencyConversionRequest.Unmarshal(m, b) } func (m *CurrencyConversionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CurrencyConversionRequest.Marshal(b, m, deterministic) } -func (dst *CurrencyConversionRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_CurrencyConversionRequest.Merge(dst, src) +func (m *CurrencyConversionRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CurrencyConversionRequest.Merge(m, src) } func (m *CurrencyConversionRequest) XXX_Size() int { return xxx_messageInfo_CurrencyConversionRequest.Size(m) @@ -962,10 +995,10 @@ func (m *CurrencyConversionRequest) GetToCode() string { } type CreditCardInfo struct { - CreditCardNumber string `protobuf:"bytes,1,opt,name=credit_card_number,json=creditCardNumber" json:"credit_card_number,omitempty"` - CreditCardCvv int32 `protobuf:"varint,2,opt,name=credit_card_cvv,json=creditCardCvv" json:"credit_card_cvv,omitempty"` - CreditCardExpirationYear int32 `protobuf:"varint,3,opt,name=credit_card_expiration_year,json=creditCardExpirationYear" json:"credit_card_expiration_year,omitempty"` - CreditCardExpirationMonth int32 `protobuf:"varint,4,opt,name=credit_card_expiration_month,json=creditCardExpirationMonth" json:"credit_card_expiration_month,omitempty"` + CreditCardNumber string `protobuf:"bytes,1,opt,name=credit_card_number,json=creditCardNumber,proto3" json:"credit_card_number,omitempty"` + CreditCardCvv int32 `protobuf:"varint,2,opt,name=credit_card_cvv,json=creditCardCvv,proto3" json:"credit_card_cvv,omitempty"` + CreditCardExpirationYear int32 `protobuf:"varint,3,opt,name=credit_card_expiration_year,json=creditCardExpirationYear,proto3" json:"credit_card_expiration_year,omitempty"` + CreditCardExpirationMonth int32 `protobuf:"varint,4,opt,name=credit_card_expiration_month,json=creditCardExpirationMonth,proto3" json:"credit_card_expiration_month,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -975,16 +1008,17 @@ func (m *CreditCardInfo) Reset() { *m = CreditCardInfo{} } func (m *CreditCardInfo) String() string { return proto.CompactTextString(m) } func (*CreditCardInfo) ProtoMessage() {} func (*CreditCardInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{21} + return fileDescriptor_ca53982754088a9d, []int{21} } + func (m *CreditCardInfo) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CreditCardInfo.Unmarshal(m, b) } func (m *CreditCardInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_CreditCardInfo.Marshal(b, m, deterministic) } -func (dst *CreditCardInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_CreditCardInfo.Merge(dst, src) +func (m *CreditCardInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreditCardInfo.Merge(m, src) } func (m *CreditCardInfo) XXX_Size() int { return xxx_messageInfo_CreditCardInfo.Size(m) @@ -1024,8 +1058,8 @@ func (m *CreditCardInfo) GetCreditCardExpirationMonth() int32 { } type ChargeRequest struct { - Amount *Money `protobuf:"bytes,1,opt,name=amount" json:"amount,omitempty"` - CreditCard *CreditCardInfo `protobuf:"bytes,2,opt,name=credit_card,json=creditCard" json:"credit_card,omitempty"` + Amount *Money `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` + CreditCard *CreditCardInfo `protobuf:"bytes,2,opt,name=credit_card,json=creditCard,proto3" json:"credit_card,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1035,16 +1069,17 @@ func (m *ChargeRequest) Reset() { *m = ChargeRequest{} } func (m *ChargeRequest) String() string { return proto.CompactTextString(m) } func (*ChargeRequest) ProtoMessage() {} func (*ChargeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{22} + return fileDescriptor_ca53982754088a9d, []int{22} } + func (m *ChargeRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChargeRequest.Unmarshal(m, b) } func (m *ChargeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ChargeRequest.Marshal(b, m, deterministic) } -func (dst *ChargeRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ChargeRequest.Merge(dst, src) +func (m *ChargeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChargeRequest.Merge(m, src) } func (m *ChargeRequest) XXX_Size() int { return xxx_messageInfo_ChargeRequest.Size(m) @@ -1070,7 +1105,7 @@ func (m *ChargeRequest) GetCreditCard() *CreditCardInfo { } type ChargeResponse struct { - TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId" json:"transaction_id,omitempty"` + TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1080,16 +1115,17 @@ func (m *ChargeResponse) Reset() { *m = ChargeResponse{} } func (m *ChargeResponse) String() string { return proto.CompactTextString(m) } func (*ChargeResponse) ProtoMessage() {} func (*ChargeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{23} + return fileDescriptor_ca53982754088a9d, []int{23} } + func (m *ChargeResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChargeResponse.Unmarshal(m, b) } func (m *ChargeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_ChargeResponse.Marshal(b, m, deterministic) } -func (dst *ChargeResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ChargeResponse.Merge(dst, src) +func (m *ChargeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChargeResponse.Merge(m, src) } func (m *ChargeResponse) XXX_Size() int { return xxx_messageInfo_ChargeResponse.Size(m) @@ -1108,8 +1144,8 @@ func (m *ChargeResponse) GetTransactionId() string { } type OrderItem struct { - Item *CartItem `protobuf:"bytes,1,opt,name=item" json:"item,omitempty"` - Cost *Money `protobuf:"bytes,2,opt,name=cost" json:"cost,omitempty"` + Item *CartItem `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` + Cost *Money `protobuf:"bytes,2,opt,name=cost,proto3" json:"cost,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1119,16 +1155,17 @@ func (m *OrderItem) Reset() { *m = OrderItem{} } func (m *OrderItem) String() string { return proto.CompactTextString(m) } func (*OrderItem) ProtoMessage() {} func (*OrderItem) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{24} + return fileDescriptor_ca53982754088a9d, []int{24} } + func (m *OrderItem) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OrderItem.Unmarshal(m, b) } func (m *OrderItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_OrderItem.Marshal(b, m, deterministic) } -func (dst *OrderItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrderItem.Merge(dst, src) +func (m *OrderItem) XXX_Merge(src proto.Message) { + xxx_messageInfo_OrderItem.Merge(m, src) } func (m *OrderItem) XXX_Size() int { return xxx_messageInfo_OrderItem.Size(m) @@ -1154,11 +1191,11 @@ func (m *OrderItem) GetCost() *Money { } type OrderResult struct { - OrderId string `protobuf:"bytes,1,opt,name=order_id,json=orderId" json:"order_id,omitempty"` - ShippingTrackingId string `protobuf:"bytes,2,opt,name=shipping_tracking_id,json=shippingTrackingId" json:"shipping_tracking_id,omitempty"` - ShippingCost *Money `protobuf:"bytes,3,opt,name=shipping_cost,json=shippingCost" json:"shipping_cost,omitempty"` - ShippingAddress *Address `protobuf:"bytes,4,opt,name=shipping_address,json=shippingAddress" json:"shipping_address,omitempty"` - Items []*OrderItem `protobuf:"bytes,5,rep,name=items" json:"items,omitempty"` + OrderId string `protobuf:"bytes,1,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"` + ShippingTrackingId string `protobuf:"bytes,2,opt,name=shipping_tracking_id,json=shippingTrackingId,proto3" json:"shipping_tracking_id,omitempty"` + ShippingCost *Money `protobuf:"bytes,3,opt,name=shipping_cost,json=shippingCost,proto3" json:"shipping_cost,omitempty"` + ShippingAddress *Address `protobuf:"bytes,4,opt,name=shipping_address,json=shippingAddress,proto3" json:"shipping_address,omitempty"` + Items []*OrderItem `protobuf:"bytes,5,rep,name=items,proto3" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1168,16 +1205,17 @@ func (m *OrderResult) Reset() { *m = OrderResult{} } func (m *OrderResult) String() string { return proto.CompactTextString(m) } func (*OrderResult) ProtoMessage() {} func (*OrderResult) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{25} + return fileDescriptor_ca53982754088a9d, []int{25} } + func (m *OrderResult) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OrderResult.Unmarshal(m, b) } func (m *OrderResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_OrderResult.Marshal(b, m, deterministic) } -func (dst *OrderResult) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrderResult.Merge(dst, src) +func (m *OrderResult) XXX_Merge(src proto.Message) { + xxx_messageInfo_OrderResult.Merge(m, src) } func (m *OrderResult) XXX_Size() int { return xxx_messageInfo_OrderResult.Size(m) @@ -1224,8 +1262,8 @@ func (m *OrderResult) GetItems() []*OrderItem { } type SendOrderConfirmationRequest struct { - Email string `protobuf:"bytes,1,opt,name=email" json:"email,omitempty"` - Order *OrderResult `protobuf:"bytes,2,opt,name=order" json:"order,omitempty"` + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` + Order *OrderResult `protobuf:"bytes,2,opt,name=order,proto3" json:"order,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1235,16 +1273,17 @@ func (m *SendOrderConfirmationRequest) Reset() { *m = SendOrderConfirmat func (m *SendOrderConfirmationRequest) String() string { return proto.CompactTextString(m) } func (*SendOrderConfirmationRequest) ProtoMessage() {} func (*SendOrderConfirmationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{26} + return fileDescriptor_ca53982754088a9d, []int{26} } + func (m *SendOrderConfirmationRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SendOrderConfirmationRequest.Unmarshal(m, b) } func (m *SendOrderConfirmationRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_SendOrderConfirmationRequest.Marshal(b, m, deterministic) } -func (dst *SendOrderConfirmationRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_SendOrderConfirmationRequest.Merge(dst, src) +func (m *SendOrderConfirmationRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SendOrderConfirmationRequest.Merge(m, src) } func (m *SendOrderConfirmationRequest) XXX_Size() int { return xxx_messageInfo_SendOrderConfirmationRequest.Size(m) @@ -1269,112 +1308,12 @@ func (m *SendOrderConfirmationRequest) GetOrder() *OrderResult { return nil } -type CreateOrderRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - UserCurrency string `protobuf:"bytes,2,opt,name=user_currency,json=userCurrency" json:"user_currency,omitempty"` - Address *Address `protobuf:"bytes,3,opt,name=address" json:"address,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *CreateOrderRequest) Reset() { *m = CreateOrderRequest{} } -func (m *CreateOrderRequest) String() string { return proto.CompactTextString(m) } -func (*CreateOrderRequest) ProtoMessage() {} -func (*CreateOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{27} -} -func (m *CreateOrderRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_CreateOrderRequest.Unmarshal(m, b) -} -func (m *CreateOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_CreateOrderRequest.Marshal(b, m, deterministic) -} -func (dst *CreateOrderRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_CreateOrderRequest.Merge(dst, src) -} -func (m *CreateOrderRequest) XXX_Size() int { - return xxx_messageInfo_CreateOrderRequest.Size(m) -} -func (m *CreateOrderRequest) XXX_DiscardUnknown() { - xxx_messageInfo_CreateOrderRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_CreateOrderRequest proto.InternalMessageInfo - -func (m *CreateOrderRequest) GetUserId() string { - if m != nil { - return m.UserId - } - return "" -} - -func (m *CreateOrderRequest) GetUserCurrency() string { - if m != nil { - return m.UserCurrency - } - return "" -} - -func (m *CreateOrderRequest) GetAddress() *Address { - if m != nil { - return m.Address - } - return nil -} - -type CreateOrderResponse struct { - Items []*OrderItem `protobuf:"bytes,1,rep,name=items" json:"items,omitempty"` - ShippingCost *Money `protobuf:"bytes,2,opt,name=shipping_cost,json=shippingCost" json:"shipping_cost,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *CreateOrderResponse) Reset() { *m = CreateOrderResponse{} } -func (m *CreateOrderResponse) String() string { return proto.CompactTextString(m) } -func (*CreateOrderResponse) ProtoMessage() {} -func (*CreateOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{28} -} -func (m *CreateOrderResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_CreateOrderResponse.Unmarshal(m, b) -} -func (m *CreateOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_CreateOrderResponse.Marshal(b, m, deterministic) -} -func (dst *CreateOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_CreateOrderResponse.Merge(dst, src) -} -func (m *CreateOrderResponse) XXX_Size() int { - return xxx_messageInfo_CreateOrderResponse.Size(m) -} -func (m *CreateOrderResponse) XXX_DiscardUnknown() { - xxx_messageInfo_CreateOrderResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_CreateOrderResponse proto.InternalMessageInfo - -func (m *CreateOrderResponse) GetItems() []*OrderItem { - if m != nil { - return m.Items - } - return nil -} - -func (m *CreateOrderResponse) GetShippingCost() *Money { - if m != nil { - return m.ShippingCost - } - return nil -} - type PlaceOrderRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` - UserCurrency string `protobuf:"bytes,2,opt,name=user_currency,json=userCurrency" json:"user_currency,omitempty"` - Address *Address `protobuf:"bytes,3,opt,name=address" json:"address,omitempty"` - Email string `protobuf:"bytes,5,opt,name=email" json:"email,omitempty"` - CreditCard *CreditCardInfo `protobuf:"bytes,6,opt,name=credit_card,json=creditCard" json:"credit_card,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + UserCurrency string `protobuf:"bytes,2,opt,name=user_currency,json=userCurrency,proto3" json:"user_currency,omitempty"` + Address *Address `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` + Email string `protobuf:"bytes,5,opt,name=email,proto3" json:"email,omitempty"` + CreditCard *CreditCardInfo `protobuf:"bytes,6,opt,name=credit_card,json=creditCard,proto3" json:"credit_card,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1384,16 +1323,17 @@ func (m *PlaceOrderRequest) Reset() { *m = PlaceOrderRequest{} } func (m *PlaceOrderRequest) String() string { return proto.CompactTextString(m) } func (*PlaceOrderRequest) ProtoMessage() {} func (*PlaceOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{29} + return fileDescriptor_ca53982754088a9d, []int{27} } + func (m *PlaceOrderRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PlaceOrderRequest.Unmarshal(m, b) } func (m *PlaceOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_PlaceOrderRequest.Marshal(b, m, deterministic) } -func (dst *PlaceOrderRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_PlaceOrderRequest.Merge(dst, src) +func (m *PlaceOrderRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlaceOrderRequest.Merge(m, src) } func (m *PlaceOrderRequest) XXX_Size() int { return xxx_messageInfo_PlaceOrderRequest.Size(m) @@ -1440,7 +1380,7 @@ func (m *PlaceOrderRequest) GetCreditCard() *CreditCardInfo { } type PlaceOrderResponse struct { - Order *OrderResult `protobuf:"bytes,1,opt,name=order" json:"order,omitempty"` + Order *OrderResult `protobuf:"bytes,1,opt,name=order,proto3" json:"order,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1450,16 +1390,17 @@ func (m *PlaceOrderResponse) Reset() { *m = PlaceOrderResponse{} } func (m *PlaceOrderResponse) String() string { return proto.CompactTextString(m) } func (*PlaceOrderResponse) ProtoMessage() {} func (*PlaceOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_demo_bbfc9458084e7e4b, []int{30} + return fileDescriptor_ca53982754088a9d, []int{28} } + func (m *PlaceOrderResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PlaceOrderResponse.Unmarshal(m, b) } func (m *PlaceOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_PlaceOrderResponse.Marshal(b, m, deterministic) } -func (dst *PlaceOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_PlaceOrderResponse.Merge(dst, src) +func (m *PlaceOrderResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlaceOrderResponse.Merge(m, src) } func (m *PlaceOrderResponse) XXX_Size() int { return xxx_messageInfo_PlaceOrderResponse.Size(m) @@ -1477,6 +1418,134 @@ func (m *PlaceOrderResponse) GetOrder() *OrderResult { return nil } +type AdRequest struct { + // List of important key words from the current page describing the context. + ContextKeys []string `protobuf:"bytes,1,rep,name=context_keys,json=contextKeys,proto3" json:"context_keys,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AdRequest) Reset() { *m = AdRequest{} } +func (m *AdRequest) String() string { return proto.CompactTextString(m) } +func (*AdRequest) ProtoMessage() {} +func (*AdRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_ca53982754088a9d, []int{29} +} + +func (m *AdRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AdRequest.Unmarshal(m, b) +} +func (m *AdRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AdRequest.Marshal(b, m, deterministic) +} +func (m *AdRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdRequest.Merge(m, src) +} +func (m *AdRequest) XXX_Size() int { + return xxx_messageInfo_AdRequest.Size(m) +} +func (m *AdRequest) XXX_DiscardUnknown() { + xxx_messageInfo_AdRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_AdRequest proto.InternalMessageInfo + +func (m *AdRequest) GetContextKeys() []string { + if m != nil { + return m.ContextKeys + } + return nil +} + +type AdResponse struct { + Ads []*Ad `protobuf:"bytes,1,rep,name=ads,proto3" json:"ads,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AdResponse) Reset() { *m = AdResponse{} } +func (m *AdResponse) String() string { return proto.CompactTextString(m) } +func (*AdResponse) ProtoMessage() {} +func (*AdResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_ca53982754088a9d, []int{30} +} + +func (m *AdResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AdResponse.Unmarshal(m, b) +} +func (m *AdResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AdResponse.Marshal(b, m, deterministic) +} +func (m *AdResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdResponse.Merge(m, src) +} +func (m *AdResponse) XXX_Size() int { + return xxx_messageInfo_AdResponse.Size(m) +} +func (m *AdResponse) XXX_DiscardUnknown() { + xxx_messageInfo_AdResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_AdResponse proto.InternalMessageInfo + +func (m *AdResponse) GetAds() []*Ad { + if m != nil { + return m.Ads + } + return nil +} + +type Ad struct { + // url to redirect to when an ad is clicked. + RedirectUrl string `protobuf:"bytes,1,opt,name=redirect_url,json=redirectUrl,proto3" json:"redirect_url,omitempty"` + // short advertisement text to display. + Text string `protobuf:"bytes,2,opt,name=text,proto3" json:"text,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Ad) Reset() { *m = Ad{} } +func (m *Ad) String() string { return proto.CompactTextString(m) } +func (*Ad) ProtoMessage() {} +func (*Ad) Descriptor() ([]byte, []int) { + return fileDescriptor_ca53982754088a9d, []int{31} +} + +func (m *Ad) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Ad.Unmarshal(m, b) +} +func (m *Ad) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Ad.Marshal(b, m, deterministic) +} +func (m *Ad) XXX_Merge(src proto.Message) { + xxx_messageInfo_Ad.Merge(m, src) +} +func (m *Ad) XXX_Size() int { + return xxx_messageInfo_Ad.Size(m) +} +func (m *Ad) XXX_DiscardUnknown() { + xxx_messageInfo_Ad.DiscardUnknown(m) +} + +var xxx_messageInfo_Ad proto.InternalMessageInfo + +func (m *Ad) GetRedirectUrl() string { + if m != nil { + return m.RedirectUrl + } + return "" +} + +func (m *Ad) GetText() string { + if m != nil { + return m.Text + } + return "" +} + func init() { proto.RegisterType((*CartItem)(nil), "hipstershop.CartItem") proto.RegisterType((*AddItemRequest)(nil), "hipstershop.AddItemRequest") @@ -1505,10 +1574,11 @@ func init() { proto.RegisterType((*OrderItem)(nil), "hipstershop.OrderItem") proto.RegisterType((*OrderResult)(nil), "hipstershop.OrderResult") proto.RegisterType((*SendOrderConfirmationRequest)(nil), "hipstershop.SendOrderConfirmationRequest") - proto.RegisterType((*CreateOrderRequest)(nil), "hipstershop.CreateOrderRequest") - proto.RegisterType((*CreateOrderResponse)(nil), "hipstershop.CreateOrderResponse") proto.RegisterType((*PlaceOrderRequest)(nil), "hipstershop.PlaceOrderRequest") proto.RegisterType((*PlaceOrderResponse)(nil), "hipstershop.PlaceOrderResponse") + proto.RegisterType((*AdRequest)(nil), "hipstershop.AdRequest") + proto.RegisterType((*AdResponse)(nil), "hipstershop.AdResponse") + proto.RegisterType((*Ad)(nil), "hipstershop.Ad") } // Reference imports to suppress errors if they are not otherwise used. @@ -2169,7 +2239,6 @@ var _EmailService_serviceDesc = grpc.ServiceDesc{ // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type CheckoutServiceClient interface { - CreateOrder(ctx context.Context, in *CreateOrderRequest, opts ...grpc.CallOption) (*CreateOrderResponse, error) PlaceOrder(ctx context.Context, in *PlaceOrderRequest, opts ...grpc.CallOption) (*PlaceOrderResponse, error) } @@ -2181,15 +2250,6 @@ func NewCheckoutServiceClient(cc *grpc.ClientConn) CheckoutServiceClient { return &checkoutServiceClient{cc} } -func (c *checkoutServiceClient) CreateOrder(ctx context.Context, in *CreateOrderRequest, opts ...grpc.CallOption) (*CreateOrderResponse, error) { - out := new(CreateOrderResponse) - err := c.cc.Invoke(ctx, "/hipstershop.CheckoutService/CreateOrder", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *checkoutServiceClient) PlaceOrder(ctx context.Context, in *PlaceOrderRequest, opts ...grpc.CallOption) (*PlaceOrderResponse, error) { out := new(PlaceOrderResponse) err := c.cc.Invoke(ctx, "/hipstershop.CheckoutService/PlaceOrder", in, out, opts...) @@ -2201,7 +2261,6 @@ func (c *checkoutServiceClient) PlaceOrder(ctx context.Context, in *PlaceOrderRe // CheckoutServiceServer is the server API for CheckoutService service. type CheckoutServiceServer interface { - CreateOrder(context.Context, *CreateOrderRequest) (*CreateOrderResponse, error) PlaceOrder(context.Context, *PlaceOrderRequest) (*PlaceOrderResponse, error) } @@ -2209,24 +2268,6 @@ func RegisterCheckoutServiceServer(s *grpc.Server, srv CheckoutServiceServer) { s.RegisterService(&_CheckoutService_serviceDesc, srv) } -func _CheckoutService_CreateOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(CreateOrderRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckoutServiceServer).CreateOrder(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.CheckoutService/CreateOrder", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckoutServiceServer).CreateOrder(ctx, req.(*CreateOrderRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _CheckoutService_PlaceOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(PlaceOrderRequest) if err := dec(in); err != nil { @@ -2249,10 +2290,6 @@ var _CheckoutService_serviceDesc = grpc.ServiceDesc{ ServiceName: "hipstershop.CheckoutService", HandlerType: (*CheckoutServiceServer)(nil), Methods: []grpc.MethodDesc{ - { - MethodName: "CreateOrder", - Handler: _CheckoutService_CreateOrder_Handler, - }, { MethodName: "PlaceOrder", Handler: _CheckoutService_PlaceOrder_Handler, @@ -2262,98 +2299,166 @@ var _CheckoutService_serviceDesc = grpc.ServiceDesc{ Metadata: "demo.proto", } -func init() { proto.RegisterFile("demo.proto", fileDescriptor_demo_bbfc9458084e7e4b) } - -var fileDescriptor_demo_bbfc9458084e7e4b = []byte{ - // 1435 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0xdd, 0x72, 0xd3, 0x46, - 0x14, 0x8e, 0x1c, 0x3b, 0xb6, 0x8f, 0x63, 0x27, 0x59, 0x12, 0x6a, 0x14, 0x7e, 0xd2, 0xcd, 0x40, - 0xa1, 0x40, 0xca, 0xa4, 0x9d, 0xe1, 0xa2, 0xb4, 0x94, 0x31, 0x19, 0xe3, 0x19, 0x28, 0x54, 0x81, - 0x0e, 0x1d, 0x3a, 0xf5, 0x08, 0x69, 0xc1, 0x2a, 0x91, 0x56, 0xd9, 0x5d, 0x65, 0x6a, 0xa6, 0x57, - 0xf4, 0x01, 0x7a, 0xdf, 0x47, 0xe8, 0x03, 0xb4, 0xef, 0xd0, 0xfb, 0xbe, 0x42, 0x9f, 0xa3, 0xb3, - 0x2b, 0xad, 0xfe, 0x6c, 0x25, 0xe1, 0xa6, 0xbd, 0xd3, 0xee, 0x7e, 0x7b, 0xce, 0xb7, 0xe7, 0xdf, - 0x06, 0x70, 0x89, 0x4f, 0x77, 0x42, 0x46, 0x05, 0x45, 0x9d, 0x89, 0x17, 0x72, 0x41, 0x18, 0x9f, - 0xd0, 0x10, 0xef, 0x41, 0x6b, 0x60, 0x33, 0x31, 0x12, 0xc4, 0x47, 0x17, 0x00, 0x42, 0x46, 0xdd, - 0xc8, 0x11, 0x63, 0xcf, 0xed, 0x1b, 0x5b, 0xc6, 0xd5, 0xb6, 0xd5, 0x4e, 0x76, 0x46, 0x2e, 0x32, - 0xa1, 0x75, 0x18, 0xd9, 0x81, 0xf0, 0xc4, 0xb4, 0x5f, 0xdb, 0x32, 0xae, 0x36, 0xac, 0x74, 0x8d, - 0x9f, 0x42, 0xef, 0x9e, 0xeb, 0x4a, 0x29, 0x16, 0x39, 0x8c, 0x08, 0x17, 0xe8, 0x03, 0x68, 0x46, - 0x9c, 0xb0, 0x4c, 0xd2, 0x92, 0x5c, 0x8e, 0x5c, 0x74, 0x0d, 0xea, 0x9e, 0x20, 0xbe, 0x12, 0xd1, - 0xd9, 0xdd, 0xd8, 0xc9, 0xb1, 0xd9, 0xd1, 0x54, 0x2c, 0x05, 0xc1, 0xd7, 0x61, 0x75, 0xcf, 0x0f, - 0xc5, 0x54, 0x6e, 0x9f, 0x24, 0x17, 0x5f, 0x83, 0xde, 0x90, 0x88, 0x53, 0x41, 0x1f, 0x42, 0x5d, - 0xe2, 0xaa, 0x39, 0x5e, 0x87, 0x86, 0x24, 0xc0, 0xfb, 0xb5, 0xad, 0xc5, 0x6a, 0x92, 0x31, 0x06, - 0x37, 0xa1, 0xa1, 0x58, 0xe2, 0x6f, 0xc1, 0x7c, 0xe8, 0x71, 0x61, 0x11, 0x87, 0xfa, 0x3e, 0x09, - 0x5c, 0x5b, 0x78, 0x34, 0xe0, 0x27, 0x1a, 0xe4, 0x12, 0x74, 0x32, 0xb3, 0xc7, 0x2a, 0xdb, 0x16, - 0xa4, 0x76, 0xe7, 0xf8, 0x4b, 0xd8, 0x9c, 0x2b, 0x97, 0x87, 0x34, 0xe0, 0xa4, 0x7c, 0xdf, 0x98, - 0xb9, 0xff, 0x9b, 0x01, 0xcd, 0x27, 0xf1, 0x12, 0xf5, 0xa0, 0x96, 0x12, 0xa8, 0x79, 0x2e, 0x42, - 0x50, 0x0f, 0x6c, 0x9f, 0x28, 0x6f, 0xb4, 0x2d, 0xf5, 0x8d, 0xb6, 0xa0, 0xe3, 0x12, 0xee, 0x30, - 0x2f, 0x94, 0x8a, 0xfa, 0x8b, 0xea, 0x28, 0xbf, 0x85, 0xfa, 0xd0, 0x0c, 0x3d, 0x47, 0x44, 0x8c, - 0xf4, 0xeb, 0xea, 0x54, 0x2f, 0xd1, 0x27, 0xd0, 0x0e, 0x99, 0xe7, 0x90, 0x71, 0xc4, 0xdd, 0x7e, - 0x43, 0xb9, 0x18, 0x15, 0xac, 0xf7, 0x88, 0x06, 0x64, 0x6a, 0xb5, 0x14, 0xe8, 0x19, 0x77, 0xf1, - 0x03, 0x58, 0x97, 0x8f, 0x4b, 0xf8, 0x65, 0xaf, 0xba, 0x05, 0xad, 0xe4, 0x09, 0xf1, 0x93, 0x3a, - 0xbb, 0xeb, 0x05, 0x39, 0xc9, 0x05, 0x2b, 0x45, 0xe1, 0x6d, 0x58, 0x1b, 0x12, 0x2d, 0x48, 0x5b, - 0xbd, 0xf4, 0x5e, 0x7c, 0x13, 0x36, 0xf6, 0x89, 0xcd, 0x9c, 0x49, 0xa6, 0x30, 0x06, 0xae, 0x43, - 0xe3, 0x30, 0x22, 0x6c, 0x9a, 0x60, 0xe3, 0x05, 0x7e, 0x00, 0x67, 0xcb, 0xf0, 0x84, 0xdf, 0x0e, - 0x34, 0x19, 0xe1, 0xd1, 0xc1, 0x09, 0xf4, 0x34, 0x08, 0x07, 0xb0, 0x32, 0x24, 0xe2, 0x9b, 0x88, - 0x0a, 0xa2, 0x55, 0xee, 0x40, 0xd3, 0x76, 0x5d, 0x46, 0x38, 0x57, 0x4a, 0xcb, 0x22, 0xee, 0xc5, - 0x67, 0x96, 0x06, 0xbd, 0x5f, 0x54, 0xde, 0x83, 0xd5, 0x4c, 0x5f, 0xc2, 0xf9, 0x26, 0xb4, 0x1c, - 0xca, 0x85, 0xf2, 0x8d, 0x51, 0xe9, 0x9b, 0xa6, 0xc4, 0x48, 0xd7, 0x50, 0x58, 0xdd, 0x9f, 0x78, - 0xe1, 0x63, 0xe6, 0x12, 0xf6, 0x9f, 0x70, 0xfe, 0x0c, 0xd6, 0x72, 0x0a, 0xb3, 0xf0, 0x16, 0xcc, - 0x76, 0xde, 0x78, 0xc1, 0xeb, 0x2c, 0x77, 0x40, 0x6f, 0x8d, 0x5c, 0xfc, 0xab, 0x01, 0xcd, 0x44, - 0x2f, 0xba, 0x0c, 0x3d, 0x2e, 0x18, 0x21, 0x62, 0x9c, 0x67, 0xd9, 0xb6, 0xba, 0xf1, 0xae, 0x86, - 0x21, 0xa8, 0x3b, 0xba, 0x8c, 0xb5, 0x2d, 0xf5, 0x2d, 0x03, 0x80, 0x0b, 0x5b, 0x90, 0x24, 0xde, - 0xe3, 0x85, 0x8c, 0x74, 0x87, 0x46, 0x81, 0x60, 0x53, 0x1d, 0xe9, 0xc9, 0x12, 0x9d, 0x83, 0xd6, - 0x5b, 0x2f, 0x1c, 0x3b, 0xd4, 0x25, 0x2a, 0xd0, 0x1b, 0x56, 0xf3, 0xad, 0x17, 0x0e, 0xa8, 0x4b, - 0xf0, 0x73, 0x68, 0x28, 0x53, 0xa2, 0x6d, 0xe8, 0x3a, 0x11, 0x63, 0x24, 0x70, 0xa6, 0x31, 0x30, - 0x66, 0xb3, 0xac, 0x37, 0x25, 0x5a, 0x2a, 0x8e, 0x02, 0x4f, 0x70, 0xc5, 0x66, 0xd1, 0x8a, 0x17, - 0x72, 0x37, 0xb0, 0x03, 0xca, 0x15, 0x9d, 0x86, 0x15, 0x2f, 0xf0, 0x10, 0x2e, 0x0e, 0x89, 0xd8, - 0x8f, 0xc2, 0x90, 0x32, 0x41, 0xdc, 0x41, 0x2c, 0xc7, 0x23, 0x59, 0x5c, 0x5e, 0x86, 0x5e, 0x41, - 0xa5, 0x2e, 0x08, 0xdd, 0xbc, 0x4e, 0x8e, 0xbf, 0x87, 0x73, 0x83, 0x74, 0x23, 0x38, 0x22, 0x8c, - 0x7b, 0x34, 0xd0, 0x4e, 0xbe, 0x02, 0xf5, 0x57, 0x8c, 0xfa, 0xc7, 0xc4, 0x88, 0x3a, 0x97, 0x25, - 0x4d, 0xd0, 0xf8, 0x61, 0xb1, 0x25, 0x97, 0x04, 0x55, 0x06, 0xf8, 0xc7, 0x80, 0xde, 0x80, 0x11, - 0xd7, 0x93, 0xf5, 0xd8, 0x1d, 0x05, 0xaf, 0x28, 0xba, 0x01, 0xc8, 0x51, 0x3b, 0x63, 0xc7, 0x66, - 0xee, 0x38, 0x88, 0xfc, 0x97, 0x84, 0x25, 0xf6, 0x58, 0x75, 0x52, 0xec, 0xd7, 0x6a, 0x1f, 0x5d, - 0x81, 0x95, 0x3c, 0xda, 0x39, 0x3a, 0x4a, 0x5a, 0x4e, 0x37, 0x83, 0x0e, 0x8e, 0x8e, 0xd0, 0x17, - 0xb0, 0x99, 0xc7, 0x91, 0x9f, 0x42, 0x8f, 0xa9, 0xf2, 0x38, 0x9e, 0x12, 0x9b, 0x25, 0xb6, 0xeb, - 0x67, 0x77, 0xf6, 0x52, 0xc0, 0x77, 0xc4, 0x66, 0xe8, 0x2e, 0x9c, 0xaf, 0xb8, 0xee, 0xd3, 0x40, - 0x4c, 0x94, 0xcb, 0x1b, 0xd6, 0xb9, 0x79, 0xf7, 0x1f, 0x49, 0x00, 0x9e, 0x42, 0x77, 0x30, 0xb1, - 0xd9, 0xeb, 0x34, 0xa7, 0x3f, 0x86, 0x25, 0xdb, 0x97, 0x11, 0x72, 0x8c, 0xf1, 0x12, 0x04, 0xba, - 0x03, 0x9d, 0x9c, 0xf6, 0xa4, 0x21, 0x6e, 0x16, 0x33, 0xa4, 0x60, 0x44, 0x0b, 0x32, 0x26, 0xf8, - 0x36, 0xf4, 0xb4, 0xea, 0xcc, 0xf5, 0x82, 0xd9, 0x01, 0xb7, 0x1d, 0xf5, 0x84, 0x34, 0x59, 0xba, - 0xb9, 0xdd, 0x91, 0x8b, 0x7f, 0x80, 0xb6, 0xca, 0x30, 0xd5, 0xf3, 0x75, 0x37, 0x36, 0x4e, 0xec, - 0xc6, 0x32, 0x2a, 0x64, 0x65, 0x48, 0x78, 0xce, 0x8d, 0x0a, 0x79, 0x8e, 0xdf, 0xd5, 0xa0, 0xa3, - 0x53, 0x38, 0x3a, 0x10, 0x32, 0x51, 0xa8, 0x5c, 0x66, 0x84, 0x9a, 0x6a, 0x3d, 0x72, 0xd1, 0x2d, - 0x58, 0xe7, 0x13, 0x2f, 0x0c, 0x65, 0x6e, 0xe7, 0x93, 0x3c, 0x8e, 0x26, 0xa4, 0xcf, 0x9e, 0xa6, - 0xc9, 0x8e, 0x6e, 0x43, 0x37, 0xbd, 0xa1, 0xd8, 0x2c, 0x56, 0xb2, 0x59, 0xd6, 0xc0, 0x01, 0xe5, - 0x02, 0xdd, 0x85, 0xd5, 0xf4, 0xa2, 0xae, 0x0d, 0xf5, 0x63, 0x2a, 0xd8, 0x8a, 0x46, 0xeb, 0x9a, - 0x71, 0x43, 0x57, 0xb2, 0x86, 0xaa, 0x64, 0x67, 0x0b, 0xb7, 0x52, 0x83, 0xea, 0x52, 0xe6, 0xc2, - 0xf9, 0x7d, 0x12, 0xb8, 0x6a, 0x7f, 0x40, 0x83, 0x57, 0x1e, 0xf3, 0x55, 0xd8, 0xe4, 0xda, 0x0d, - 0xf1, 0x6d, 0xef, 0x40, 0xb7, 0x1b, 0xb5, 0x40, 0x3b, 0xd0, 0x50, 0xa6, 0x49, 0x6c, 0xdc, 0x9f, - 0xd5, 0x11, 0xdb, 0xd4, 0x8a, 0x61, 0xf8, 0x9d, 0x01, 0x68, 0xc0, 0x88, 0x2d, 0x48, 0xa1, 0x48, - 0x57, 0x8e, 0x1a, 0xdb, 0xd0, 0x55, 0x07, 0xba, 0x16, 0x24, 0x86, 0x5e, 0x96, 0x9b, 0xba, 0x1c, - 0xe4, 0x4b, 0xfc, 0xe2, 0x29, 0x4a, 0x3c, 0xfe, 0x19, 0xce, 0x14, 0x38, 0x24, 0xd1, 0x98, 0xda, - 0xcb, 0x38, 0x85, 0xbd, 0x66, 0xfd, 0x5a, 0x3b, 0x9d, 0x5f, 0xf1, 0xdf, 0x06, 0xac, 0x3d, 0x39, - 0xb0, 0x9d, 0xff, 0xd1, 0x02, 0x99, 0x33, 0x1b, 0x79, 0x67, 0x96, 0xd2, 0x7b, 0xe9, 0xfd, 0xd2, - 0xfb, 0x3e, 0xa0, 0xfc, 0xb3, 0xd2, 0xa9, 0x23, 0x09, 0x10, 0xe3, 0x54, 0x01, 0xb2, 0xfb, 0x97, - 0x01, 0x1d, 0x99, 0xc6, 0xfb, 0x84, 0x1d, 0x79, 0x0e, 0x41, 0x77, 0x54, 0xab, 0x54, 0x99, 0xbf, - 0x59, 0x7e, 0x53, 0x6e, 0x7a, 0x37, 0x8b, 0x76, 0x8f, 0xc7, 0xdb, 0x05, 0xf4, 0x39, 0x34, 0x93, - 0x11, 0xbb, 0x74, 0xbb, 0x38, 0x78, 0x9b, 0x6b, 0x33, 0x65, 0x04, 0x2f, 0xa0, 0xaf, 0xa0, 0x9d, - 0x0e, 0xf3, 0xe8, 0xc2, 0xac, 0xfc, 0xbc, 0x80, 0xb9, 0xea, 0x77, 0x7f, 0x31, 0x60, 0xa3, 0x38, - 0x04, 0xeb, 0x67, 0xfd, 0x08, 0x67, 0xe6, 0x4c, 0xc8, 0xe8, 0xa3, 0x82, 0x98, 0xea, 0xd9, 0xdc, - 0xbc, 0x7a, 0x32, 0x30, 0x76, 0x80, 0x64, 0x51, 0x83, 0x8d, 0x64, 0xba, 0x1b, 0xd8, 0xc2, 0x3e, - 0xa0, 0xaf, 0x35, 0x8b, 0x21, 0x2c, 0xe7, 0x47, 0x59, 0x34, 0xe7, 0x15, 0xe6, 0x87, 0x33, 0x9a, - 0xca, 0x93, 0x25, 0x5e, 0x40, 0xf7, 0x01, 0xb2, 0x49, 0x16, 0x5d, 0x2c, 0x9b, 0xba, 0x38, 0xe2, - 0x9a, 0x73, 0x07, 0x4f, 0xbc, 0x80, 0x5e, 0x40, 0xaf, 0x38, 0xbb, 0x22, 0x5c, 0x40, 0xce, 0x9d, - 0x83, 0xcd, 0xed, 0x63, 0x31, 0xa9, 0x15, 0x7e, 0x37, 0x60, 0x65, 0x3f, 0xc9, 0x43, 0xfd, 0xfe, - 0x11, 0xb4, 0xf4, 0xc8, 0x89, 0xce, 0x97, 0x49, 0xe7, 0x27, 0x5f, 0xf3, 0x42, 0xc5, 0x69, 0x6a, - 0x81, 0x87, 0xd0, 0x4e, 0x27, 0xc1, 0x52, 0xb0, 0x94, 0x47, 0x52, 0xf3, 0x62, 0xd5, 0x71, 0x4a, - 0xf6, 0x4f, 0x03, 0x56, 0x74, 0x72, 0x6b, 0xb2, 0x2f, 0xe0, 0xec, 0xfc, 0x49, 0x6a, 0xae, 0xdb, - 0xae, 0x97, 0x09, 0x1f, 0x33, 0x82, 0xe1, 0x05, 0x34, 0x84, 0x66, 0x3c, 0x55, 0x09, 0x74, 0xa5, - 0x98, 0x0b, 0x55, 0x33, 0x97, 0x39, 0xa7, 0xd2, 0xe1, 0x85, 0xdd, 0x67, 0xd0, 0x7b, 0x62, 0x4f, - 0x7d, 0x12, 0xa4, 0x19, 0x3c, 0x80, 0xa5, 0xb8, 0xed, 0x23, 0xb3, 0x28, 0x39, 0x3f, 0x86, 0x98, - 0x9b, 0x73, 0xcf, 0x52, 0x83, 0x4c, 0x60, 0x79, 0x4f, 0xd6, 0x28, 0x2d, 0xf4, 0xb9, 0xfc, 0x55, - 0x34, 0xa7, 0x5b, 0xa1, 0x6b, 0xa5, 0x68, 0xa8, 0xee, 0x68, 0x15, 0x39, 0xfb, 0x87, 0x34, 0xfd, - 0x84, 0x38, 0x6f, 0x68, 0x94, 0x3e, 0xc1, 0x82, 0x4e, 0xae, 0x61, 0xa0, 0x4b, 0xe5, 0x92, 0x58, - 0x6a, 0x67, 0xe6, 0x56, 0x35, 0x20, 0xb5, 0xf8, 0x63, 0x80, 0xac, 0x5c, 0x96, 0x52, 0x66, 0xa6, - 0x3d, 0x98, 0x97, 0x2a, 0xcf, 0xb5, 0xc0, 0x97, 0x4b, 0xea, 0xcf, 0x92, 0x4f, 0xff, 0x0d, 0x00, - 0x00, 0xff, 0xff, 0x1d, 0x9c, 0xae, 0xb8, 0x3a, 0x11, 0x00, 0x00, +// AdServiceClient is the client API for AdService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type AdServiceClient interface { + GetAds(ctx context.Context, in *AdRequest, opts ...grpc.CallOption) (*AdResponse, error) +} + +type adServiceClient struct { + cc *grpc.ClientConn +} + +func NewAdServiceClient(cc *grpc.ClientConn) AdServiceClient { + return &adServiceClient{cc} +} + +func (c *adServiceClient) GetAds(ctx context.Context, in *AdRequest, opts ...grpc.CallOption) (*AdResponse, error) { + out := new(AdResponse) + err := c.cc.Invoke(ctx, "/hipstershop.AdService/GetAds", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AdServiceServer is the server API for AdService service. +type AdServiceServer interface { + GetAds(context.Context, *AdRequest) (*AdResponse, error) +} + +func RegisterAdServiceServer(s *grpc.Server, srv AdServiceServer) { + s.RegisterService(&_AdService_serviceDesc, srv) +} + +func _AdService_GetAds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdServiceServer).GetAds(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hipstershop.AdService/GetAds", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdServiceServer).GetAds(ctx, req.(*AdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _AdService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "hipstershop.AdService", + HandlerType: (*AdServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetAds", + Handler: _AdService_GetAds_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "demo.proto", +} + +func init() { proto.RegisterFile("demo.proto", fileDescriptor_ca53982754088a9d) } + +var fileDescriptor_ca53982754088a9d = []byte{ + // 1500 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xef, 0x72, 0x13, 0xb7, + 0x16, 0xcf, 0x26, 0xb1, 0x1d, 0x1f, 0xc7, 0x4e, 0xa2, 0x9b, 0x04, 0xb3, 0x81, 0x10, 0x94, 0x81, + 0x0b, 0x17, 0x08, 0x4c, 0xee, 0x9d, 0xe1, 0x03, 0xdc, 0xd2, 0x8c, 0xc9, 0x18, 0x4f, 0xa1, 0xd0, + 0x0d, 0xe9, 0xd0, 0xa1, 0x53, 0xcf, 0xb2, 0x12, 0xf1, 0x96, 0xec, 0x6a, 0x91, 0xb4, 0x19, 0xcc, + 0xc7, 0xf6, 0x01, 0xfa, 0x1e, 0x7d, 0x81, 0xce, 0xf4, 0x11, 0xfa, 0xbd, 0xaf, 0xd0, 0xe7, 0xe8, + 0x48, 0xbb, 0xda, 0x7f, 0xb1, 0x13, 0xf8, 0xd2, 0x6f, 0xab, 0xa3, 0x9f, 0xce, 0xf9, 0xe9, 0xe8, + 0xfc, 0xb3, 0x01, 0x08, 0x0d, 0xd8, 0x4e, 0xc4, 0x99, 0x64, 0xa8, 0x35, 0xf2, 0x23, 0x21, 0x29, + 0x17, 0x23, 0x16, 0xe1, 0x7d, 0x58, 0xe8, 0xb9, 0x5c, 0x0e, 0x24, 0x0d, 0xd0, 0x65, 0x80, 0x88, + 0x33, 0x12, 0x7b, 0x72, 0xe8, 0x93, 0xae, 0xb5, 0x65, 0xdd, 0x68, 0x3a, 0xcd, 0x54, 0x32, 0x20, + 0xc8, 0x86, 0x85, 0xf7, 0xb1, 0x1b, 0x4a, 0x5f, 0x8e, 0xbb, 0xb3, 0x5b, 0xd6, 0x8d, 0x9a, 0x93, + 0xad, 0xf1, 0x4b, 0xe8, 0xec, 0x11, 0xa2, 0xb4, 0x38, 0xf4, 0x7d, 0x4c, 0x85, 0x44, 0x17, 0xa0, + 0x11, 0x0b, 0xca, 0x73, 0x4d, 0x75, 0xb5, 0x1c, 0x10, 0x74, 0x13, 0xe6, 0x7d, 0x49, 0x03, 0xad, + 0xa2, 0xb5, 0xbb, 0xb6, 0x53, 0x60, 0xb3, 0x63, 0xa8, 0x38, 0x1a, 0x82, 0x6f, 0xc1, 0xf2, 0x7e, + 0x10, 0xc9, 0xb1, 0x12, 0x9f, 0xa7, 0x17, 0xdf, 0x84, 0x4e, 0x9f, 0xca, 0x4f, 0x82, 0x3e, 0x85, + 0x79, 0x85, 0x9b, 0xce, 0xf1, 0x16, 0xd4, 0x14, 0x01, 0xd1, 0x9d, 0xdd, 0x9a, 0x9b, 0x4e, 0x32, + 0xc1, 0xe0, 0x06, 0xd4, 0x34, 0x4b, 0xfc, 0x2d, 0xd8, 0x4f, 0x7d, 0x21, 0x1d, 0xea, 0xb1, 0x20, + 0xa0, 0x21, 0x71, 0xa5, 0xcf, 0x42, 0x71, 0xae, 0x43, 0xae, 0x40, 0x2b, 0x77, 0x7b, 0x62, 0xb2, + 0xe9, 0x40, 0xe6, 0x77, 0x81, 0xbf, 0x80, 0x8d, 0x89, 0x7a, 0x45, 0xc4, 0x42, 0x41, 0xab, 0xe7, + 0xad, 0x53, 0xe7, 0x7f, 0xb7, 0xa0, 0xf1, 0x22, 0x59, 0xa2, 0x0e, 0xcc, 0x66, 0x04, 0x66, 0x7d, + 0x82, 0x10, 0xcc, 0x87, 0x6e, 0x40, 0xf5, 0x6b, 0x34, 0x1d, 0xfd, 0x8d, 0xb6, 0xa0, 0x45, 0xa8, + 0xf0, 0xb8, 0x1f, 0x29, 0x43, 0xdd, 0x39, 0xbd, 0x55, 0x14, 0xa1, 0x2e, 0x34, 0x22, 0xdf, 0x93, + 0x31, 0xa7, 0xdd, 0x79, 0xbd, 0x6b, 0x96, 0xe8, 0x2e, 0x34, 0x23, 0xee, 0x7b, 0x74, 0x18, 0x0b, + 0xd2, 0xad, 0xe9, 0x27, 0x46, 0x25, 0xef, 0x3d, 0x63, 0x21, 0x1d, 0x3b, 0x0b, 0x1a, 0x74, 0x28, + 0x08, 0xda, 0x04, 0xf0, 0x5c, 0x49, 0x8f, 0x18, 0xf7, 0xa9, 0xe8, 0xd6, 0x13, 0xf2, 0xb9, 0x04, + 0x3f, 0x81, 0x55, 0x75, 0xf9, 0x94, 0x7f, 0x7e, 0xeb, 0x7b, 0xb0, 0x90, 0x5e, 0x31, 0xb9, 0x72, + 0x6b, 0x77, 0xb5, 0x64, 0x27, 0x3d, 0xe0, 0x64, 0x28, 0xbc, 0x0d, 0x2b, 0x7d, 0x6a, 0x14, 0x99, + 0x57, 0xa9, 0xf8, 0x03, 0xdf, 0x81, 0xb5, 0x03, 0xea, 0x72, 0x6f, 0x94, 0x1b, 0x4c, 0x80, 0xab, + 0x50, 0x7b, 0x1f, 0x53, 0x3e, 0x4e, 0xb1, 0xc9, 0x02, 0x3f, 0x81, 0xf5, 0x2a, 0x3c, 0xe5, 0xb7, + 0x03, 0x0d, 0x4e, 0x45, 0x7c, 0x7c, 0x0e, 0x3d, 0x03, 0xc2, 0x21, 0x2c, 0xf5, 0xa9, 0xfc, 0x26, + 0x66, 0x92, 0x1a, 0x93, 0x3b, 0xd0, 0x70, 0x09, 0xe1, 0x54, 0x08, 0x6d, 0xb4, 0xaa, 0x62, 0x2f, + 0xd9, 0x73, 0x0c, 0xe8, 0xf3, 0xa2, 0x76, 0x0f, 0x96, 0x73, 0x7b, 0x29, 0xe7, 0x3b, 0xb0, 0xe0, + 0x31, 0x21, 0xf5, 0xdb, 0x59, 0x53, 0xdf, 0xae, 0xa1, 0x30, 0x87, 0x82, 0x60, 0x06, 0xcb, 0x07, + 0x23, 0x3f, 0x7a, 0xce, 0x09, 0xe5, 0xff, 0x08, 0xe7, 0xff, 0xc1, 0x4a, 0xc1, 0x60, 0x1e, 0xfe, + 0x92, 0xbb, 0xde, 0x3b, 0x3f, 0x3c, 0xca, 0x73, 0x0b, 0x8c, 0x68, 0x40, 0xf0, 0x2f, 0x16, 0x34, + 0x52, 0xbb, 0xe8, 0x1a, 0x74, 0x84, 0xe4, 0x94, 0xca, 0x61, 0x91, 0x65, 0xd3, 0x69, 0x27, 0x52, + 0x03, 0x43, 0x30, 0xef, 0x99, 0x32, 0xd7, 0x74, 0xf4, 0xb7, 0x0a, 0x00, 0x21, 0x5d, 0x49, 0xd3, + 0x7c, 0x48, 0x16, 0x2a, 0x13, 0x3c, 0x16, 0x87, 0x92, 0x8f, 0x4d, 0x26, 0xa4, 0x4b, 0x74, 0x11, + 0x16, 0x3e, 0xfa, 0xd1, 0xd0, 0x63, 0x84, 0xea, 0x44, 0xa8, 0x39, 0x8d, 0x8f, 0x7e, 0xd4, 0x63, + 0x84, 0xe2, 0x57, 0x50, 0xd3, 0xae, 0x44, 0xdb, 0xd0, 0xf6, 0x62, 0xce, 0x69, 0xe8, 0x8d, 0x13, + 0x60, 0xc2, 0x66, 0xd1, 0x08, 0x15, 0x5a, 0x19, 0x8e, 0x43, 0x5f, 0x0a, 0xcd, 0x66, 0xce, 0x49, + 0x16, 0x4a, 0x1a, 0xba, 0x21, 0x13, 0x9a, 0x4e, 0xcd, 0x49, 0x16, 0xb8, 0x0f, 0x9b, 0x7d, 0x2a, + 0x0f, 0xe2, 0x28, 0x62, 0x5c, 0x52, 0xd2, 0x4b, 0xf4, 0xf8, 0x34, 0x8f, 0xcb, 0x6b, 0xd0, 0x29, + 0x99, 0x34, 0x05, 0xa3, 0x5d, 0xb4, 0x29, 0xf0, 0xf7, 0x70, 0xb1, 0x97, 0x09, 0xc2, 0x13, 0xca, + 0x85, 0xcf, 0x42, 0xf3, 0xc8, 0xd7, 0x61, 0xfe, 0x2d, 0x67, 0xc1, 0x19, 0x31, 0xa2, 0xf7, 0x55, + 0xc9, 0x93, 0x2c, 0xb9, 0x58, 0xe2, 0xc9, 0xba, 0x64, 0xda, 0x01, 0x7f, 0x59, 0xd0, 0xe9, 0x71, + 0x4a, 0x7c, 0x55, 0xaf, 0xc9, 0x20, 0x7c, 0xcb, 0xd0, 0x6d, 0x40, 0x9e, 0x96, 0x0c, 0x3d, 0x97, + 0x93, 0x61, 0x18, 0x07, 0x6f, 0x28, 0x4f, 0xfd, 0xb1, 0xec, 0x65, 0xd8, 0xaf, 0xb5, 0x1c, 0x5d, + 0x87, 0xa5, 0x22, 0xda, 0x3b, 0x39, 0x49, 0x5b, 0x52, 0x3b, 0x87, 0xf6, 0x4e, 0x4e, 0xd0, 0xff, + 0x61, 0xa3, 0x88, 0xa3, 0x1f, 0x22, 0x9f, 0xeb, 0xf2, 0x39, 0x1c, 0x53, 0x97, 0xa7, 0xbe, 0xeb, + 0xe6, 0x67, 0xf6, 0x33, 0xc0, 0x77, 0xd4, 0xe5, 0xe8, 0x11, 0x5c, 0x9a, 0x72, 0x3c, 0x60, 0xa1, + 0x1c, 0xe9, 0x27, 0xaf, 0x39, 0x17, 0x27, 0x9d, 0x7f, 0xa6, 0x00, 0x78, 0x0c, 0xed, 0xde, 0xc8, + 0xe5, 0x47, 0x59, 0x4e, 0xff, 0x07, 0xea, 0x6e, 0xa0, 0x22, 0xe4, 0x0c, 0xe7, 0xa5, 0x08, 0xf4, + 0x10, 0x5a, 0x05, 0xeb, 0x69, 0xc3, 0xdc, 0x28, 0x67, 0x48, 0xc9, 0x89, 0x0e, 0xe4, 0x4c, 0xf0, + 0x7d, 0xe8, 0x18, 0xd3, 0xf9, 0xd3, 0x4b, 0xee, 0x86, 0xc2, 0xf5, 0xf4, 0x15, 0xb2, 0x64, 0x69, + 0x17, 0xa4, 0x03, 0x82, 0x7f, 0x80, 0xa6, 0xce, 0x30, 0x3d, 0x13, 0x98, 0x6e, 0x6d, 0x9d, 0xdb, + 0xad, 0x55, 0x54, 0xa8, 0xca, 0x90, 0xf2, 0x9c, 0x18, 0x15, 0x6a, 0x1f, 0xff, 0x34, 0x0b, 0x2d, + 0x93, 0xc2, 0xf1, 0xb1, 0x54, 0x89, 0xc2, 0xd4, 0x32, 0x27, 0xd4, 0xd0, 0xeb, 0x01, 0x41, 0xf7, + 0x60, 0x55, 0x8c, 0xfc, 0x28, 0x52, 0xb9, 0x5d, 0x4c, 0xf2, 0x24, 0x9a, 0x90, 0xd9, 0x7b, 0x99, + 0x25, 0x3b, 0xba, 0x0f, 0xed, 0xec, 0x84, 0x66, 0x33, 0x37, 0x95, 0xcd, 0xa2, 0x01, 0xf6, 0x98, + 0x90, 0xe8, 0x11, 0x2c, 0x67, 0x07, 0x4d, 0x6d, 0x98, 0x3f, 0xa3, 0x82, 0x2d, 0x19, 0xb4, 0xa9, + 0x19, 0xb7, 0x4d, 0x25, 0xab, 0xe9, 0x4a, 0xb6, 0x5e, 0x3a, 0x95, 0x39, 0xd4, 0x94, 0x32, 0x02, + 0x97, 0x0e, 0x68, 0x48, 0xb4, 0xbc, 0xc7, 0xc2, 0xb7, 0x3e, 0x0f, 0x74, 0xd8, 0x14, 0xda, 0x0d, + 0x0d, 0x5c, 0xff, 0xd8, 0xb4, 0x1b, 0xbd, 0x40, 0x3b, 0x50, 0xd3, 0xae, 0x49, 0x7d, 0xdc, 0x3d, + 0x6d, 0x23, 0xf1, 0xa9, 0x93, 0xc0, 0xf0, 0x9f, 0x16, 0xac, 0xbc, 0x38, 0x76, 0x3d, 0x5a, 0xaa, + 0xd1, 0x53, 0x27, 0x91, 0x6d, 0x68, 0xeb, 0x0d, 0x53, 0x0a, 0x52, 0x3f, 0x2f, 0x2a, 0xa1, 0xa9, + 0x06, 0xc5, 0x0a, 0x3f, 0xf7, 0x29, 0x15, 0x3e, 0xbb, 0x49, 0xad, 0x78, 0x93, 0x4a, 0x6c, 0xd7, + 0x3f, 0x2f, 0xb6, 0x1f, 0x03, 0x2a, 0x5e, 0x2b, 0x6b, 0xb9, 0xa9, 0x77, 0xac, 0x4f, 0xf3, 0xce, + 0x0e, 0x34, 0xf7, 0x88, 0x71, 0xca, 0x55, 0x58, 0xf4, 0x58, 0x28, 0xe9, 0x07, 0x39, 0x7c, 0x47, + 0xc7, 0xa6, 0x2a, 0xb6, 0x52, 0xd9, 0x57, 0x74, 0x2c, 0xf0, 0x5d, 0x00, 0x85, 0x4f, 0xad, 0x5d, + 0x85, 0x39, 0x97, 0x98, 0xe6, 0xbe, 0x54, 0xf1, 0x81, 0xa3, 0xf6, 0xf0, 0x03, 0x98, 0xdd, 0x23, + 0x4a, 0xb3, 0x62, 0xce, 0xa9, 0x27, 0x87, 0x31, 0x37, 0x2f, 0xda, 0x32, 0xb2, 0x43, 0x7e, 0xac, + 0xfa, 0x8d, 0xb2, 0x62, 0xfa, 0x8d, 0xfa, 0xde, 0xfd, 0xc3, 0x82, 0x96, 0xca, 0xb0, 0x03, 0xca, + 0x4f, 0x7c, 0x8f, 0xa2, 0x87, 0xba, 0x8b, 0xe9, 0xa4, 0xdc, 0xa8, 0x7a, 0xbc, 0x30, 0x78, 0xdb, + 0xe5, 0x50, 0x4f, 0x26, 0xd3, 0x19, 0xf4, 0x00, 0x1a, 0xe9, 0x74, 0x5c, 0x39, 0x5d, 0x9e, 0x99, + 0xed, 0x95, 0x53, 0x19, 0x8e, 0x67, 0xd0, 0x97, 0xd0, 0xcc, 0xe6, 0x70, 0x74, 0xf9, 0xb4, 0xfe, + 0xa2, 0x82, 0x89, 0xe6, 0x77, 0x7f, 0xb6, 0x60, 0xad, 0x3c, 0xbf, 0x9a, 0x6b, 0xfd, 0x08, 0xff, + 0x9a, 0x30, 0xdc, 0xa2, 0x7f, 0x97, 0xd4, 0x4c, 0x1f, 0xab, 0xed, 0x1b, 0xe7, 0x03, 0x93, 0x07, + 0x53, 0x2c, 0x66, 0x61, 0x2d, 0x1d, 0xbc, 0x7a, 0xae, 0x74, 0x8f, 0xd9, 0x91, 0x61, 0xd1, 0x87, + 0xc5, 0xe2, 0x94, 0x89, 0x26, 0xdc, 0xc2, 0xbe, 0x7a, 0xca, 0x52, 0x75, 0xe8, 0xc3, 0x33, 0xe8, + 0x31, 0x40, 0x3e, 0x64, 0xa2, 0xcd, 0xaa, 0xab, 0xcb, 0xd3, 0xa7, 0x3d, 0x71, 0x26, 0xc4, 0x33, + 0xe8, 0x35, 0x74, 0xca, 0x63, 0x25, 0xc2, 0x25, 0xe4, 0xc4, 0x11, 0xd5, 0xde, 0x3e, 0x13, 0x93, + 0x79, 0xe1, 0x57, 0x0b, 0x96, 0x0e, 0xd2, 0xe2, 0x65, 0xee, 0x3f, 0x80, 0x05, 0x33, 0x0d, 0xa2, + 0x4b, 0x55, 0xd2, 0xc5, 0xa1, 0xd4, 0xbe, 0x3c, 0x65, 0x37, 0xf3, 0xc0, 0x53, 0x68, 0x66, 0x43, + 0x5a, 0x25, 0x58, 0xaa, 0xd3, 0xa2, 0xbd, 0x39, 0x6d, 0x3b, 0x23, 0xfb, 0x9b, 0x05, 0x4b, 0xa6, + 0xf4, 0x18, 0xb2, 0xaf, 0x61, 0x7d, 0xf2, 0x90, 0x33, 0xf1, 0xd9, 0x6e, 0x55, 0x09, 0x9f, 0x31, + 0x1d, 0xe1, 0x19, 0xd4, 0x87, 0x46, 0x32, 0xf0, 0x48, 0x74, 0xbd, 0x9c, 0x0b, 0xd3, 0xc6, 0x21, + 0x7b, 0x42, 0x73, 0xc1, 0x33, 0xbb, 0x87, 0xd0, 0x79, 0xe1, 0x8e, 0x03, 0x1a, 0x66, 0x19, 0xdc, + 0x83, 0x7a, 0xd2, 0x91, 0x91, 0x5d, 0xd6, 0x5c, 0x9c, 0x10, 0xec, 0x8d, 0x89, 0x7b, 0x99, 0x43, + 0x46, 0xb0, 0xb8, 0xaf, 0x2a, 0xa8, 0x51, 0xfa, 0x4a, 0xfd, 0x60, 0x99, 0xd0, 0x48, 0xd0, 0xcd, + 0x4a, 0x34, 0x4c, 0x6f, 0x36, 0x53, 0x72, 0xf6, 0x0d, 0x2c, 0xf5, 0x46, 0xd4, 0x7b, 0xc7, 0xe2, + 0xec, 0x06, 0xcf, 0x01, 0xf2, 0xba, 0x5b, 0x89, 0xee, 0x53, 0x7d, 0xc6, 0xbe, 0x32, 0x75, 0x3f, + 0xbb, 0xcd, 0x13, 0x55, 0x82, 0x8d, 0xf6, 0x07, 0x50, 0xef, 0xab, 0x19, 0x5c, 0xa0, 0xf5, 0x6a, + 0x39, 0x4d, 0x35, 0x5e, 0x38, 0x25, 0x37, 0x9a, 0xde, 0xd4, 0xf5, 0x9f, 0x1b, 0xff, 0xfd, 0x3b, + 0x00, 0x00, 0xff, 0xff, 0xb2, 0xa0, 0x6e, 0x6c, 0xea, 0x10, 0x00, 0x00, } From 848d4bbe90cde76fa112bf5a91c90ae7a641fbe3 Mon Sep 17 00:00:00 2001 From: sebright Date: Mon, 1 Oct 2018 22:45:09 -0700 Subject: [PATCH 12/91] adservice: enable structured logging and OpenCensus log correlation (#59) This commit enables OpenCensus log correlation using opencensus-contrib-log-correlation-log4j2 (https://github.com/census-instrumentation/opencensus-java/tree/master/contrib/log_correlation/log4j2). The library inserts the trace ID, span ID, and sampling decision into every Log4j log event. This commit includes other changes to make the tracing data available in the logs, in a format that can be interpreted by the Stackdriver Logging agent: - Convert all adservice log statements from java.util.logging to Log4j. - Specify a JSON format for Log4j output. This is related to issue #47. - Add the trace ID, span ID, and sampling decision to the JSON format. Trace ID and span ID use special keys that the Stackdriver Logging agent uses to populate the tracing data fields in the LogEntry uploaded to Stackdriver (https://cloud.google.com/logging/docs/agent/configuration#special_fields_in_structured_payloads). However, Stackdriver won't be able to link the traces and log entries until fluent-plugin-google-cloud can automatically format the trace ID with the format expected by Stackdriver (https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud/issues/239, https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud/pull/260). This commit also upgrades OpenCensus to 0.16.1 in order to use opencensus-contrib-log-correlation-log4j2. --- src/adservice/build.gradle | 15 +++++++++--- .../src/main/java/hipstershop/AdService.java | 13 +++++----- .../java/hipstershop/AdServiceClient.java | 15 ++++++------ src/adservice/src/main/resources/log4j2.xml | 24 +++++++++++++++++++ 4 files changed, 51 insertions(+), 16 deletions(-) create mode 100644 src/adservice/src/main/resources/log4j2.xml diff --git a/src/adservice/build.gradle b/src/adservice/build.gradle index 2c6bce7..11e1be4 100644 --- a/src/adservice/build.gradle +++ b/src/adservice/build.gradle @@ -25,8 +25,9 @@ repositories { group = "adservice" version = "0.1.0-SNAPSHOT" // CURRENT_OPENCENSUS_VERSION -def opencensusVersion = "0.15.0" // LATEST_OPENCENSUS_RELEASE_VERSION +def opencensusVersion = "0.16.1" // LATEST_OPENCENSUS_RELEASE_VERSION def grpcVersion = "1.15.0" // CURRENT_GRPC_VERSION +def jacksonVersion = "2.9.6" def prometheusVersion = "0.3.0" tasks.withType(JavaCompile) { @@ -52,9 +53,13 @@ dependencies { "io.grpc:grpc-stub:${grpcVersion}", "io.grpc:grpc-netty:${grpcVersion}", "io.grpc:grpc-services:${grpcVersion}", - "io.prometheus:simpleclient_httpserver:${prometheusVersion}" + "io.prometheus:simpleclient_httpserver:${prometheusVersion}", + "org.apache.logging.log4j:log4j-core:2.11.1" - runtime "io.opencensus:opencensus-impl:${opencensusVersion}", + runtime "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}", + "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}", + "io.opencensus:opencensus-contrib-log-correlation-log4j2:${opencensusVersion}", + "io.opencensus:opencensus-impl:${opencensusVersion}", "io.netty:netty-tcnative-boringssl-static:2.0.8.Final" } } @@ -106,6 +111,8 @@ task adService(type: CreateStartScripts) { applicationName = 'AdService' outputDir = new File(project.buildDir, 'tmp') classpath = jar.outputs.files + project.configurations.runtime + defaultJvmOpts = + ["-Dlog4j2.contextDataInjector=io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector"] } task adServiceClient(type: CreateStartScripts) { @@ -113,6 +120,8 @@ task adServiceClient(type: CreateStartScripts) { applicationName = 'AdServiceClient' outputDir = new File(project.buildDir, 'tmp') classpath = jar.outputs.files + project.configurations.runtime + defaultJvmOpts = + ["-Dlog4j2.contextDataInjector=io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector"] } applicationDistribution.into('bin') { diff --git a/src/adservice/src/main/java/hipstershop/AdService.java b/src/adservice/src/main/java/hipstershop/AdService.java index dfb1e40..9ba3329 100644 --- a/src/adservice/src/main/java/hipstershop/AdService.java +++ b/src/adservice/src/main/java/hipstershop/AdService.java @@ -50,11 +50,12 @@ import java.util.HashMap; import java.util.List; import java.util.Random; import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; public class AdService { - private static final Logger logger = Logger.getLogger(AdService.class.getName()); + private static final Logger logger = LogManager.getLogger(AdService.class); private static final Tracer tracer = Tracing.getTracer(); @@ -139,7 +140,7 @@ public class AdService { responseObserver.onNext(reply); responseObserver.onCompleted(); } catch (StatusRuntimeException e) { - logger.log(Level.WARNING, "GetAds Failed", e.getStatus()); + logger.log(Level.WARN, "GetAds Failed", e.getStatus()); return; } } @@ -218,7 +219,7 @@ public class AdService { .build()); } catch (Exception e) { if (i==(maxAttempts-1)) { - logger.log(Level.WARNING, "Failed to register Stackdriver Exporter." + + logger.log(Level.WARN, "Failed to register Stackdriver Exporter." + " Tracing and Stats data will not reported to Stackdriver. Error message: " + e .toString()); } else { @@ -226,7 +227,7 @@ public class AdService { try { Thread.sleep(TimeUnit.SECONDS.toMillis(sleepTime)); } catch (Exception se) { - logger.log(Level.WARNING, "Exception while sleeping" + se.toString()); + logger.log(Level.WARN, "Exception while sleeping" + se.toString()); } } } diff --git a/src/adservice/src/main/java/hipstershop/AdServiceClient.java b/src/adservice/src/main/java/hipstershop/AdServiceClient.java index df6df07..a269a4c 100644 --- a/src/adservice/src/main/java/hipstershop/AdServiceClient.java +++ b/src/adservice/src/main/java/hipstershop/AdServiceClient.java @@ -38,13 +38,14 @@ import io.opencensus.trace.Tracing; import io.opencensus.trace.samplers.Samplers; import java.io.IOException; import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.annotation.Nullable; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; /** A simple client that requests ads from the Ads Service. */ public class AdServiceClient { - private static final Logger logger = Logger.getLogger(AdServiceClient.class.getName()); + private static final Logger logger = LogManager.getLogger(AdServiceClient.class); private static final Tracer tracer = Tracing.getTracer(); @@ -90,7 +91,7 @@ public class AdServiceClient { CanonicalCode.valueOf(e.getStatus().getCode().name()) .toStatus() .withDescription(e.getMessage())); - logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); + logger.log(Level.WARN, "RPC failed: {0}", e.getStatus()); return; } for(Ad ads: response.getAdsList()) { @@ -104,7 +105,7 @@ public class AdServiceClient { try { portNumber = Integer.parseInt(args[index]); } catch (NumberFormatException e) { - logger.warning( + logger.warn( String.format("Port %s is invalid, use default port %d.", args[index], defaultPort)); } } @@ -156,7 +157,7 @@ public class AdServiceClient { .build()); } catch (Exception e) { if (i==(maxAttempts-1)) { - logger.log(Level.WARNING, "Failed to register Stackdriver Exporter." + + logger.log(Level.WARN, "Failed to register Stackdriver Exporter." + " Tracing and Stats data will not reported to Stackdriver. Error message: " + e .toString()); } else { @@ -164,7 +165,7 @@ public class AdServiceClient { try { Thread.sleep(TimeUnit.SECONDS.toMillis(sleepTime)); } catch (Exception se) { - logger.log(Level.WARNING, "Exception while sleeping" + e.toString()); + logger.log(Level.WARN, "Exception while sleeping" + e.toString()); } } } diff --git a/src/adservice/src/main/resources/log4j2.xml b/src/adservice/src/main/resources/log4j2.xml new file mode 100644 index 0000000..f050ded --- /dev/null +++ b/src/adservice/src/main/resources/log4j2.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + From 2771a0372739789ede12f419c8b6fc10829ae4a9 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Mon, 1 Oct 2018 23:20:42 -0700 Subject: [PATCH 13/91] k8s: start using grpc health check for cartservice (#63) --- kubernetes-manifests/cartservice.yaml | 4 +- kubernetes-manifests/frontend.yaml | 2 +- src/cartservice/Dockerfile | 19 +- src/cartservice/probe/.dockerignore | 1 - src/cartservice/probe/Gopkg.lock | 101 - src/cartservice/probe/Gopkg.toml | 42 - src/cartservice/probe/README.md | 4 - src/cartservice/probe/genproto.sh | 22 - src/cartservice/probe/genproto/demo.pb.go | 2464 --------------------- src/cartservice/probe/main.go | 51 - 10 files changed, 9 insertions(+), 2701 deletions(-) delete mode 100644 src/cartservice/probe/.dockerignore delete mode 100644 src/cartservice/probe/Gopkg.lock delete mode 100644 src/cartservice/probe/Gopkg.toml delete mode 100644 src/cartservice/probe/README.md delete mode 100755 src/cartservice/probe/genproto.sh delete mode 100644 src/cartservice/probe/genproto/demo.pb.go delete mode 100644 src/cartservice/probe/main.go diff --git a/kubernetes-manifests/cartservice.yaml b/kubernetes-manifests/cartservice.yaml index 178b8dd..55aa5be 100644 --- a/kubernetes-manifests/cartservice.yaml +++ b/kubernetes-manifests/cartservice.yaml @@ -45,12 +45,12 @@ spec: readinessProbe: initialDelaySeconds: 15 exec: - command: ["/cartservice_probe"] + command: ["/bin/grpc_health_probe", "-addr=:7070"] livenessProbe: initialDelaySeconds: 15 periodSeconds: 10 exec: - command: ["/cartservice_probe"] + command: ["/bin/grpc_health_probe", "-addr=:7070"] --- apiVersion: v1 kind: Service diff --git a/kubernetes-manifests/frontend.yaml b/kubernetes-manifests/frontend.yaml index d921a8f..27d1b8e 100644 --- a/kubernetes-manifests/frontend.yaml +++ b/kubernetes-manifests/frontend.yaml @@ -38,7 +38,7 @@ spec: livenessProbe: initialDelaySeconds: 10 httpGet: - path: "/" + path: "/_healthz" port: 8080 httpHeaders: - name: "Cookie" diff --git a/src/cartservice/Dockerfile b/src/cartservice/Dockerfile index ae28b24..eae7f06 100644 --- a/src/cartservice/Dockerfile +++ b/src/cartservice/Dockerfile @@ -1,13 +1,3 @@ -FROM golang:1.10 as probe -RUN wget -qO/go/bin/dep https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 && \ - chmod +x /go/bin/dep -ENV PROJECT github.com/GoogleCloudPlatform/microservices-demo/src/cartservice/probe -WORKDIR /go/src/$PROJECT -COPY probe/Gopkg.* ./ -RUN dep ensure --vendor-only -v -COPY ./probe ./ -RUN go build -o /cartservice_probe . - FROM microsoft/dotnet:2.1-sdk-alpine as builder WORKDIR /app COPY . . @@ -17,8 +7,11 @@ RUN dotnet restore && \ # cartservice FROM alpine:3.8 -# Add the probe -COPY --from=probe /cartservice_probe /cartservice_probe + +RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ + wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ + chmod +x /bin/grpc_health_probe + # Dependencies for runtime # busybox-extras => telnet RUN apk add --no-cache \ @@ -32,4 +25,4 @@ RUN apk add --no-cache \ icu WORKDIR /app COPY --from=builder /cartservice . -ENTRYPOINT ["./cartservice", "start"] \ No newline at end of file +ENTRYPOINT ["./cartservice", "start"] diff --git a/src/cartservice/probe/.dockerignore b/src/cartservice/probe/.dockerignore deleted file mode 100644 index 48b8bf9..0000000 --- a/src/cartservice/probe/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -vendor/ diff --git a/src/cartservice/probe/Gopkg.lock b/src/cartservice/probe/Gopkg.lock deleted file mode 100644 index 20ec989..0000000 --- a/src/cartservice/probe/Gopkg.lock +++ /dev/null @@ -1,101 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - name = "github.com/golang/protobuf" - packages = [ - "proto", - "ptypes", - "ptypes/any", - "ptypes/duration", - "ptypes/timestamp" - ] - revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" - version = "v1.1.0" - -[[projects]] - branch = "master" - name = "golang.org/x/net" - packages = [ - "context", - "http/httpguts", - "http2", - "http2/hpack", - "idna", - "internal/timeseries", - "trace" - ] - revision = "f4c29de78a2a91c00474a2e689954305c350adf9" - -[[projects]] - branch = "master" - name = "golang.org/x/sys" - packages = ["unix"] - revision = "0ffbfd41fbef8ffcf9b62b0b0aa3a5873ed7a4fe" - -[[projects]] - name = "golang.org/x/text" - packages = [ - "collate", - "collate/build", - "internal/colltab", - "internal/gen", - "internal/tag", - "internal/triegen", - "internal/ucd", - "language", - "secure/bidirule", - "transform", - "unicode/bidi", - "unicode/cldr", - "unicode/norm", - "unicode/rangetable" - ] - revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" - version = "v0.3.0" - -[[projects]] - branch = "master" - name = "google.golang.org/genproto" - packages = ["googleapis/rpc/status"] - revision = "daca94659cb50e9f37c1b834680f2e46358f10b0" - -[[projects]] - name = "google.golang.org/grpc" - packages = [ - ".", - "balancer", - "balancer/base", - "balancer/roundrobin", - "codes", - "connectivity", - "credentials", - "encoding", - "encoding/proto", - "grpclog", - "internal", - "internal/backoff", - "internal/channelz", - "internal/envconfig", - "internal/grpcrand", - "internal/transport", - "keepalive", - "metadata", - "naming", - "peer", - "resolver", - "resolver/dns", - "resolver/passthrough", - "stats", - "status", - "tap" - ] - revision = "32fb0ac620c32ba40a4626ddf94d90d12cce3455" - version = "v1.14.0" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - inputs-digest = "8f3c07df5ebc7dc4d50ca8a6c274eef95f3045d33bbe5f384271fa87166a457e" - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/src/cartservice/probe/Gopkg.toml b/src/cartservice/probe/Gopkg.toml deleted file mode 100644 index e0c6765..0000000 --- a/src/cartservice/probe/Gopkg.toml +++ /dev/null @@ -1,42 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" -# -# [prune] -# non-go = false -# go-tests = true -# unused-packages = true - - -[[constraint]] - name = "github.com/golang/protobuf" - version = "1.1.0" - -[[constraint]] - branch = "master" - name = "golang.org/x/net" - -[[constraint]] - name = "google.golang.org/grpc" - version = "1.14.0" - -[prune] - go-tests = true - unused-packages = true diff --git a/src/cartservice/probe/README.md b/src/cartservice/probe/README.md deleted file mode 100644 index e20cf50..0000000 --- a/src/cartservice/probe/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# cartservice Probe - -This probe makes a call to the cartservice over localhost and exits to verify -liveness of the cartservice. diff --git a/src/cartservice/probe/genproto.sh b/src/cartservice/probe/genproto.sh deleted file mode 100755 index 8013609..0000000 --- a/src/cartservice/probe/genproto.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -eu -# -# Copyright 2018 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -#!/bin/bash -e - -PATH=$PATH:$GOPATH/bin -protodir=../../../pb - -protoc --go_out=plugins=grpc:genproto -I $protodir $protodir/demo.proto diff --git a/src/cartservice/probe/genproto/demo.pb.go b/src/cartservice/probe/genproto/demo.pb.go deleted file mode 100644 index f59af20..0000000 --- a/src/cartservice/probe/genproto/demo.pb.go +++ /dev/null @@ -1,2464 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: demo.proto - -package hipstershop - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -import ( - context "golang.org/x/net/context" - grpc "google.golang.org/grpc" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -type CartItem struct { - ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` - Quantity int32 `protobuf:"varint,2,opt,name=quantity,proto3" json:"quantity,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *CartItem) Reset() { *m = CartItem{} } -func (m *CartItem) String() string { return proto.CompactTextString(m) } -func (*CartItem) ProtoMessage() {} -func (*CartItem) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{0} -} - -func (m *CartItem) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_CartItem.Unmarshal(m, b) -} -func (m *CartItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_CartItem.Marshal(b, m, deterministic) -} -func (m *CartItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_CartItem.Merge(m, src) -} -func (m *CartItem) XXX_Size() int { - return xxx_messageInfo_CartItem.Size(m) -} -func (m *CartItem) XXX_DiscardUnknown() { - xxx_messageInfo_CartItem.DiscardUnknown(m) -} - -var xxx_messageInfo_CartItem proto.InternalMessageInfo - -func (m *CartItem) GetProductId() string { - if m != nil { - return m.ProductId - } - return "" -} - -func (m *CartItem) GetQuantity() int32 { - if m != nil { - return m.Quantity - } - return 0 -} - -type AddItemRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - Item *CartItem `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *AddItemRequest) Reset() { *m = AddItemRequest{} } -func (m *AddItemRequest) String() string { return proto.CompactTextString(m) } -func (*AddItemRequest) ProtoMessage() {} -func (*AddItemRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{1} -} - -func (m *AddItemRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_AddItemRequest.Unmarshal(m, b) -} -func (m *AddItemRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_AddItemRequest.Marshal(b, m, deterministic) -} -func (m *AddItemRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_AddItemRequest.Merge(m, src) -} -func (m *AddItemRequest) XXX_Size() int { - return xxx_messageInfo_AddItemRequest.Size(m) -} -func (m *AddItemRequest) XXX_DiscardUnknown() { - xxx_messageInfo_AddItemRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_AddItemRequest proto.InternalMessageInfo - -func (m *AddItemRequest) GetUserId() string { - if m != nil { - return m.UserId - } - return "" -} - -func (m *AddItemRequest) GetItem() *CartItem { - if m != nil { - return m.Item - } - return nil -} - -type EmptyCartRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *EmptyCartRequest) Reset() { *m = EmptyCartRequest{} } -func (m *EmptyCartRequest) String() string { return proto.CompactTextString(m) } -func (*EmptyCartRequest) ProtoMessage() {} -func (*EmptyCartRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{2} -} - -func (m *EmptyCartRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EmptyCartRequest.Unmarshal(m, b) -} -func (m *EmptyCartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EmptyCartRequest.Marshal(b, m, deterministic) -} -func (m *EmptyCartRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_EmptyCartRequest.Merge(m, src) -} -func (m *EmptyCartRequest) XXX_Size() int { - return xxx_messageInfo_EmptyCartRequest.Size(m) -} -func (m *EmptyCartRequest) XXX_DiscardUnknown() { - xxx_messageInfo_EmptyCartRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_EmptyCartRequest proto.InternalMessageInfo - -func (m *EmptyCartRequest) GetUserId() string { - if m != nil { - return m.UserId - } - return "" -} - -type GetCartRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetCartRequest) Reset() { *m = GetCartRequest{} } -func (m *GetCartRequest) String() string { return proto.CompactTextString(m) } -func (*GetCartRequest) ProtoMessage() {} -func (*GetCartRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{3} -} - -func (m *GetCartRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetCartRequest.Unmarshal(m, b) -} -func (m *GetCartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetCartRequest.Marshal(b, m, deterministic) -} -func (m *GetCartRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetCartRequest.Merge(m, src) -} -func (m *GetCartRequest) XXX_Size() int { - return xxx_messageInfo_GetCartRequest.Size(m) -} -func (m *GetCartRequest) XXX_DiscardUnknown() { - xxx_messageInfo_GetCartRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_GetCartRequest proto.InternalMessageInfo - -func (m *GetCartRequest) GetUserId() string { - if m != nil { - return m.UserId - } - return "" -} - -type Cart struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Cart) Reset() { *m = Cart{} } -func (m *Cart) String() string { return proto.CompactTextString(m) } -func (*Cart) ProtoMessage() {} -func (*Cart) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{4} -} - -func (m *Cart) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Cart.Unmarshal(m, b) -} -func (m *Cart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Cart.Marshal(b, m, deterministic) -} -func (m *Cart) XXX_Merge(src proto.Message) { - xxx_messageInfo_Cart.Merge(m, src) -} -func (m *Cart) XXX_Size() int { - return xxx_messageInfo_Cart.Size(m) -} -func (m *Cart) XXX_DiscardUnknown() { - xxx_messageInfo_Cart.DiscardUnknown(m) -} - -var xxx_messageInfo_Cart proto.InternalMessageInfo - -func (m *Cart) GetUserId() string { - if m != nil { - return m.UserId - } - return "" -} - -func (m *Cart) GetItems() []*CartItem { - if m != nil { - return m.Items - } - return nil -} - -type Empty struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Empty) Reset() { *m = Empty{} } -func (m *Empty) String() string { return proto.CompactTextString(m) } -func (*Empty) ProtoMessage() {} -func (*Empty) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{5} -} - -func (m *Empty) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Empty.Unmarshal(m, b) -} -func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Empty.Marshal(b, m, deterministic) -} -func (m *Empty) XXX_Merge(src proto.Message) { - xxx_messageInfo_Empty.Merge(m, src) -} -func (m *Empty) XXX_Size() int { - return xxx_messageInfo_Empty.Size(m) -} -func (m *Empty) XXX_DiscardUnknown() { - xxx_messageInfo_Empty.DiscardUnknown(m) -} - -var xxx_messageInfo_Empty proto.InternalMessageInfo - -type ListRecommendationsRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - ProductIds []string `protobuf:"bytes,2,rep,name=product_ids,json=productIds,proto3" json:"product_ids,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ListRecommendationsRequest) Reset() { *m = ListRecommendationsRequest{} } -func (m *ListRecommendationsRequest) String() string { return proto.CompactTextString(m) } -func (*ListRecommendationsRequest) ProtoMessage() {} -func (*ListRecommendationsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{6} -} - -func (m *ListRecommendationsRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ListRecommendationsRequest.Unmarshal(m, b) -} -func (m *ListRecommendationsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ListRecommendationsRequest.Marshal(b, m, deterministic) -} -func (m *ListRecommendationsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListRecommendationsRequest.Merge(m, src) -} -func (m *ListRecommendationsRequest) XXX_Size() int { - return xxx_messageInfo_ListRecommendationsRequest.Size(m) -} -func (m *ListRecommendationsRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ListRecommendationsRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_ListRecommendationsRequest proto.InternalMessageInfo - -func (m *ListRecommendationsRequest) GetUserId() string { - if m != nil { - return m.UserId - } - return "" -} - -func (m *ListRecommendationsRequest) GetProductIds() []string { - if m != nil { - return m.ProductIds - } - return nil -} - -type ListRecommendationsResponse struct { - ProductIds []string `protobuf:"bytes,1,rep,name=product_ids,json=productIds,proto3" json:"product_ids,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ListRecommendationsResponse) Reset() { *m = ListRecommendationsResponse{} } -func (m *ListRecommendationsResponse) String() string { return proto.CompactTextString(m) } -func (*ListRecommendationsResponse) ProtoMessage() {} -func (*ListRecommendationsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{7} -} - -func (m *ListRecommendationsResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ListRecommendationsResponse.Unmarshal(m, b) -} -func (m *ListRecommendationsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ListRecommendationsResponse.Marshal(b, m, deterministic) -} -func (m *ListRecommendationsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListRecommendationsResponse.Merge(m, src) -} -func (m *ListRecommendationsResponse) XXX_Size() int { - return xxx_messageInfo_ListRecommendationsResponse.Size(m) -} -func (m *ListRecommendationsResponse) XXX_DiscardUnknown() { - xxx_messageInfo_ListRecommendationsResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_ListRecommendationsResponse proto.InternalMessageInfo - -func (m *ListRecommendationsResponse) GetProductIds() []string { - if m != nil { - return m.ProductIds - } - return nil -} - -type Product struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` - Picture string `protobuf:"bytes,4,opt,name=picture,proto3" json:"picture,omitempty"` - PriceUsd *Money `protobuf:"bytes,5,opt,name=price_usd,json=priceUsd,proto3" json:"price_usd,omitempty"` - // Categories such as "vintage" or "gardening" that can be used to look up - // other related products. - Categories []string `protobuf:"bytes,6,rep,name=categories,proto3" json:"categories,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Product) Reset() { *m = Product{} } -func (m *Product) String() string { return proto.CompactTextString(m) } -func (*Product) ProtoMessage() {} -func (*Product) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{8} -} - -func (m *Product) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Product.Unmarshal(m, b) -} -func (m *Product) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Product.Marshal(b, m, deterministic) -} -func (m *Product) XXX_Merge(src proto.Message) { - xxx_messageInfo_Product.Merge(m, src) -} -func (m *Product) XXX_Size() int { - return xxx_messageInfo_Product.Size(m) -} -func (m *Product) XXX_DiscardUnknown() { - xxx_messageInfo_Product.DiscardUnknown(m) -} - -var xxx_messageInfo_Product proto.InternalMessageInfo - -func (m *Product) GetId() string { - if m != nil { - return m.Id - } - return "" -} - -func (m *Product) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -func (m *Product) GetDescription() string { - if m != nil { - return m.Description - } - return "" -} - -func (m *Product) GetPicture() string { - if m != nil { - return m.Picture - } - return "" -} - -func (m *Product) GetPriceUsd() *Money { - if m != nil { - return m.PriceUsd - } - return nil -} - -func (m *Product) GetCategories() []string { - if m != nil { - return m.Categories - } - return nil -} - -type ListProductsResponse struct { - Products []*Product `protobuf:"bytes,1,rep,name=products,proto3" json:"products,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ListProductsResponse) Reset() { *m = ListProductsResponse{} } -func (m *ListProductsResponse) String() string { return proto.CompactTextString(m) } -func (*ListProductsResponse) ProtoMessage() {} -func (*ListProductsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{9} -} - -func (m *ListProductsResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ListProductsResponse.Unmarshal(m, b) -} -func (m *ListProductsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ListProductsResponse.Marshal(b, m, deterministic) -} -func (m *ListProductsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListProductsResponse.Merge(m, src) -} -func (m *ListProductsResponse) XXX_Size() int { - return xxx_messageInfo_ListProductsResponse.Size(m) -} -func (m *ListProductsResponse) XXX_DiscardUnknown() { - xxx_messageInfo_ListProductsResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_ListProductsResponse proto.InternalMessageInfo - -func (m *ListProductsResponse) GetProducts() []*Product { - if m != nil { - return m.Products - } - return nil -} - -type GetProductRequest struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetProductRequest) Reset() { *m = GetProductRequest{} } -func (m *GetProductRequest) String() string { return proto.CompactTextString(m) } -func (*GetProductRequest) ProtoMessage() {} -func (*GetProductRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{10} -} - -func (m *GetProductRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetProductRequest.Unmarshal(m, b) -} -func (m *GetProductRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetProductRequest.Marshal(b, m, deterministic) -} -func (m *GetProductRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetProductRequest.Merge(m, src) -} -func (m *GetProductRequest) XXX_Size() int { - return xxx_messageInfo_GetProductRequest.Size(m) -} -func (m *GetProductRequest) XXX_DiscardUnknown() { - xxx_messageInfo_GetProductRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_GetProductRequest proto.InternalMessageInfo - -func (m *GetProductRequest) GetId() string { - if m != nil { - return m.Id - } - return "" -} - -type SearchProductsRequest struct { - Query string `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SearchProductsRequest) Reset() { *m = SearchProductsRequest{} } -func (m *SearchProductsRequest) String() string { return proto.CompactTextString(m) } -func (*SearchProductsRequest) ProtoMessage() {} -func (*SearchProductsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{11} -} - -func (m *SearchProductsRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SearchProductsRequest.Unmarshal(m, b) -} -func (m *SearchProductsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SearchProductsRequest.Marshal(b, m, deterministic) -} -func (m *SearchProductsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_SearchProductsRequest.Merge(m, src) -} -func (m *SearchProductsRequest) XXX_Size() int { - return xxx_messageInfo_SearchProductsRequest.Size(m) -} -func (m *SearchProductsRequest) XXX_DiscardUnknown() { - xxx_messageInfo_SearchProductsRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_SearchProductsRequest proto.InternalMessageInfo - -func (m *SearchProductsRequest) GetQuery() string { - if m != nil { - return m.Query - } - return "" -} - -type SearchProductsResponse struct { - Results []*Product `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SearchProductsResponse) Reset() { *m = SearchProductsResponse{} } -func (m *SearchProductsResponse) String() string { return proto.CompactTextString(m) } -func (*SearchProductsResponse) ProtoMessage() {} -func (*SearchProductsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{12} -} - -func (m *SearchProductsResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SearchProductsResponse.Unmarshal(m, b) -} -func (m *SearchProductsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SearchProductsResponse.Marshal(b, m, deterministic) -} -func (m *SearchProductsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_SearchProductsResponse.Merge(m, src) -} -func (m *SearchProductsResponse) XXX_Size() int { - return xxx_messageInfo_SearchProductsResponse.Size(m) -} -func (m *SearchProductsResponse) XXX_DiscardUnknown() { - xxx_messageInfo_SearchProductsResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_SearchProductsResponse proto.InternalMessageInfo - -func (m *SearchProductsResponse) GetResults() []*Product { - if m != nil { - return m.Results - } - return nil -} - -type GetQuoteRequest struct { - Address *Address `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetQuoteRequest) Reset() { *m = GetQuoteRequest{} } -func (m *GetQuoteRequest) String() string { return proto.CompactTextString(m) } -func (*GetQuoteRequest) ProtoMessage() {} -func (*GetQuoteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{13} -} - -func (m *GetQuoteRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetQuoteRequest.Unmarshal(m, b) -} -func (m *GetQuoteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetQuoteRequest.Marshal(b, m, deterministic) -} -func (m *GetQuoteRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetQuoteRequest.Merge(m, src) -} -func (m *GetQuoteRequest) XXX_Size() int { - return xxx_messageInfo_GetQuoteRequest.Size(m) -} -func (m *GetQuoteRequest) XXX_DiscardUnknown() { - xxx_messageInfo_GetQuoteRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_GetQuoteRequest proto.InternalMessageInfo - -func (m *GetQuoteRequest) GetAddress() *Address { - if m != nil { - return m.Address - } - return nil -} - -func (m *GetQuoteRequest) GetItems() []*CartItem { - if m != nil { - return m.Items - } - return nil -} - -type GetQuoteResponse struct { - CostUsd *Money `protobuf:"bytes,1,opt,name=cost_usd,json=costUsd,proto3" json:"cost_usd,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetQuoteResponse) Reset() { *m = GetQuoteResponse{} } -func (m *GetQuoteResponse) String() string { return proto.CompactTextString(m) } -func (*GetQuoteResponse) ProtoMessage() {} -func (*GetQuoteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{14} -} - -func (m *GetQuoteResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetQuoteResponse.Unmarshal(m, b) -} -func (m *GetQuoteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetQuoteResponse.Marshal(b, m, deterministic) -} -func (m *GetQuoteResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetQuoteResponse.Merge(m, src) -} -func (m *GetQuoteResponse) XXX_Size() int { - return xxx_messageInfo_GetQuoteResponse.Size(m) -} -func (m *GetQuoteResponse) XXX_DiscardUnknown() { - xxx_messageInfo_GetQuoteResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_GetQuoteResponse proto.InternalMessageInfo - -func (m *GetQuoteResponse) GetCostUsd() *Money { - if m != nil { - return m.CostUsd - } - return nil -} - -type ShipOrderRequest struct { - Address *Address `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - Items []*CartItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ShipOrderRequest) Reset() { *m = ShipOrderRequest{} } -func (m *ShipOrderRequest) String() string { return proto.CompactTextString(m) } -func (*ShipOrderRequest) ProtoMessage() {} -func (*ShipOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{15} -} - -func (m *ShipOrderRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ShipOrderRequest.Unmarshal(m, b) -} -func (m *ShipOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ShipOrderRequest.Marshal(b, m, deterministic) -} -func (m *ShipOrderRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ShipOrderRequest.Merge(m, src) -} -func (m *ShipOrderRequest) XXX_Size() int { - return xxx_messageInfo_ShipOrderRequest.Size(m) -} -func (m *ShipOrderRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ShipOrderRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_ShipOrderRequest proto.InternalMessageInfo - -func (m *ShipOrderRequest) GetAddress() *Address { - if m != nil { - return m.Address - } - return nil -} - -func (m *ShipOrderRequest) GetItems() []*CartItem { - if m != nil { - return m.Items - } - return nil -} - -type ShipOrderResponse struct { - TrackingId string `protobuf:"bytes,1,opt,name=tracking_id,json=trackingId,proto3" json:"tracking_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ShipOrderResponse) Reset() { *m = ShipOrderResponse{} } -func (m *ShipOrderResponse) String() string { return proto.CompactTextString(m) } -func (*ShipOrderResponse) ProtoMessage() {} -func (*ShipOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{16} -} - -func (m *ShipOrderResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ShipOrderResponse.Unmarshal(m, b) -} -func (m *ShipOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ShipOrderResponse.Marshal(b, m, deterministic) -} -func (m *ShipOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ShipOrderResponse.Merge(m, src) -} -func (m *ShipOrderResponse) XXX_Size() int { - return xxx_messageInfo_ShipOrderResponse.Size(m) -} -func (m *ShipOrderResponse) XXX_DiscardUnknown() { - xxx_messageInfo_ShipOrderResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_ShipOrderResponse proto.InternalMessageInfo - -func (m *ShipOrderResponse) GetTrackingId() string { - if m != nil { - return m.TrackingId - } - return "" -} - -type Address struct { - StreetAddress string `protobuf:"bytes,1,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` - City string `protobuf:"bytes,2,opt,name=city,proto3" json:"city,omitempty"` - State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` - Country string `protobuf:"bytes,4,opt,name=country,proto3" json:"country,omitempty"` - ZipCode int32 `protobuf:"varint,5,opt,name=zip_code,json=zipCode,proto3" json:"zip_code,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Address) Reset() { *m = Address{} } -func (m *Address) String() string { return proto.CompactTextString(m) } -func (*Address) ProtoMessage() {} -func (*Address) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{17} -} - -func (m *Address) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Address.Unmarshal(m, b) -} -func (m *Address) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Address.Marshal(b, m, deterministic) -} -func (m *Address) XXX_Merge(src proto.Message) { - xxx_messageInfo_Address.Merge(m, src) -} -func (m *Address) XXX_Size() int { - return xxx_messageInfo_Address.Size(m) -} -func (m *Address) XXX_DiscardUnknown() { - xxx_messageInfo_Address.DiscardUnknown(m) -} - -var xxx_messageInfo_Address proto.InternalMessageInfo - -func (m *Address) GetStreetAddress() string { - if m != nil { - return m.StreetAddress - } - return "" -} - -func (m *Address) GetCity() string { - if m != nil { - return m.City - } - return "" -} - -func (m *Address) GetState() string { - if m != nil { - return m.State - } - return "" -} - -func (m *Address) GetCountry() string { - if m != nil { - return m.Country - } - return "" -} - -func (m *Address) GetZipCode() int32 { - if m != nil { - return m.ZipCode - } - return 0 -} - -// Represents an amount of money with its currency type. -type Money struct { - // The 3-letter currency code defined in ISO 4217. - CurrencyCode string `protobuf:"bytes,1,opt,name=currency_code,json=currencyCode,proto3" json:"currency_code,omitempty"` - // The whole units of the amount. - // For example if `currencyCode` is `"USD"`, then 1 unit is one US dollar. - Units int64 `protobuf:"varint,2,opt,name=units,proto3" json:"units,omitempty"` - // Number of nano (10^-9) units of the amount. - // The value must be between -999,999,999 and +999,999,999 inclusive. - // If `units` is positive, `nanos` must be positive or zero. - // If `units` is zero, `nanos` can be positive, zero, or negative. - // If `units` is negative, `nanos` must be negative or zero. - // For example $-1.75 is represented as `units`=-1 and `nanos`=-750,000,000. - Nanos int32 `protobuf:"varint,3,opt,name=nanos,proto3" json:"nanos,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Money) Reset() { *m = Money{} } -func (m *Money) String() string { return proto.CompactTextString(m) } -func (*Money) ProtoMessage() {} -func (*Money) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{18} -} - -func (m *Money) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Money.Unmarshal(m, b) -} -func (m *Money) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Money.Marshal(b, m, deterministic) -} -func (m *Money) XXX_Merge(src proto.Message) { - xxx_messageInfo_Money.Merge(m, src) -} -func (m *Money) XXX_Size() int { - return xxx_messageInfo_Money.Size(m) -} -func (m *Money) XXX_DiscardUnknown() { - xxx_messageInfo_Money.DiscardUnknown(m) -} - -var xxx_messageInfo_Money proto.InternalMessageInfo - -func (m *Money) GetCurrencyCode() string { - if m != nil { - return m.CurrencyCode - } - return "" -} - -func (m *Money) GetUnits() int64 { - if m != nil { - return m.Units - } - return 0 -} - -func (m *Money) GetNanos() int32 { - if m != nil { - return m.Nanos - } - return 0 -} - -type GetSupportedCurrenciesResponse struct { - // The 3-letter currency code defined in ISO 4217. - CurrencyCodes []string `protobuf:"bytes,1,rep,name=currency_codes,json=currencyCodes,proto3" json:"currency_codes,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetSupportedCurrenciesResponse) Reset() { *m = GetSupportedCurrenciesResponse{} } -func (m *GetSupportedCurrenciesResponse) String() string { return proto.CompactTextString(m) } -func (*GetSupportedCurrenciesResponse) ProtoMessage() {} -func (*GetSupportedCurrenciesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{19} -} - -func (m *GetSupportedCurrenciesResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetSupportedCurrenciesResponse.Unmarshal(m, b) -} -func (m *GetSupportedCurrenciesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetSupportedCurrenciesResponse.Marshal(b, m, deterministic) -} -func (m *GetSupportedCurrenciesResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetSupportedCurrenciesResponse.Merge(m, src) -} -func (m *GetSupportedCurrenciesResponse) XXX_Size() int { - return xxx_messageInfo_GetSupportedCurrenciesResponse.Size(m) -} -func (m *GetSupportedCurrenciesResponse) XXX_DiscardUnknown() { - xxx_messageInfo_GetSupportedCurrenciesResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_GetSupportedCurrenciesResponse proto.InternalMessageInfo - -func (m *GetSupportedCurrenciesResponse) GetCurrencyCodes() []string { - if m != nil { - return m.CurrencyCodes - } - return nil -} - -type CurrencyConversionRequest struct { - From *Money `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` - // The 3-letter currency code defined in ISO 4217. - ToCode string `protobuf:"bytes,2,opt,name=to_code,json=toCode,proto3" json:"to_code,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *CurrencyConversionRequest) Reset() { *m = CurrencyConversionRequest{} } -func (m *CurrencyConversionRequest) String() string { return proto.CompactTextString(m) } -func (*CurrencyConversionRequest) ProtoMessage() {} -func (*CurrencyConversionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{20} -} - -func (m *CurrencyConversionRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_CurrencyConversionRequest.Unmarshal(m, b) -} -func (m *CurrencyConversionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_CurrencyConversionRequest.Marshal(b, m, deterministic) -} -func (m *CurrencyConversionRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_CurrencyConversionRequest.Merge(m, src) -} -func (m *CurrencyConversionRequest) XXX_Size() int { - return xxx_messageInfo_CurrencyConversionRequest.Size(m) -} -func (m *CurrencyConversionRequest) XXX_DiscardUnknown() { - xxx_messageInfo_CurrencyConversionRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_CurrencyConversionRequest proto.InternalMessageInfo - -func (m *CurrencyConversionRequest) GetFrom() *Money { - if m != nil { - return m.From - } - return nil -} - -func (m *CurrencyConversionRequest) GetToCode() string { - if m != nil { - return m.ToCode - } - return "" -} - -type CreditCardInfo struct { - CreditCardNumber string `protobuf:"bytes,1,opt,name=credit_card_number,json=creditCardNumber,proto3" json:"credit_card_number,omitempty"` - CreditCardCvv int32 `protobuf:"varint,2,opt,name=credit_card_cvv,json=creditCardCvv,proto3" json:"credit_card_cvv,omitempty"` - CreditCardExpirationYear int32 `protobuf:"varint,3,opt,name=credit_card_expiration_year,json=creditCardExpirationYear,proto3" json:"credit_card_expiration_year,omitempty"` - CreditCardExpirationMonth int32 `protobuf:"varint,4,opt,name=credit_card_expiration_month,json=creditCardExpirationMonth,proto3" json:"credit_card_expiration_month,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *CreditCardInfo) Reset() { *m = CreditCardInfo{} } -func (m *CreditCardInfo) String() string { return proto.CompactTextString(m) } -func (*CreditCardInfo) ProtoMessage() {} -func (*CreditCardInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{21} -} - -func (m *CreditCardInfo) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_CreditCardInfo.Unmarshal(m, b) -} -func (m *CreditCardInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_CreditCardInfo.Marshal(b, m, deterministic) -} -func (m *CreditCardInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_CreditCardInfo.Merge(m, src) -} -func (m *CreditCardInfo) XXX_Size() int { - return xxx_messageInfo_CreditCardInfo.Size(m) -} -func (m *CreditCardInfo) XXX_DiscardUnknown() { - xxx_messageInfo_CreditCardInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_CreditCardInfo proto.InternalMessageInfo - -func (m *CreditCardInfo) GetCreditCardNumber() string { - if m != nil { - return m.CreditCardNumber - } - return "" -} - -func (m *CreditCardInfo) GetCreditCardCvv() int32 { - if m != nil { - return m.CreditCardCvv - } - return 0 -} - -func (m *CreditCardInfo) GetCreditCardExpirationYear() int32 { - if m != nil { - return m.CreditCardExpirationYear - } - return 0 -} - -func (m *CreditCardInfo) GetCreditCardExpirationMonth() int32 { - if m != nil { - return m.CreditCardExpirationMonth - } - return 0 -} - -type ChargeRequest struct { - Amount *Money `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` - CreditCard *CreditCardInfo `protobuf:"bytes,2,opt,name=credit_card,json=creditCard,proto3" json:"credit_card,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ChargeRequest) Reset() { *m = ChargeRequest{} } -func (m *ChargeRequest) String() string { return proto.CompactTextString(m) } -func (*ChargeRequest) ProtoMessage() {} -func (*ChargeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{22} -} - -func (m *ChargeRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ChargeRequest.Unmarshal(m, b) -} -func (m *ChargeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ChargeRequest.Marshal(b, m, deterministic) -} -func (m *ChargeRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ChargeRequest.Merge(m, src) -} -func (m *ChargeRequest) XXX_Size() int { - return xxx_messageInfo_ChargeRequest.Size(m) -} -func (m *ChargeRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ChargeRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_ChargeRequest proto.InternalMessageInfo - -func (m *ChargeRequest) GetAmount() *Money { - if m != nil { - return m.Amount - } - return nil -} - -func (m *ChargeRequest) GetCreditCard() *CreditCardInfo { - if m != nil { - return m.CreditCard - } - return nil -} - -type ChargeResponse struct { - TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ChargeResponse) Reset() { *m = ChargeResponse{} } -func (m *ChargeResponse) String() string { return proto.CompactTextString(m) } -func (*ChargeResponse) ProtoMessage() {} -func (*ChargeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{23} -} - -func (m *ChargeResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ChargeResponse.Unmarshal(m, b) -} -func (m *ChargeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ChargeResponse.Marshal(b, m, deterministic) -} -func (m *ChargeResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ChargeResponse.Merge(m, src) -} -func (m *ChargeResponse) XXX_Size() int { - return xxx_messageInfo_ChargeResponse.Size(m) -} -func (m *ChargeResponse) XXX_DiscardUnknown() { - xxx_messageInfo_ChargeResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_ChargeResponse proto.InternalMessageInfo - -func (m *ChargeResponse) GetTransactionId() string { - if m != nil { - return m.TransactionId - } - return "" -} - -type OrderItem struct { - Item *CartItem `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` - Cost *Money `protobuf:"bytes,2,opt,name=cost,proto3" json:"cost,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *OrderItem) Reset() { *m = OrderItem{} } -func (m *OrderItem) String() string { return proto.CompactTextString(m) } -func (*OrderItem) ProtoMessage() {} -func (*OrderItem) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{24} -} - -func (m *OrderItem) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_OrderItem.Unmarshal(m, b) -} -func (m *OrderItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_OrderItem.Marshal(b, m, deterministic) -} -func (m *OrderItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrderItem.Merge(m, src) -} -func (m *OrderItem) XXX_Size() int { - return xxx_messageInfo_OrderItem.Size(m) -} -func (m *OrderItem) XXX_DiscardUnknown() { - xxx_messageInfo_OrderItem.DiscardUnknown(m) -} - -var xxx_messageInfo_OrderItem proto.InternalMessageInfo - -func (m *OrderItem) GetItem() *CartItem { - if m != nil { - return m.Item - } - return nil -} - -func (m *OrderItem) GetCost() *Money { - if m != nil { - return m.Cost - } - return nil -} - -type OrderResult struct { - OrderId string `protobuf:"bytes,1,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"` - ShippingTrackingId string `protobuf:"bytes,2,opt,name=shipping_tracking_id,json=shippingTrackingId,proto3" json:"shipping_tracking_id,omitempty"` - ShippingCost *Money `protobuf:"bytes,3,opt,name=shipping_cost,json=shippingCost,proto3" json:"shipping_cost,omitempty"` - ShippingAddress *Address `protobuf:"bytes,4,opt,name=shipping_address,json=shippingAddress,proto3" json:"shipping_address,omitempty"` - Items []*OrderItem `protobuf:"bytes,5,rep,name=items,proto3" json:"items,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *OrderResult) Reset() { *m = OrderResult{} } -func (m *OrderResult) String() string { return proto.CompactTextString(m) } -func (*OrderResult) ProtoMessage() {} -func (*OrderResult) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{25} -} - -func (m *OrderResult) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_OrderResult.Unmarshal(m, b) -} -func (m *OrderResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_OrderResult.Marshal(b, m, deterministic) -} -func (m *OrderResult) XXX_Merge(src proto.Message) { - xxx_messageInfo_OrderResult.Merge(m, src) -} -func (m *OrderResult) XXX_Size() int { - return xxx_messageInfo_OrderResult.Size(m) -} -func (m *OrderResult) XXX_DiscardUnknown() { - xxx_messageInfo_OrderResult.DiscardUnknown(m) -} - -var xxx_messageInfo_OrderResult proto.InternalMessageInfo - -func (m *OrderResult) GetOrderId() string { - if m != nil { - return m.OrderId - } - return "" -} - -func (m *OrderResult) GetShippingTrackingId() string { - if m != nil { - return m.ShippingTrackingId - } - return "" -} - -func (m *OrderResult) GetShippingCost() *Money { - if m != nil { - return m.ShippingCost - } - return nil -} - -func (m *OrderResult) GetShippingAddress() *Address { - if m != nil { - return m.ShippingAddress - } - return nil -} - -func (m *OrderResult) GetItems() []*OrderItem { - if m != nil { - return m.Items - } - return nil -} - -type SendOrderConfirmationRequest struct { - Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` - Order *OrderResult `protobuf:"bytes,2,opt,name=order,proto3" json:"order,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *SendOrderConfirmationRequest) Reset() { *m = SendOrderConfirmationRequest{} } -func (m *SendOrderConfirmationRequest) String() string { return proto.CompactTextString(m) } -func (*SendOrderConfirmationRequest) ProtoMessage() {} -func (*SendOrderConfirmationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{26} -} - -func (m *SendOrderConfirmationRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SendOrderConfirmationRequest.Unmarshal(m, b) -} -func (m *SendOrderConfirmationRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SendOrderConfirmationRequest.Marshal(b, m, deterministic) -} -func (m *SendOrderConfirmationRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_SendOrderConfirmationRequest.Merge(m, src) -} -func (m *SendOrderConfirmationRequest) XXX_Size() int { - return xxx_messageInfo_SendOrderConfirmationRequest.Size(m) -} -func (m *SendOrderConfirmationRequest) XXX_DiscardUnknown() { - xxx_messageInfo_SendOrderConfirmationRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_SendOrderConfirmationRequest proto.InternalMessageInfo - -func (m *SendOrderConfirmationRequest) GetEmail() string { - if m != nil { - return m.Email - } - return "" -} - -func (m *SendOrderConfirmationRequest) GetOrder() *OrderResult { - if m != nil { - return m.Order - } - return nil -} - -type PlaceOrderRequest struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - UserCurrency string `protobuf:"bytes,2,opt,name=user_currency,json=userCurrency,proto3" json:"user_currency,omitempty"` - Address *Address `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` - Email string `protobuf:"bytes,5,opt,name=email,proto3" json:"email,omitempty"` - CreditCard *CreditCardInfo `protobuf:"bytes,6,opt,name=credit_card,json=creditCard,proto3" json:"credit_card,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *PlaceOrderRequest) Reset() { *m = PlaceOrderRequest{} } -func (m *PlaceOrderRequest) String() string { return proto.CompactTextString(m) } -func (*PlaceOrderRequest) ProtoMessage() {} -func (*PlaceOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{27} -} - -func (m *PlaceOrderRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PlaceOrderRequest.Unmarshal(m, b) -} -func (m *PlaceOrderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PlaceOrderRequest.Marshal(b, m, deterministic) -} -func (m *PlaceOrderRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_PlaceOrderRequest.Merge(m, src) -} -func (m *PlaceOrderRequest) XXX_Size() int { - return xxx_messageInfo_PlaceOrderRequest.Size(m) -} -func (m *PlaceOrderRequest) XXX_DiscardUnknown() { - xxx_messageInfo_PlaceOrderRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_PlaceOrderRequest proto.InternalMessageInfo - -func (m *PlaceOrderRequest) GetUserId() string { - if m != nil { - return m.UserId - } - return "" -} - -func (m *PlaceOrderRequest) GetUserCurrency() string { - if m != nil { - return m.UserCurrency - } - return "" -} - -func (m *PlaceOrderRequest) GetAddress() *Address { - if m != nil { - return m.Address - } - return nil -} - -func (m *PlaceOrderRequest) GetEmail() string { - if m != nil { - return m.Email - } - return "" -} - -func (m *PlaceOrderRequest) GetCreditCard() *CreditCardInfo { - if m != nil { - return m.CreditCard - } - return nil -} - -type PlaceOrderResponse struct { - Order *OrderResult `protobuf:"bytes,1,opt,name=order,proto3" json:"order,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *PlaceOrderResponse) Reset() { *m = PlaceOrderResponse{} } -func (m *PlaceOrderResponse) String() string { return proto.CompactTextString(m) } -func (*PlaceOrderResponse) ProtoMessage() {} -func (*PlaceOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{28} -} - -func (m *PlaceOrderResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PlaceOrderResponse.Unmarshal(m, b) -} -func (m *PlaceOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PlaceOrderResponse.Marshal(b, m, deterministic) -} -func (m *PlaceOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_PlaceOrderResponse.Merge(m, src) -} -func (m *PlaceOrderResponse) XXX_Size() int { - return xxx_messageInfo_PlaceOrderResponse.Size(m) -} -func (m *PlaceOrderResponse) XXX_DiscardUnknown() { - xxx_messageInfo_PlaceOrderResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_PlaceOrderResponse proto.InternalMessageInfo - -func (m *PlaceOrderResponse) GetOrder() *OrderResult { - if m != nil { - return m.Order - } - return nil -} - -type AdRequest struct { - // List of important key words from the current page describing the context. - ContextKeys []string `protobuf:"bytes,1,rep,name=context_keys,json=contextKeys,proto3" json:"context_keys,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *AdRequest) Reset() { *m = AdRequest{} } -func (m *AdRequest) String() string { return proto.CompactTextString(m) } -func (*AdRequest) ProtoMessage() {} -func (*AdRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{29} -} - -func (m *AdRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_AdRequest.Unmarshal(m, b) -} -func (m *AdRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_AdRequest.Marshal(b, m, deterministic) -} -func (m *AdRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_AdRequest.Merge(m, src) -} -func (m *AdRequest) XXX_Size() int { - return xxx_messageInfo_AdRequest.Size(m) -} -func (m *AdRequest) XXX_DiscardUnknown() { - xxx_messageInfo_AdRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_AdRequest proto.InternalMessageInfo - -func (m *AdRequest) GetContextKeys() []string { - if m != nil { - return m.ContextKeys - } - return nil -} - -type AdResponse struct { - Ads []*Ad `protobuf:"bytes,1,rep,name=ads,proto3" json:"ads,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *AdResponse) Reset() { *m = AdResponse{} } -func (m *AdResponse) String() string { return proto.CompactTextString(m) } -func (*AdResponse) ProtoMessage() {} -func (*AdResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{30} -} - -func (m *AdResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_AdResponse.Unmarshal(m, b) -} -func (m *AdResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_AdResponse.Marshal(b, m, deterministic) -} -func (m *AdResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_AdResponse.Merge(m, src) -} -func (m *AdResponse) XXX_Size() int { - return xxx_messageInfo_AdResponse.Size(m) -} -func (m *AdResponse) XXX_DiscardUnknown() { - xxx_messageInfo_AdResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_AdResponse proto.InternalMessageInfo - -func (m *AdResponse) GetAds() []*Ad { - if m != nil { - return m.Ads - } - return nil -} - -type Ad struct { - // url to redirect to when an ad is clicked. - RedirectUrl string `protobuf:"bytes,1,opt,name=redirect_url,json=redirectUrl,proto3" json:"redirect_url,omitempty"` - // short advertisement text to display. - Text string `protobuf:"bytes,2,opt,name=text,proto3" json:"text,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Ad) Reset() { *m = Ad{} } -func (m *Ad) String() string { return proto.CompactTextString(m) } -func (*Ad) ProtoMessage() {} -func (*Ad) Descriptor() ([]byte, []int) { - return fileDescriptor_ca53982754088a9d, []int{31} -} - -func (m *Ad) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Ad.Unmarshal(m, b) -} -func (m *Ad) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Ad.Marshal(b, m, deterministic) -} -func (m *Ad) XXX_Merge(src proto.Message) { - xxx_messageInfo_Ad.Merge(m, src) -} -func (m *Ad) XXX_Size() int { - return xxx_messageInfo_Ad.Size(m) -} -func (m *Ad) XXX_DiscardUnknown() { - xxx_messageInfo_Ad.DiscardUnknown(m) -} - -var xxx_messageInfo_Ad proto.InternalMessageInfo - -func (m *Ad) GetRedirectUrl() string { - if m != nil { - return m.RedirectUrl - } - return "" -} - -func (m *Ad) GetText() string { - if m != nil { - return m.Text - } - return "" -} - -func init() { - proto.RegisterType((*CartItem)(nil), "hipstershop.CartItem") - proto.RegisterType((*AddItemRequest)(nil), "hipstershop.AddItemRequest") - proto.RegisterType((*EmptyCartRequest)(nil), "hipstershop.EmptyCartRequest") - proto.RegisterType((*GetCartRequest)(nil), "hipstershop.GetCartRequest") - proto.RegisterType((*Cart)(nil), "hipstershop.Cart") - proto.RegisterType((*Empty)(nil), "hipstershop.Empty") - proto.RegisterType((*ListRecommendationsRequest)(nil), "hipstershop.ListRecommendationsRequest") - proto.RegisterType((*ListRecommendationsResponse)(nil), "hipstershop.ListRecommendationsResponse") - proto.RegisterType((*Product)(nil), "hipstershop.Product") - proto.RegisterType((*ListProductsResponse)(nil), "hipstershop.ListProductsResponse") - proto.RegisterType((*GetProductRequest)(nil), "hipstershop.GetProductRequest") - proto.RegisterType((*SearchProductsRequest)(nil), "hipstershop.SearchProductsRequest") - proto.RegisterType((*SearchProductsResponse)(nil), "hipstershop.SearchProductsResponse") - proto.RegisterType((*GetQuoteRequest)(nil), "hipstershop.GetQuoteRequest") - proto.RegisterType((*GetQuoteResponse)(nil), "hipstershop.GetQuoteResponse") - proto.RegisterType((*ShipOrderRequest)(nil), "hipstershop.ShipOrderRequest") - proto.RegisterType((*ShipOrderResponse)(nil), "hipstershop.ShipOrderResponse") - proto.RegisterType((*Address)(nil), "hipstershop.Address") - proto.RegisterType((*Money)(nil), "hipstershop.Money") - proto.RegisterType((*GetSupportedCurrenciesResponse)(nil), "hipstershop.GetSupportedCurrenciesResponse") - proto.RegisterType((*CurrencyConversionRequest)(nil), "hipstershop.CurrencyConversionRequest") - proto.RegisterType((*CreditCardInfo)(nil), "hipstershop.CreditCardInfo") - proto.RegisterType((*ChargeRequest)(nil), "hipstershop.ChargeRequest") - proto.RegisterType((*ChargeResponse)(nil), "hipstershop.ChargeResponse") - proto.RegisterType((*OrderItem)(nil), "hipstershop.OrderItem") - proto.RegisterType((*OrderResult)(nil), "hipstershop.OrderResult") - proto.RegisterType((*SendOrderConfirmationRequest)(nil), "hipstershop.SendOrderConfirmationRequest") - proto.RegisterType((*PlaceOrderRequest)(nil), "hipstershop.PlaceOrderRequest") - proto.RegisterType((*PlaceOrderResponse)(nil), "hipstershop.PlaceOrderResponse") - proto.RegisterType((*AdRequest)(nil), "hipstershop.AdRequest") - proto.RegisterType((*AdResponse)(nil), "hipstershop.AdResponse") - proto.RegisterType((*Ad)(nil), "hipstershop.Ad") -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// CartServiceClient is the client API for CartService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type CartServiceClient interface { - AddItem(ctx context.Context, in *AddItemRequest, opts ...grpc.CallOption) (*Empty, error) - GetCart(ctx context.Context, in *GetCartRequest, opts ...grpc.CallOption) (*Cart, error) - EmptyCart(ctx context.Context, in *EmptyCartRequest, opts ...grpc.CallOption) (*Empty, error) -} - -type cartServiceClient struct { - cc *grpc.ClientConn -} - -func NewCartServiceClient(cc *grpc.ClientConn) CartServiceClient { - return &cartServiceClient{cc} -} - -func (c *cartServiceClient) AddItem(ctx context.Context, in *AddItemRequest, opts ...grpc.CallOption) (*Empty, error) { - out := new(Empty) - err := c.cc.Invoke(ctx, "/hipstershop.CartService/AddItem", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *cartServiceClient) GetCart(ctx context.Context, in *GetCartRequest, opts ...grpc.CallOption) (*Cart, error) { - out := new(Cart) - err := c.cc.Invoke(ctx, "/hipstershop.CartService/GetCart", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *cartServiceClient) EmptyCart(ctx context.Context, in *EmptyCartRequest, opts ...grpc.CallOption) (*Empty, error) { - out := new(Empty) - err := c.cc.Invoke(ctx, "/hipstershop.CartService/EmptyCart", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// CartServiceServer is the server API for CartService service. -type CartServiceServer interface { - AddItem(context.Context, *AddItemRequest) (*Empty, error) - GetCart(context.Context, *GetCartRequest) (*Cart, error) - EmptyCart(context.Context, *EmptyCartRequest) (*Empty, error) -} - -func RegisterCartServiceServer(s *grpc.Server, srv CartServiceServer) { - s.RegisterService(&_CartService_serviceDesc, srv) -} - -func _CartService_AddItem_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(AddItemRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CartServiceServer).AddItem(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.CartService/AddItem", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CartServiceServer).AddItem(ctx, req.(*AddItemRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _CartService_GetCart_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetCartRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CartServiceServer).GetCart(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.CartService/GetCart", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CartServiceServer).GetCart(ctx, req.(*GetCartRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _CartService_EmptyCart_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(EmptyCartRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CartServiceServer).EmptyCart(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.CartService/EmptyCart", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CartServiceServer).EmptyCart(ctx, req.(*EmptyCartRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _CartService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "hipstershop.CartService", - HandlerType: (*CartServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "AddItem", - Handler: _CartService_AddItem_Handler, - }, - { - MethodName: "GetCart", - Handler: _CartService_GetCart_Handler, - }, - { - MethodName: "EmptyCart", - Handler: _CartService_EmptyCart_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "demo.proto", -} - -// RecommendationServiceClient is the client API for RecommendationService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type RecommendationServiceClient interface { - ListRecommendations(ctx context.Context, in *ListRecommendationsRequest, opts ...grpc.CallOption) (*ListRecommendationsResponse, error) -} - -type recommendationServiceClient struct { - cc *grpc.ClientConn -} - -func NewRecommendationServiceClient(cc *grpc.ClientConn) RecommendationServiceClient { - return &recommendationServiceClient{cc} -} - -func (c *recommendationServiceClient) ListRecommendations(ctx context.Context, in *ListRecommendationsRequest, opts ...grpc.CallOption) (*ListRecommendationsResponse, error) { - out := new(ListRecommendationsResponse) - err := c.cc.Invoke(ctx, "/hipstershop.RecommendationService/ListRecommendations", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// RecommendationServiceServer is the server API for RecommendationService service. -type RecommendationServiceServer interface { - ListRecommendations(context.Context, *ListRecommendationsRequest) (*ListRecommendationsResponse, error) -} - -func RegisterRecommendationServiceServer(s *grpc.Server, srv RecommendationServiceServer) { - s.RegisterService(&_RecommendationService_serviceDesc, srv) -} - -func _RecommendationService_ListRecommendations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ListRecommendationsRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(RecommendationServiceServer).ListRecommendations(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.RecommendationService/ListRecommendations", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(RecommendationServiceServer).ListRecommendations(ctx, req.(*ListRecommendationsRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _RecommendationService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "hipstershop.RecommendationService", - HandlerType: (*RecommendationServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "ListRecommendations", - Handler: _RecommendationService_ListRecommendations_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "demo.proto", -} - -// ProductCatalogServiceClient is the client API for ProductCatalogService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type ProductCatalogServiceClient interface { - ListProducts(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*ListProductsResponse, error) - GetProduct(ctx context.Context, in *GetProductRequest, opts ...grpc.CallOption) (*Product, error) - SearchProducts(ctx context.Context, in *SearchProductsRequest, opts ...grpc.CallOption) (*SearchProductsResponse, error) -} - -type productCatalogServiceClient struct { - cc *grpc.ClientConn -} - -func NewProductCatalogServiceClient(cc *grpc.ClientConn) ProductCatalogServiceClient { - return &productCatalogServiceClient{cc} -} - -func (c *productCatalogServiceClient) ListProducts(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*ListProductsResponse, error) { - out := new(ListProductsResponse) - err := c.cc.Invoke(ctx, "/hipstershop.ProductCatalogService/ListProducts", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *productCatalogServiceClient) GetProduct(ctx context.Context, in *GetProductRequest, opts ...grpc.CallOption) (*Product, error) { - out := new(Product) - err := c.cc.Invoke(ctx, "/hipstershop.ProductCatalogService/GetProduct", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *productCatalogServiceClient) SearchProducts(ctx context.Context, in *SearchProductsRequest, opts ...grpc.CallOption) (*SearchProductsResponse, error) { - out := new(SearchProductsResponse) - err := c.cc.Invoke(ctx, "/hipstershop.ProductCatalogService/SearchProducts", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// ProductCatalogServiceServer is the server API for ProductCatalogService service. -type ProductCatalogServiceServer interface { - ListProducts(context.Context, *Empty) (*ListProductsResponse, error) - GetProduct(context.Context, *GetProductRequest) (*Product, error) - SearchProducts(context.Context, *SearchProductsRequest) (*SearchProductsResponse, error) -} - -func RegisterProductCatalogServiceServer(s *grpc.Server, srv ProductCatalogServiceServer) { - s.RegisterService(&_ProductCatalogService_serviceDesc, srv) -} - -func _ProductCatalogService_ListProducts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(Empty) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ProductCatalogServiceServer).ListProducts(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.ProductCatalogService/ListProducts", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ProductCatalogServiceServer).ListProducts(ctx, req.(*Empty)) - } - return interceptor(ctx, in, info, handler) -} - -func _ProductCatalogService_GetProduct_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetProductRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ProductCatalogServiceServer).GetProduct(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.ProductCatalogService/GetProduct", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ProductCatalogServiceServer).GetProduct(ctx, req.(*GetProductRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _ProductCatalogService_SearchProducts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SearchProductsRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ProductCatalogServiceServer).SearchProducts(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.ProductCatalogService/SearchProducts", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ProductCatalogServiceServer).SearchProducts(ctx, req.(*SearchProductsRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _ProductCatalogService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "hipstershop.ProductCatalogService", - HandlerType: (*ProductCatalogServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "ListProducts", - Handler: _ProductCatalogService_ListProducts_Handler, - }, - { - MethodName: "GetProduct", - Handler: _ProductCatalogService_GetProduct_Handler, - }, - { - MethodName: "SearchProducts", - Handler: _ProductCatalogService_SearchProducts_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "demo.proto", -} - -// ShippingServiceClient is the client API for ShippingService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type ShippingServiceClient interface { - GetQuote(ctx context.Context, in *GetQuoteRequest, opts ...grpc.CallOption) (*GetQuoteResponse, error) - ShipOrder(ctx context.Context, in *ShipOrderRequest, opts ...grpc.CallOption) (*ShipOrderResponse, error) -} - -type shippingServiceClient struct { - cc *grpc.ClientConn -} - -func NewShippingServiceClient(cc *grpc.ClientConn) ShippingServiceClient { - return &shippingServiceClient{cc} -} - -func (c *shippingServiceClient) GetQuote(ctx context.Context, in *GetQuoteRequest, opts ...grpc.CallOption) (*GetQuoteResponse, error) { - out := new(GetQuoteResponse) - err := c.cc.Invoke(ctx, "/hipstershop.ShippingService/GetQuote", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *shippingServiceClient) ShipOrder(ctx context.Context, in *ShipOrderRequest, opts ...grpc.CallOption) (*ShipOrderResponse, error) { - out := new(ShipOrderResponse) - err := c.cc.Invoke(ctx, "/hipstershop.ShippingService/ShipOrder", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// ShippingServiceServer is the server API for ShippingService service. -type ShippingServiceServer interface { - GetQuote(context.Context, *GetQuoteRequest) (*GetQuoteResponse, error) - ShipOrder(context.Context, *ShipOrderRequest) (*ShipOrderResponse, error) -} - -func RegisterShippingServiceServer(s *grpc.Server, srv ShippingServiceServer) { - s.RegisterService(&_ShippingService_serviceDesc, srv) -} - -func _ShippingService_GetQuote_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetQuoteRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ShippingServiceServer).GetQuote(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.ShippingService/GetQuote", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ShippingServiceServer).GetQuote(ctx, req.(*GetQuoteRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _ShippingService_ShipOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ShipOrderRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ShippingServiceServer).ShipOrder(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.ShippingService/ShipOrder", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ShippingServiceServer).ShipOrder(ctx, req.(*ShipOrderRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _ShippingService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "hipstershop.ShippingService", - HandlerType: (*ShippingServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "GetQuote", - Handler: _ShippingService_GetQuote_Handler, - }, - { - MethodName: "ShipOrder", - Handler: _ShippingService_ShipOrder_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "demo.proto", -} - -// CurrencyServiceClient is the client API for CurrencyService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type CurrencyServiceClient interface { - GetSupportedCurrencies(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*GetSupportedCurrenciesResponse, error) - Convert(ctx context.Context, in *CurrencyConversionRequest, opts ...grpc.CallOption) (*Money, error) -} - -type currencyServiceClient struct { - cc *grpc.ClientConn -} - -func NewCurrencyServiceClient(cc *grpc.ClientConn) CurrencyServiceClient { - return ¤cyServiceClient{cc} -} - -func (c *currencyServiceClient) GetSupportedCurrencies(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*GetSupportedCurrenciesResponse, error) { - out := new(GetSupportedCurrenciesResponse) - err := c.cc.Invoke(ctx, "/hipstershop.CurrencyService/GetSupportedCurrencies", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *currencyServiceClient) Convert(ctx context.Context, in *CurrencyConversionRequest, opts ...grpc.CallOption) (*Money, error) { - out := new(Money) - err := c.cc.Invoke(ctx, "/hipstershop.CurrencyService/Convert", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// CurrencyServiceServer is the server API for CurrencyService service. -type CurrencyServiceServer interface { - GetSupportedCurrencies(context.Context, *Empty) (*GetSupportedCurrenciesResponse, error) - Convert(context.Context, *CurrencyConversionRequest) (*Money, error) -} - -func RegisterCurrencyServiceServer(s *grpc.Server, srv CurrencyServiceServer) { - s.RegisterService(&_CurrencyService_serviceDesc, srv) -} - -func _CurrencyService_GetSupportedCurrencies_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(Empty) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CurrencyServiceServer).GetSupportedCurrencies(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.CurrencyService/GetSupportedCurrencies", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CurrencyServiceServer).GetSupportedCurrencies(ctx, req.(*Empty)) - } - return interceptor(ctx, in, info, handler) -} - -func _CurrencyService_Convert_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(CurrencyConversionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CurrencyServiceServer).Convert(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.CurrencyService/Convert", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CurrencyServiceServer).Convert(ctx, req.(*CurrencyConversionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _CurrencyService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "hipstershop.CurrencyService", - HandlerType: (*CurrencyServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "GetSupportedCurrencies", - Handler: _CurrencyService_GetSupportedCurrencies_Handler, - }, - { - MethodName: "Convert", - Handler: _CurrencyService_Convert_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "demo.proto", -} - -// PaymentServiceClient is the client API for PaymentService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type PaymentServiceClient interface { - Charge(ctx context.Context, in *ChargeRequest, opts ...grpc.CallOption) (*ChargeResponse, error) -} - -type paymentServiceClient struct { - cc *grpc.ClientConn -} - -func NewPaymentServiceClient(cc *grpc.ClientConn) PaymentServiceClient { - return &paymentServiceClient{cc} -} - -func (c *paymentServiceClient) Charge(ctx context.Context, in *ChargeRequest, opts ...grpc.CallOption) (*ChargeResponse, error) { - out := new(ChargeResponse) - err := c.cc.Invoke(ctx, "/hipstershop.PaymentService/Charge", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// PaymentServiceServer is the server API for PaymentService service. -type PaymentServiceServer interface { - Charge(context.Context, *ChargeRequest) (*ChargeResponse, error) -} - -func RegisterPaymentServiceServer(s *grpc.Server, srv PaymentServiceServer) { - s.RegisterService(&_PaymentService_serviceDesc, srv) -} - -func _PaymentService_Charge_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ChargeRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(PaymentServiceServer).Charge(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.PaymentService/Charge", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(PaymentServiceServer).Charge(ctx, req.(*ChargeRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _PaymentService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "hipstershop.PaymentService", - HandlerType: (*PaymentServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Charge", - Handler: _PaymentService_Charge_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "demo.proto", -} - -// EmailServiceClient is the client API for EmailService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type EmailServiceClient interface { - SendOrderConfirmation(ctx context.Context, in *SendOrderConfirmationRequest, opts ...grpc.CallOption) (*Empty, error) -} - -type emailServiceClient struct { - cc *grpc.ClientConn -} - -func NewEmailServiceClient(cc *grpc.ClientConn) EmailServiceClient { - return &emailServiceClient{cc} -} - -func (c *emailServiceClient) SendOrderConfirmation(ctx context.Context, in *SendOrderConfirmationRequest, opts ...grpc.CallOption) (*Empty, error) { - out := new(Empty) - err := c.cc.Invoke(ctx, "/hipstershop.EmailService/SendOrderConfirmation", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// EmailServiceServer is the server API for EmailService service. -type EmailServiceServer interface { - SendOrderConfirmation(context.Context, *SendOrderConfirmationRequest) (*Empty, error) -} - -func RegisterEmailServiceServer(s *grpc.Server, srv EmailServiceServer) { - s.RegisterService(&_EmailService_serviceDesc, srv) -} - -func _EmailService_SendOrderConfirmation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SendOrderConfirmationRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EmailServiceServer).SendOrderConfirmation(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.EmailService/SendOrderConfirmation", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EmailServiceServer).SendOrderConfirmation(ctx, req.(*SendOrderConfirmationRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _EmailService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "hipstershop.EmailService", - HandlerType: (*EmailServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "SendOrderConfirmation", - Handler: _EmailService_SendOrderConfirmation_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "demo.proto", -} - -// CheckoutServiceClient is the client API for CheckoutService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type CheckoutServiceClient interface { - PlaceOrder(ctx context.Context, in *PlaceOrderRequest, opts ...grpc.CallOption) (*PlaceOrderResponse, error) -} - -type checkoutServiceClient struct { - cc *grpc.ClientConn -} - -func NewCheckoutServiceClient(cc *grpc.ClientConn) CheckoutServiceClient { - return &checkoutServiceClient{cc} -} - -func (c *checkoutServiceClient) PlaceOrder(ctx context.Context, in *PlaceOrderRequest, opts ...grpc.CallOption) (*PlaceOrderResponse, error) { - out := new(PlaceOrderResponse) - err := c.cc.Invoke(ctx, "/hipstershop.CheckoutService/PlaceOrder", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// CheckoutServiceServer is the server API for CheckoutService service. -type CheckoutServiceServer interface { - PlaceOrder(context.Context, *PlaceOrderRequest) (*PlaceOrderResponse, error) -} - -func RegisterCheckoutServiceServer(s *grpc.Server, srv CheckoutServiceServer) { - s.RegisterService(&_CheckoutService_serviceDesc, srv) -} - -func _CheckoutService_PlaceOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(PlaceOrderRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CheckoutServiceServer).PlaceOrder(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.CheckoutService/PlaceOrder", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CheckoutServiceServer).PlaceOrder(ctx, req.(*PlaceOrderRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _CheckoutService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "hipstershop.CheckoutService", - HandlerType: (*CheckoutServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "PlaceOrder", - Handler: _CheckoutService_PlaceOrder_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "demo.proto", -} - -// AdServiceClient is the client API for AdService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type AdServiceClient interface { - GetAds(ctx context.Context, in *AdRequest, opts ...grpc.CallOption) (*AdResponse, error) -} - -type adServiceClient struct { - cc *grpc.ClientConn -} - -func NewAdServiceClient(cc *grpc.ClientConn) AdServiceClient { - return &adServiceClient{cc} -} - -func (c *adServiceClient) GetAds(ctx context.Context, in *AdRequest, opts ...grpc.CallOption) (*AdResponse, error) { - out := new(AdResponse) - err := c.cc.Invoke(ctx, "/hipstershop.AdService/GetAds", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// AdServiceServer is the server API for AdService service. -type AdServiceServer interface { - GetAds(context.Context, *AdRequest) (*AdResponse, error) -} - -func RegisterAdServiceServer(s *grpc.Server, srv AdServiceServer) { - s.RegisterService(&_AdService_serviceDesc, srv) -} - -func _AdService_GetAds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(AdRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AdServiceServer).GetAds(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/hipstershop.AdService/GetAds", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AdServiceServer).GetAds(ctx, req.(*AdRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _AdService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "hipstershop.AdService", - HandlerType: (*AdServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "GetAds", - Handler: _AdService_GetAds_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "demo.proto", -} - -func init() { proto.RegisterFile("demo.proto", fileDescriptor_ca53982754088a9d) } - -var fileDescriptor_ca53982754088a9d = []byte{ - // 1500 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xef, 0x72, 0x13, 0xb7, - 0x16, 0xcf, 0x26, 0xb1, 0x1d, 0x1f, 0xc7, 0x4e, 0xa2, 0x9b, 0x04, 0xb3, 0x81, 0x10, 0x94, 0x81, - 0x0b, 0x17, 0x08, 0x4c, 0xee, 0x9d, 0xe1, 0x03, 0xdc, 0xd2, 0x8c, 0xc9, 0x18, 0x4f, 0xa1, 0xd0, - 0x0d, 0xe9, 0xd0, 0xa1, 0x53, 0xcf, 0xb2, 0x12, 0xf1, 0x96, 0xec, 0x6a, 0x91, 0xb4, 0x19, 0xcc, - 0xc7, 0xf6, 0x01, 0xfa, 0x1e, 0x7d, 0x81, 0xce, 0xf4, 0x11, 0xfa, 0xbd, 0xaf, 0xd0, 0xe7, 0xe8, - 0x48, 0xbb, 0xda, 0x7f, 0xb1, 0x13, 0xf8, 0xd2, 0x6f, 0xab, 0xa3, 0x9f, 0xce, 0xf9, 0xe9, 0xe8, - 0xfc, 0xb3, 0x01, 0x08, 0x0d, 0xd8, 0x4e, 0xc4, 0x99, 0x64, 0xa8, 0x35, 0xf2, 0x23, 0x21, 0x29, - 0x17, 0x23, 0x16, 0xe1, 0x7d, 0x58, 0xe8, 0xb9, 0x5c, 0x0e, 0x24, 0x0d, 0xd0, 0x65, 0x80, 0x88, - 0x33, 0x12, 0x7b, 0x72, 0xe8, 0x93, 0xae, 0xb5, 0x65, 0xdd, 0x68, 0x3a, 0xcd, 0x54, 0x32, 0x20, - 0xc8, 0x86, 0x85, 0xf7, 0xb1, 0x1b, 0x4a, 0x5f, 0x8e, 0xbb, 0xb3, 0x5b, 0xd6, 0x8d, 0x9a, 0x93, - 0xad, 0xf1, 0x4b, 0xe8, 0xec, 0x11, 0xa2, 0xb4, 0x38, 0xf4, 0x7d, 0x4c, 0x85, 0x44, 0x17, 0xa0, - 0x11, 0x0b, 0xca, 0x73, 0x4d, 0x75, 0xb5, 0x1c, 0x10, 0x74, 0x13, 0xe6, 0x7d, 0x49, 0x03, 0xad, - 0xa2, 0xb5, 0xbb, 0xb6, 0x53, 0x60, 0xb3, 0x63, 0xa8, 0x38, 0x1a, 0x82, 0x6f, 0xc1, 0xf2, 0x7e, - 0x10, 0xc9, 0xb1, 0x12, 0x9f, 0xa7, 0x17, 0xdf, 0x84, 0x4e, 0x9f, 0xca, 0x4f, 0x82, 0x3e, 0x85, - 0x79, 0x85, 0x9b, 0xce, 0xf1, 0x16, 0xd4, 0x14, 0x01, 0xd1, 0x9d, 0xdd, 0x9a, 0x9b, 0x4e, 0x32, - 0xc1, 0xe0, 0x06, 0xd4, 0x34, 0x4b, 0xfc, 0x2d, 0xd8, 0x4f, 0x7d, 0x21, 0x1d, 0xea, 0xb1, 0x20, - 0xa0, 0x21, 0x71, 0xa5, 0xcf, 0x42, 0x71, 0xae, 0x43, 0xae, 0x40, 0x2b, 0x77, 0x7b, 0x62, 0xb2, - 0xe9, 0x40, 0xe6, 0x77, 0x81, 0xbf, 0x80, 0x8d, 0x89, 0x7a, 0x45, 0xc4, 0x42, 0x41, 0xab, 0xe7, - 0xad, 0x53, 0xe7, 0x7f, 0xb7, 0xa0, 0xf1, 0x22, 0x59, 0xa2, 0x0e, 0xcc, 0x66, 0x04, 0x66, 0x7d, - 0x82, 0x10, 0xcc, 0x87, 0x6e, 0x40, 0xf5, 0x6b, 0x34, 0x1d, 0xfd, 0x8d, 0xb6, 0xa0, 0x45, 0xa8, - 0xf0, 0xb8, 0x1f, 0x29, 0x43, 0xdd, 0x39, 0xbd, 0x55, 0x14, 0xa1, 0x2e, 0x34, 0x22, 0xdf, 0x93, - 0x31, 0xa7, 0xdd, 0x79, 0xbd, 0x6b, 0x96, 0xe8, 0x2e, 0x34, 0x23, 0xee, 0x7b, 0x74, 0x18, 0x0b, - 0xd2, 0xad, 0xe9, 0x27, 0x46, 0x25, 0xef, 0x3d, 0x63, 0x21, 0x1d, 0x3b, 0x0b, 0x1a, 0x74, 0x28, - 0x08, 0xda, 0x04, 0xf0, 0x5c, 0x49, 0x8f, 0x18, 0xf7, 0xa9, 0xe8, 0xd6, 0x13, 0xf2, 0xb9, 0x04, - 0x3f, 0x81, 0x55, 0x75, 0xf9, 0x94, 0x7f, 0x7e, 0xeb, 0x7b, 0xb0, 0x90, 0x5e, 0x31, 0xb9, 0x72, - 0x6b, 0x77, 0xb5, 0x64, 0x27, 0x3d, 0xe0, 0x64, 0x28, 0xbc, 0x0d, 0x2b, 0x7d, 0x6a, 0x14, 0x99, - 0x57, 0xa9, 0xf8, 0x03, 0xdf, 0x81, 0xb5, 0x03, 0xea, 0x72, 0x6f, 0x94, 0x1b, 0x4c, 0x80, 0xab, - 0x50, 0x7b, 0x1f, 0x53, 0x3e, 0x4e, 0xb1, 0xc9, 0x02, 0x3f, 0x81, 0xf5, 0x2a, 0x3c, 0xe5, 0xb7, - 0x03, 0x0d, 0x4e, 0x45, 0x7c, 0x7c, 0x0e, 0x3d, 0x03, 0xc2, 0x21, 0x2c, 0xf5, 0xa9, 0xfc, 0x26, - 0x66, 0x92, 0x1a, 0x93, 0x3b, 0xd0, 0x70, 0x09, 0xe1, 0x54, 0x08, 0x6d, 0xb4, 0xaa, 0x62, 0x2f, - 0xd9, 0x73, 0x0c, 0xe8, 0xf3, 0xa2, 0x76, 0x0f, 0x96, 0x73, 0x7b, 0x29, 0xe7, 0x3b, 0xb0, 0xe0, - 0x31, 0x21, 0xf5, 0xdb, 0x59, 0x53, 0xdf, 0xae, 0xa1, 0x30, 0x87, 0x82, 0x60, 0x06, 0xcb, 0x07, - 0x23, 0x3f, 0x7a, 0xce, 0x09, 0xe5, 0xff, 0x08, 0xe7, 0xff, 0xc1, 0x4a, 0xc1, 0x60, 0x1e, 0xfe, - 0x92, 0xbb, 0xde, 0x3b, 0x3f, 0x3c, 0xca, 0x73, 0x0b, 0x8c, 0x68, 0x40, 0xf0, 0x2f, 0x16, 0x34, - 0x52, 0xbb, 0xe8, 0x1a, 0x74, 0x84, 0xe4, 0x94, 0xca, 0x61, 0x91, 0x65, 0xd3, 0x69, 0x27, 0x52, - 0x03, 0x43, 0x30, 0xef, 0x99, 0x32, 0xd7, 0x74, 0xf4, 0xb7, 0x0a, 0x00, 0x21, 0x5d, 0x49, 0xd3, - 0x7c, 0x48, 0x16, 0x2a, 0x13, 0x3c, 0x16, 0x87, 0x92, 0x8f, 0x4d, 0x26, 0xa4, 0x4b, 0x74, 0x11, - 0x16, 0x3e, 0xfa, 0xd1, 0xd0, 0x63, 0x84, 0xea, 0x44, 0xa8, 0x39, 0x8d, 0x8f, 0x7e, 0xd4, 0x63, - 0x84, 0xe2, 0x57, 0x50, 0xd3, 0xae, 0x44, 0xdb, 0xd0, 0xf6, 0x62, 0xce, 0x69, 0xe8, 0x8d, 0x13, - 0x60, 0xc2, 0x66, 0xd1, 0x08, 0x15, 0x5a, 0x19, 0x8e, 0x43, 0x5f, 0x0a, 0xcd, 0x66, 0xce, 0x49, - 0x16, 0x4a, 0x1a, 0xba, 0x21, 0x13, 0x9a, 0x4e, 0xcd, 0x49, 0x16, 0xb8, 0x0f, 0x9b, 0x7d, 0x2a, - 0x0f, 0xe2, 0x28, 0x62, 0x5c, 0x52, 0xd2, 0x4b, 0xf4, 0xf8, 0x34, 0x8f, 0xcb, 0x6b, 0xd0, 0x29, - 0x99, 0x34, 0x05, 0xa3, 0x5d, 0xb4, 0x29, 0xf0, 0xf7, 0x70, 0xb1, 0x97, 0x09, 0xc2, 0x13, 0xca, - 0x85, 0xcf, 0x42, 0xf3, 0xc8, 0xd7, 0x61, 0xfe, 0x2d, 0x67, 0xc1, 0x19, 0x31, 0xa2, 0xf7, 0x55, - 0xc9, 0x93, 0x2c, 0xb9, 0x58, 0xe2, 0xc9, 0xba, 0x64, 0xda, 0x01, 0x7f, 0x59, 0xd0, 0xe9, 0x71, - 0x4a, 0x7c, 0x55, 0xaf, 0xc9, 0x20, 0x7c, 0xcb, 0xd0, 0x6d, 0x40, 0x9e, 0x96, 0x0c, 0x3d, 0x97, - 0x93, 0x61, 0x18, 0x07, 0x6f, 0x28, 0x4f, 0xfd, 0xb1, 0xec, 0x65, 0xd8, 0xaf, 0xb5, 0x1c, 0x5d, - 0x87, 0xa5, 0x22, 0xda, 0x3b, 0x39, 0x49, 0x5b, 0x52, 0x3b, 0x87, 0xf6, 0x4e, 0x4e, 0xd0, 0xff, - 0x61, 0xa3, 0x88, 0xa3, 0x1f, 0x22, 0x9f, 0xeb, 0xf2, 0x39, 0x1c, 0x53, 0x97, 0xa7, 0xbe, 0xeb, - 0xe6, 0x67, 0xf6, 0x33, 0xc0, 0x77, 0xd4, 0xe5, 0xe8, 0x11, 0x5c, 0x9a, 0x72, 0x3c, 0x60, 0xa1, - 0x1c, 0xe9, 0x27, 0xaf, 0x39, 0x17, 0x27, 0x9d, 0x7f, 0xa6, 0x00, 0x78, 0x0c, 0xed, 0xde, 0xc8, - 0xe5, 0x47, 0x59, 0x4e, 0xff, 0x07, 0xea, 0x6e, 0xa0, 0x22, 0xe4, 0x0c, 0xe7, 0xa5, 0x08, 0xf4, - 0x10, 0x5a, 0x05, 0xeb, 0x69, 0xc3, 0xdc, 0x28, 0x67, 0x48, 0xc9, 0x89, 0x0e, 0xe4, 0x4c, 0xf0, - 0x7d, 0xe8, 0x18, 0xd3, 0xf9, 0xd3, 0x4b, 0xee, 0x86, 0xc2, 0xf5, 0xf4, 0x15, 0xb2, 0x64, 0x69, - 0x17, 0xa4, 0x03, 0x82, 0x7f, 0x80, 0xa6, 0xce, 0x30, 0x3d, 0x13, 0x98, 0x6e, 0x6d, 0x9d, 0xdb, - 0xad, 0x55, 0x54, 0xa8, 0xca, 0x90, 0xf2, 0x9c, 0x18, 0x15, 0x6a, 0x1f, 0xff, 0x34, 0x0b, 0x2d, - 0x93, 0xc2, 0xf1, 0xb1, 0x54, 0x89, 0xc2, 0xd4, 0x32, 0x27, 0xd4, 0xd0, 0xeb, 0x01, 0x41, 0xf7, - 0x60, 0x55, 0x8c, 0xfc, 0x28, 0x52, 0xb9, 0x5d, 0x4c, 0xf2, 0x24, 0x9a, 0x90, 0xd9, 0x7b, 0x99, - 0x25, 0x3b, 0xba, 0x0f, 0xed, 0xec, 0x84, 0x66, 0x33, 0x37, 0x95, 0xcd, 0xa2, 0x01, 0xf6, 0x98, - 0x90, 0xe8, 0x11, 0x2c, 0x67, 0x07, 0x4d, 0x6d, 0x98, 0x3f, 0xa3, 0x82, 0x2d, 0x19, 0xb4, 0xa9, - 0x19, 0xb7, 0x4d, 0x25, 0xab, 0xe9, 0x4a, 0xb6, 0x5e, 0x3a, 0x95, 0x39, 0xd4, 0x94, 0x32, 0x02, - 0x97, 0x0e, 0x68, 0x48, 0xb4, 0xbc, 0xc7, 0xc2, 0xb7, 0x3e, 0x0f, 0x74, 0xd8, 0x14, 0xda, 0x0d, - 0x0d, 0x5c, 0xff, 0xd8, 0xb4, 0x1b, 0xbd, 0x40, 0x3b, 0x50, 0xd3, 0xae, 0x49, 0x7d, 0xdc, 0x3d, - 0x6d, 0x23, 0xf1, 0xa9, 0x93, 0xc0, 0xf0, 0x9f, 0x16, 0xac, 0xbc, 0x38, 0x76, 0x3d, 0x5a, 0xaa, - 0xd1, 0x53, 0x27, 0x91, 0x6d, 0x68, 0xeb, 0x0d, 0x53, 0x0a, 0x52, 0x3f, 0x2f, 0x2a, 0xa1, 0xa9, - 0x06, 0xc5, 0x0a, 0x3f, 0xf7, 0x29, 0x15, 0x3e, 0xbb, 0x49, 0xad, 0x78, 0x93, 0x4a, 0x6c, 0xd7, - 0x3f, 0x2f, 0xb6, 0x1f, 0x03, 0x2a, 0x5e, 0x2b, 0x6b, 0xb9, 0xa9, 0x77, 0xac, 0x4f, 0xf3, 0xce, - 0x0e, 0x34, 0xf7, 0x88, 0x71, 0xca, 0x55, 0x58, 0xf4, 0x58, 0x28, 0xe9, 0x07, 0x39, 0x7c, 0x47, - 0xc7, 0xa6, 0x2a, 0xb6, 0x52, 0xd9, 0x57, 0x74, 0x2c, 0xf0, 0x5d, 0x00, 0x85, 0x4f, 0xad, 0x5d, - 0x85, 0x39, 0x97, 0x98, 0xe6, 0xbe, 0x54, 0xf1, 0x81, 0xa3, 0xf6, 0xf0, 0x03, 0x98, 0xdd, 0x23, - 0x4a, 0xb3, 0x62, 0xce, 0xa9, 0x27, 0x87, 0x31, 0x37, 0x2f, 0xda, 0x32, 0xb2, 0x43, 0x7e, 0xac, - 0xfa, 0x8d, 0xb2, 0x62, 0xfa, 0x8d, 0xfa, 0xde, 0xfd, 0xc3, 0x82, 0x96, 0xca, 0xb0, 0x03, 0xca, - 0x4f, 0x7c, 0x8f, 0xa2, 0x87, 0xba, 0x8b, 0xe9, 0xa4, 0xdc, 0xa8, 0x7a, 0xbc, 0x30, 0x78, 0xdb, - 0xe5, 0x50, 0x4f, 0x26, 0xd3, 0x19, 0xf4, 0x00, 0x1a, 0xe9, 0x74, 0x5c, 0x39, 0x5d, 0x9e, 0x99, - 0xed, 0x95, 0x53, 0x19, 0x8e, 0x67, 0xd0, 0x97, 0xd0, 0xcc, 0xe6, 0x70, 0x74, 0xf9, 0xb4, 0xfe, - 0xa2, 0x82, 0x89, 0xe6, 0x77, 0x7f, 0xb6, 0x60, 0xad, 0x3c, 0xbf, 0x9a, 0x6b, 0xfd, 0x08, 0xff, - 0x9a, 0x30, 0xdc, 0xa2, 0x7f, 0x97, 0xd4, 0x4c, 0x1f, 0xab, 0xed, 0x1b, 0xe7, 0x03, 0x93, 0x07, - 0x53, 0x2c, 0x66, 0x61, 0x2d, 0x1d, 0xbc, 0x7a, 0xae, 0x74, 0x8f, 0xd9, 0x91, 0x61, 0xd1, 0x87, - 0xc5, 0xe2, 0x94, 0x89, 0x26, 0xdc, 0xc2, 0xbe, 0x7a, 0xca, 0x52, 0x75, 0xe8, 0xc3, 0x33, 0xe8, - 0x31, 0x40, 0x3e, 0x64, 0xa2, 0xcd, 0xaa, 0xab, 0xcb, 0xd3, 0xa7, 0x3d, 0x71, 0x26, 0xc4, 0x33, - 0xe8, 0x35, 0x74, 0xca, 0x63, 0x25, 0xc2, 0x25, 0xe4, 0xc4, 0x11, 0xd5, 0xde, 0x3e, 0x13, 0x93, - 0x79, 0xe1, 0x57, 0x0b, 0x96, 0x0e, 0xd2, 0xe2, 0x65, 0xee, 0x3f, 0x80, 0x05, 0x33, 0x0d, 0xa2, - 0x4b, 0x55, 0xd2, 0xc5, 0xa1, 0xd4, 0xbe, 0x3c, 0x65, 0x37, 0xf3, 0xc0, 0x53, 0x68, 0x66, 0x43, - 0x5a, 0x25, 0x58, 0xaa, 0xd3, 0xa2, 0xbd, 0x39, 0x6d, 0x3b, 0x23, 0xfb, 0x9b, 0x05, 0x4b, 0xa6, - 0xf4, 0x18, 0xb2, 0xaf, 0x61, 0x7d, 0xf2, 0x90, 0x33, 0xf1, 0xd9, 0x6e, 0x55, 0x09, 0x9f, 0x31, - 0x1d, 0xe1, 0x19, 0xd4, 0x87, 0x46, 0x32, 0xf0, 0x48, 0x74, 0xbd, 0x9c, 0x0b, 0xd3, 0xc6, 0x21, - 0x7b, 0x42, 0x73, 0xc1, 0x33, 0xbb, 0x87, 0xd0, 0x79, 0xe1, 0x8e, 0x03, 0x1a, 0x66, 0x19, 0xdc, - 0x83, 0x7a, 0xd2, 0x91, 0x91, 0x5d, 0xd6, 0x5c, 0x9c, 0x10, 0xec, 0x8d, 0x89, 0x7b, 0x99, 0x43, - 0x46, 0xb0, 0xb8, 0xaf, 0x2a, 0xa8, 0x51, 0xfa, 0x4a, 0xfd, 0x60, 0x99, 0xd0, 0x48, 0xd0, 0xcd, - 0x4a, 0x34, 0x4c, 0x6f, 0x36, 0x53, 0x72, 0xf6, 0x0d, 0x2c, 0xf5, 0x46, 0xd4, 0x7b, 0xc7, 0xe2, - 0xec, 0x06, 0xcf, 0x01, 0xf2, 0xba, 0x5b, 0x89, 0xee, 0x53, 0x7d, 0xc6, 0xbe, 0x32, 0x75, 0x3f, - 0xbb, 0xcd, 0x13, 0x55, 0x82, 0x8d, 0xf6, 0x07, 0x50, 0xef, 0xab, 0x19, 0x5c, 0xa0, 0xf5, 0x6a, - 0x39, 0x4d, 0x35, 0x5e, 0x38, 0x25, 0x37, 0x9a, 0xde, 0xd4, 0xf5, 0x9f, 0x1b, 0xff, 0xfd, 0x3b, - 0x00, 0x00, 0xff, 0xff, 0xb2, 0xa0, 0x6e, 0x6c, 0xea, 0x10, 0x00, 0x00, -} diff --git a/src/cartservice/probe/main.go b/src/cartservice/probe/main.go deleted file mode 100644 index 23252c5..0000000 --- a/src/cartservice/probe/main.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "log" - "os" - "time" - - pb "github.com/GoogleCloudPlatform/microservices-demo/src/cartservice/probe/genproto" - - "google.golang.org/grpc" -) - -func main() { - port := os.Getenv("PORT") - if port == "" { - log.Fatal("probe is executed without PORT env var") - } - log.Printf("probe executing on port %q", port) - - conn, err := grpc.DialContext(context.TODO(), - "127.0.0.1:"+port, - grpc.WithBlock(), - grpc.WithTimeout(time.Second*3), - grpc.WithInsecure(), - ) - if err != nil { - log.Fatalf("probe failed: failed to connect: %+v", err) - } - defer conn.Close() - - if _, err := pb.NewCartServiceClient(conn).GetCart(context.TODO(), - &pb.GetCartRequest{UserId: "exec-probe-nonexistinguser"}); err != nil { - log.Fatalf("probe failed: failed to query: %+v", err) - } - log.Println("probe successful") -} From 7f40378ecc790bfbe94a60f2a7e900632d23d57d Mon Sep 17 00:00:00 2001 From: Yoshi Yamaguchi Date: Sat, 6 Oct 2018 03:23:45 +0900 Subject: [PATCH 14/91] log: change log format to JSON payload for better log in Stackdriver (#66) change the log format in Python and Node.js services. Effected services are currencyservice, emailservice, paymentservice, and recommendationservice. Loadgenerator is left as is because of the diffculty to change the log format and log target in locust. ref. #47 --- src/currencyservice/client.js | 16 +++-- src/currencyservice/package-lock.json | 62 +++++++++++++++++++ src/currencyservice/package.json | 1 + src/currencyservice/server.js | 21 ++++--- src/emailservice/email_client.py | 11 ++-- src/emailservice/email_server.py | 17 ++--- src/emailservice/logger.py | 40 ++++++++++++ src/emailservice/requirements.txt | 3 +- src/paymentservice/charge.js | 11 +++- src/paymentservice/package-lock.json | 62 +++++++++++++++++++ src/paymentservice/package.json | 1 + src/paymentservice/server.js | 12 +++- src/recommendationservice/client.py | 7 ++- src/recommendationservice/logger.py | 40 ++++++++++++ .../recommendation_server.py | 16 ++--- src/recommendationservice/requirements.txt | 1 + 16 files changed, 286 insertions(+), 35 deletions(-) create mode 100644 src/emailservice/logger.py create mode 100644 src/recommendationservice/logger.py diff --git a/src/currencyservice/client.js b/src/currencyservice/client.js index 2d367e0..f381dc8 100644 --- a/src/currencyservice/client.js +++ b/src/currencyservice/client.js @@ -20,6 +20,7 @@ require('@google-cloud/trace-agent').start(); const path = require('path'); const grpc = require('grpc'); const leftPad = require('left-pad'); +const pino = require('pino'); const PROTO_PATH = path.join(__dirname, './proto/demo.proto'); const PORT = 7000; @@ -28,6 +29,13 @@ const shopProto = grpc.load(PROTO_PATH).hipstershop; const client = new shopProto.CurrencyService(`localhost:${PORT}`, grpc.credentials.createInsecure()); +const logger = pino({ + name: 'currencyservice-client', + messageKey: 'message', + changeLevelName: 'severity', + useLevelLabels: true +}); + const request = { from: { currency_code: 'CHF', @@ -43,16 +51,16 @@ function _moneyToString (m) { client.getSupportedCurrencies({}, (err, response) => { if (err) { - console.error(`Error in getSupportedCurrencies: ${err}`); + logger.error(`Error in getSupportedCurrencies: ${err}`); } else { - console.log(`Currency codes: ${response.currency_codes}`); + logger.info(`Currency codes: ${response.currency_codes}`); } }); client.convert(request, (err, response) => { if (err) { - console.error(`Error in convert: ${err}`); + logger.error(`Error in convert: ${err}`); } else { - console.log(`Convert: ${_moneyToString(request.from)} to ${_moneyToString(response)}`); + logger.log(`Convert: ${_moneyToString(request.from)} to ${_moneyToString(response)}`); } }); diff --git a/src/currencyservice/package-lock.json b/src/currencyservice/package-lock.json index fb39603..3279481 100644 --- a/src/currencyservice/package-lock.json +++ b/src/currencyservice/package-lock.json @@ -663,16 +663,36 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" }, + "fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==" + }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fast-redact": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-1.2.0.tgz", + "integrity": "sha512-k/uSk9PtFmvYx0m7bRk5B2gZChQk4euWhrn7Mf3vYSmwZBLh7cGNuMuc/vhH1MKMPyVJMMtl9oMwPnwlKqs7CQ==" + }, + "fast-safe-stringify": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", + "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==" + }, "findit2": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/findit2/-/findit2-2.2.3.tgz", "integrity": "sha1-WKRmaX34piBc39vzlVNri9d3pfY=" }, + "flatstr": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.8.tgz", + "integrity": "sha512-YXblbv/vc1zuVVUtnKl1hPqqk7TalZCppnKE7Pr8FI/Rp48vzckS/4SJ4Y9O9RNiI82Vcw/FydmtqdQOg1Dpqw==" + }, "follow-redirects": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.1.tgz", @@ -1570,6 +1590,26 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, + "pino": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/pino/-/pino-5.6.2.tgz", + "integrity": "sha512-JVMYqJkE58b2u5+t85zJLbUDOhoWDjEQqrRY1eQzuR4Ub9RIyUSQJms4deT8Joy+C/QIdrrie7NffgCm+ao9xw==", + "requires": { + "fast-json-parse": "^1.0.3", + "fast-redact": "^1.2.0", + "fast-safe-stringify": "^2.0.6", + "flatstr": "^1.0.5", + "pino-std-serializers": "^2.2.1", + "pump": "^3.0.0", + "quick-format-unescaped": "^3.0.0", + "sonic-boom": "^0.6.1" + } + }, + "pino-std-serializers": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-2.2.1.tgz", + "integrity": "sha512-QqL7kkF7eMCpFG4hpZD8UPQga/kxkkh3E62HzMzTIL4OQyijyisAnBL8msBEAml8xcb/ioGhH7UUzGxuHqczhQ==" + }, "pretty-ms": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-3.2.0.tgz", @@ -1599,6 +1639,15 @@ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", @@ -1609,6 +1658,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, + "quick-format-unescaped": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-3.0.0.tgz", + "integrity": "sha512-XmIOc07VM2kPm6m3j/U6jgxyUgDm2Rgh2c1PPy0JUHoQRdoh86hOym0bHyF6G1T6sn+N5lildhvl/T59H5KVyA==" + }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", @@ -1706,6 +1760,14 @@ "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.0.tgz", "integrity": "sha512-xTCx2vohXC2EWWDqY/zb4+5Mu28D+HYNSOuFzsyRDRvI/e1ICb69afwaUwfjr+25ZXldbOLyp+iDUZHq8UnTag==" }, + "sonic-boom": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-0.6.1.tgz", + "integrity": "sha512-3qx6XXDeG+hPNa+jla1H6BMBLcjLl8L8NRERLVeIf/EuPqoqmq4K8owG29Xu7OypT/7/YT/0uKW6YitsKA+nLQ==", + "requires": { + "flatstr": "^1.0.5" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/src/currencyservice/package.json b/src/currencyservice/package.json index 1d89148..7a21752 100644 --- a/src/currencyservice/package.json +++ b/src/currencyservice/package.json @@ -17,6 +17,7 @@ "google-protobuf": "^3.0.0", "grpc": "^1.0.0", "left-pad": "^1.3.0", + "pino": "^5.6.2", "request": "^2.87.0", "xml2js": "^0.4.19" }, diff --git a/src/currencyservice/server.js b/src/currencyservice/server.js index 69f7c3c..633078c 100644 --- a/src/currencyservice/server.js +++ b/src/currencyservice/server.js @@ -32,6 +32,7 @@ const path = require('path'); const grpc = require('grpc'); const request = require('request'); const xml2js = require('xml2js'); +const pino = require('pino'); const protoLoader = require('@grpc/proto-loader'); const MAIN_PROTO_PATH = path.join(__dirname, './proto/demo.proto'); @@ -43,6 +44,13 @@ const DATA_URL = 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml'; const shopProto = _loadProto(MAIN_PROTO_PATH).hipstershop; const healthProto = _loadProto(HEALTH_PROTO_PATH).grpc.health.v1; +const logger = pino({ + name: 'currencyservice-server', + messageKey: 'message', + changeLevelName: 'severity', + useLevelLabels: true +}); + /** * Helper function that loads a protobuf file. */ @@ -67,7 +75,7 @@ function _loadProto (path) { let _data; function _getCurrencyData (callback) { if (!_data) { - console.log('Fetching currency data...'); + logger.info('Fetching currency data...'); request(DATA_URL, (err, res) => { if (err) { throw new Error(`Error getting data: ${err}`); @@ -108,7 +116,7 @@ function _carry (amount) { * Lists the supported currencies */ function getSupportedCurrencies (call, callback) { - console.log('Getting supported currencies...'); + logger.info('Getting supported currencies...'); _getCurrencyData((data) => { callback(null, {currency_codes: Object.keys(data)}); }); @@ -118,7 +126,7 @@ function getSupportedCurrencies (call, callback) { * Converts between currencies */ function convert (call, callback) { - console.log('received conversion request'); + logger.info('received conversion request'); try { _getCurrencyData((data) => { const request = call.request; @@ -142,12 +150,11 @@ function convert (call, callback) { result.nanos = Math.floor(result.nanos); result.currency_code = request.to_code; - console.log(`conversion request successful`); + logger.info(`conversion request successful`); callback(null, result); }); } catch (err) { - console.error('conversion request failed.'); - console.error(err); + logger.error(`conversion request failed: ${err}`); callback(err.message); } } @@ -164,7 +171,7 @@ function check (call, callback) { * CurrencyConverter service at the sample server port */ function main () { - console.log(`Starting gRPC server on port ${PORT}...`); + logger.info(`Starting gRPC server on port ${PORT}...`); const server = new grpc.Server(); server.addService(shopProto.CurrencyService.service, {getSupportedCurrencies, convert}); server.addService(healthProto.Health.service, {check}); diff --git a/src/emailservice/email_client.py b/src/emailservice/email_client.py index e4e591f..32593fe 100644 --- a/src/emailservice/email_client.py +++ b/src/emailservice/email_client.py @@ -19,6 +19,9 @@ import grpc import demo_pb2 import demo_pb2_grpc +from logger import getJSONLogger +logger = getJSONLogger('emailservice-client') + # from opencensus.trace.tracer import Tracer # from opencensus.trace.exporters import stackdriver_exporter # from opencensus.trace.ext.grpc import client_interceptor @@ -39,10 +42,10 @@ def send_confirmation_email(email, order): email = email, order = order )) - print('Request sent.') + logger.info('Request sent.') except grpc.RpcError as err: - print(err.details()) - print('{}, {}'.format(err.code().name, err.code().value)) + logger.error(err.details()) + logger.error('{}, {}'.format(err.code().name, err.code().value)) if __name__ == '__main__': - print('Client for email service.') \ No newline at end of file + logger.info('Client for email service.') diff --git a/src/emailservice/email_server.py b/src/emailservice/email_server.py index a2cb073..676b70e 100644 --- a/src/emailservice/email_server.py +++ b/src/emailservice/email_server.py @@ -50,6 +50,9 @@ from grpc_health.v1 import health_pb2_grpc # except: # pass +from logger import getJSONLogger +logger = getJSONLogger('emailservice-server') + # Loads confirmation email template from file env = Environment( loader=FileSystemLoader('templates'), @@ -78,14 +81,14 @@ class EmailService(BaseEmailService): "from": { "address_spec": from_address, }, - "to": [{ - "address_spec": email_address + "to": [{ + "address_spec": email_address }], "subject": "Your Confirmation Email", "html_body": content } ) - print("Message sent: {}".format(response.rfc822_message_id)) + logger.info("Message sent: {}".format(response.rfc822_message_id)) def SendOrderConfirmation(self, request, context): email = request.email @@ -95,7 +98,7 @@ class EmailService(BaseEmailService): confirmation = template.render(order = order) except TemplateError as err: context.set_details("An error occurred when preparing the confirmation mail.") - print(err.message) + logger.error(err.message) context.set_code(grpc.StatusCode.INTERNAL) return demo_pb2.Empty() @@ -111,7 +114,7 @@ class EmailService(BaseEmailService): class DummyEmailService(BaseEmailService): def SendOrderConfirmation(self, request, context): - print('A request to send order confirmation email to {} has been received.'.format(request.email)) + logger.info('A request to send order confirmation email to {} has been received.'.format(request.email)) return demo_pb2.Empty() class HealthCheck(): @@ -131,7 +134,7 @@ def start(dummy_mode): health_pb2_grpc.add_HealthServicer_to_server(service, server) port = os.environ.get('PORT', "8080") - print("listening on port: "+port) + logger.info("listening on port: "+port) server.add_insecure_port('[::]:'+port) server.start() try: @@ -142,5 +145,5 @@ def start(dummy_mode): if __name__ == '__main__': - print('starting the email service in dummy mode.') + logger.info('starting the email service in dummy mode.') start(dummy_mode = True) diff --git a/src/emailservice/logger.py b/src/emailservice/logger.py new file mode 100644 index 0000000..a7fb527 --- /dev/null +++ b/src/emailservice/logger.py @@ -0,0 +1,40 @@ +#!/usr/bin/python +# +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import sys +from pythonjsonlogger import jsonlogger + +# TODO(yoshifumi) this class is duplicated since other Python services are +# not sharing the modules for logging. +class CustomJsonFormatter(jsonlogger.JsonFormatter): + def add_fields(self, log_record, record, message_dict): + super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict) + if not log_record.get('timestamp'): + log_record['timestamp'] = record.created + if log_record.get('severity'): + log_record['severity'] = log_record['severity'].upper() + else: + log_record['severity'] = record.levelname + +def getJSONLogger(name): + logger = logging.getLogger(name) + handler = logging.StreamHandler(sys.stdout) + formatter = CustomJsonFormatter('(timestamp) (severity) (name) (message)') + handler.setFormatter(formatter) + logger.addHandler(handler) + logger.setLevel(logging.INFO) + return logger diff --git a/src/emailservice/requirements.txt b/src/emailservice/requirements.txt index ca3f1c3..37f6f10 100644 --- a/src/emailservice/requirements.txt +++ b/src/emailservice/requirements.txt @@ -32,10 +32,11 @@ pycairo==1.17.1 pycparser==2.19 pycrypto==2.6.1 PyGObject==3.30.1 +python-json-logger==0.1.9 pytz==2018.5 pyxdg==0.26 requests==2.19.1 rsa==4.0 SecretStorage==3.1.0 six==1.11.0 -urllib3==1.23 \ No newline at end of file +urllib3==1.23 diff --git a/src/paymentservice/charge.js b/src/paymentservice/charge.js index a0151ed..ce9674a 100644 --- a/src/paymentservice/charge.js +++ b/src/paymentservice/charge.js @@ -14,6 +14,15 @@ const cardValidator = require('simple-card-validator'); const uuid = require('uuid/v4'); +const pino = require('pino'); + +const logger = pino({ + name: 'paymentservice-charge', + messageKey: 'message', + changeLevelName: 'severity', + useLevelLabels: true +}); + class CreditCardError extends Error { constructor (message) { @@ -67,7 +76,7 @@ module.exports = function charge (request) { const { credit_card_expiration_year: year, credit_card_expiration_month: month } = creditCard; if ((currentYear * 12 + currentMonth) > (year * 12 + month)) { throw new ExpiredCreditCard(cardNumber.replace('-', ''), month, year); } - console.log(`Transaction processed: ${cardType} ending ${cardNumber.substr(-4)} \ + logger.info(`Transaction processed: ${cardType} ending ${cardNumber.substr(-4)} \ Amount: ${amount.currency_code}${amount.units}.${amount.nanos}`); return { transaction_id: uuid() }; diff --git a/src/paymentservice/package-lock.json b/src/paymentservice/package-lock.json index f7d35a4..7d0e682 100644 --- a/src/paymentservice/package-lock.json +++ b/src/paymentservice/package-lock.json @@ -700,16 +700,36 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" }, + "fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==" + }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fast-redact": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-1.2.0.tgz", + "integrity": "sha512-k/uSk9PtFmvYx0m7bRk5B2gZChQk4euWhrn7Mf3vYSmwZBLh7cGNuMuc/vhH1MKMPyVJMMtl9oMwPnwlKqs7CQ==" + }, + "fast-safe-stringify": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", + "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==" + }, "findit2": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/findit2/-/findit2-2.2.3.tgz", "integrity": "sha1-WKRmaX34piBc39vzlVNri9d3pfY=" }, + "flatstr": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.8.tgz", + "integrity": "sha512-YXblbv/vc1zuVVUtnKl1hPqqk7TalZCppnKE7Pr8FI/Rp48vzckS/4SJ4Y9O9RNiI82Vcw/FydmtqdQOg1Dpqw==" + }, "follow-redirects": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.1.tgz", @@ -1592,6 +1612,26 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, + "pino": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/pino/-/pino-5.6.2.tgz", + "integrity": "sha512-JVMYqJkE58b2u5+t85zJLbUDOhoWDjEQqrRY1eQzuR4Ub9RIyUSQJms4deT8Joy+C/QIdrrie7NffgCm+ao9xw==", + "requires": { + "fast-json-parse": "^1.0.3", + "fast-redact": "^1.2.0", + "fast-safe-stringify": "^2.0.6", + "flatstr": "^1.0.5", + "pino-std-serializers": "^2.2.1", + "pump": "^3.0.0", + "quick-format-unescaped": "^3.0.0", + "sonic-boom": "^0.6.1" + } + }, + "pino-std-serializers": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-2.2.1.tgz", + "integrity": "sha512-QqL7kkF7eMCpFG4hpZD8UPQga/kxkkh3E62HzMzTIL4OQyijyisAnBL8msBEAml8xcb/ioGhH7UUzGxuHqczhQ==" + }, "pretty-ms": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-3.2.0.tgz", @@ -1621,6 +1661,15 @@ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", @@ -1631,6 +1680,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, + "quick-format-unescaped": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-3.0.0.tgz", + "integrity": "sha512-XmIOc07VM2kPm6m3j/U6jgxyUgDm2Rgh2c1PPy0JUHoQRdoh86hOym0bHyF6G1T6sn+N5lildhvl/T59H5KVyA==" + }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", @@ -1728,6 +1782,14 @@ "resolved": "https://registry.npmjs.org/simple-card-validator/-/simple-card-validator-1.1.0.tgz", "integrity": "sha1-675uRp/q7Cy7SBX4Qyu+BMccNvk=" }, + "sonic-boom": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-0.6.1.tgz", + "integrity": "sha512-3qx6XXDeG+hPNa+jla1H6BMBLcjLl8L8NRERLVeIf/EuPqoqmq4K8owG29Xu7OypT/7/YT/0uKW6YitsKA+nLQ==", + "requires": { + "flatstr": "^1.0.5" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/src/paymentservice/package.json b/src/paymentservice/package.json index c62033b..b977be4 100644 --- a/src/paymentservice/package.json +++ b/src/paymentservice/package.json @@ -16,6 +16,7 @@ "@google-cloud/trace-agent": "^2.11.0", "@grpc/proto-loader": "^0.1.0", "grpc": "^1.12.3", + "pino": "^5.6.2", "simple-card-validator": "^1.1.0", "uuid": "^3.2.1" }, diff --git a/src/paymentservice/server.js b/src/paymentservice/server.js index ebce323..11598b7 100644 --- a/src/paymentservice/server.js +++ b/src/paymentservice/server.js @@ -14,10 +14,18 @@ const path = require('path'); const grpc = require('grpc'); +const pino = require('pino'); const protoLoader = require('@grpc/proto-loader'); const charge = require('./charge'); +const logger = pino({ + name: 'paymentservice-server', + messageKey: 'message', + changeLevelName: 'severity', + useLevelLabels: true +}); + class HipsterShopServer { constructor (protoRoot, port = HipsterShopServer.DEFAULT_PORT) { this.port = port; @@ -38,7 +46,7 @@ class HipsterShopServer { */ static ChargeServiceHandler (call, callback) { try { - console.log(`PaymentService#Charge invoked with request ${JSON.stringify(call.request)}`); + logger.info(`PaymentService#Charge invoked with request ${JSON.stringify(call.request)}`); const response = charge(call.request); callback(null, response); } catch (err) { @@ -53,7 +61,7 @@ class HipsterShopServer { listen () { this.server.bind(`0.0.0.0:${this.port}`, grpc.ServerCredentials.createInsecure()); - console.log(`PaymentService grpc server listening on ${this.port}`); + logger.info(`PaymentService grpc server listening on ${this.port}`); this.server.start(); } diff --git a/src/recommendationservice/client.py b/src/recommendationservice/client.py index d24afee..7894886 100644 --- a/src/recommendationservice/client.py +++ b/src/recommendationservice/client.py @@ -14,15 +14,18 @@ # See the License for the specific language governing permissions and # limitations under the License. +import sys import grpc import demo_pb2 import demo_pb2_grpc -import sys from opencensus.trace.tracer import Tracer from opencensus.trace.exporters import stackdriver_exporter from opencensus.trace.ext.grpc import client_interceptor +from logger import getJSONLogger +logger = getJSONLogger('recommendationservice-server') + if __name__ == "__main__": # get port if len(sys.argv) > 1: @@ -45,4 +48,4 @@ if __name__ == "__main__": request = demo_pb2.ListRecommendationsRequest(user_id="test", product_ids=["test"]) # make call to server response = stub.ListRecommendations(request) - print(response) \ No newline at end of file + logger.info(response) diff --git a/src/recommendationservice/logger.py b/src/recommendationservice/logger.py new file mode 100644 index 0000000..a7fb527 --- /dev/null +++ b/src/recommendationservice/logger.py @@ -0,0 +1,40 @@ +#!/usr/bin/python +# +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import sys +from pythonjsonlogger import jsonlogger + +# TODO(yoshifumi) this class is duplicated since other Python services are +# not sharing the modules for logging. +class CustomJsonFormatter(jsonlogger.JsonFormatter): + def add_fields(self, log_record, record, message_dict): + super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict) + if not log_record.get('timestamp'): + log_record['timestamp'] = record.created + if log_record.get('severity'): + log_record['severity'] = log_record['severity'].upper() + else: + log_record['severity'] = record.levelname + +def getJSONLogger(name): + logger = logging.getLogger(name) + handler = logging.StreamHandler(sys.stdout) + formatter = CustomJsonFormatter('(timestamp) (severity) (name) (message)') + handler.setFormatter(formatter) + logger.addHandler(handler) + logger.setLevel(logging.INFO) + return logger diff --git a/src/recommendationservice/recommendation_server.py b/src/recommendationservice/recommendation_server.py index b897f73..09e6e0d 100644 --- a/src/recommendationservice/recommendation_server.py +++ b/src/recommendationservice/recommendation_server.py @@ -18,8 +18,8 @@ import grpc from concurrent import futures import time import traceback -import random import os +import random import googleclouddebugger import demo_pb2 @@ -27,6 +27,8 @@ import demo_pb2_grpc from grpc_health.v1 import health_pb2 from grpc_health.v1 import health_pb2_grpc +from logger import getJSONLogger +logger = getJSONLogger('recommendationservice-server') # TODO(morganmclean,ahmetb) tracing currently disabled due to memory leak (see TODO below) # from opencensus.trace.ext.grpc import server_interceptor @@ -47,7 +49,7 @@ class RecommendationService(demo_pb2_grpc.RecommendationServiceServicer): indices = random.sample(range(num_products), num_return) # fetch product ids from indices prod_list = [filtered_products[i] for i in indices] - print("[Recv ListRecommendations] product_ids={}".format(prod_list)) + logger.info("[Recv ListRecommendations] product_ids={}".format(prod_list)) # build and return response response = demo_pb2.ListRecommendationsResponse() response.product_ids.extend(prod_list) @@ -59,7 +61,7 @@ class RecommendationService(demo_pb2_grpc.RecommendationServiceServicer): if __name__ == "__main__": - print("initializing recommendationservice") + logger.info("initializing recommendationservice") # TODO(morganmclean,ahmetb) enabling the tracing interceptor/sampler below # causes an unbounded memory leak eventually OOMing the container. @@ -77,15 +79,15 @@ if __name__ == "__main__": version='1.0.0' ) except Exception, err: - print("could not enable debugger") - traceback.print_exc() + logger.error("could not enable debugger") + logger.error(traceback.print_exc()) pass port = os.environ.get('PORT', "8080") catalog_addr = os.environ.get('PRODUCT_CATALOG_SERVICE_ADDR', '') if catalog_addr == "": raise Exception('PRODUCT_CATALOG_SERVICE_ADDR environment variable not set') - print("product catalog address: " + catalog_addr) + logger.info("product catalog address: " + catalog_addr) channel = grpc.insecure_channel(catalog_addr) product_catalog_stub = demo_pb2_grpc.ProductCatalogServiceStub(channel) @@ -98,7 +100,7 @@ if __name__ == "__main__": health_pb2_grpc.add_HealthServicer_to_server(service, server) # start server - print("listening on port: " + port) + logger.info("listening on port: " + port) server.add_insecure_port('[::]:'+port) server.start() diff --git a/src/recommendationservice/requirements.txt b/src/recommendationservice/requirements.txt index 470d93c..7e77517 100644 --- a/src/recommendationservice/requirements.txt +++ b/src/recommendationservice/requirements.txt @@ -20,6 +20,7 @@ opencensus==0.1.5 protobuf==3.5.2.post1 pyasn1==0.4.3 pyasn1-modules==0.2.2 +python-json-logger==0.1.9 pytz==2018.5 PyYAML==3.13 requests==2.19.1 From 571285d9aa497153253bcc908d0a59edf59a8549 Mon Sep 17 00:00:00 2001 From: Colin Nelson Date: Tue, 9 Oct 2018 10:42:49 -0700 Subject: [PATCH 15/91] Optimized adservice Image Size (#67) * adservice: Reduced docker image size to ~165MB (down from ~886MB) by switching to alpine and using multi stage builds * adservice: Changed install of glibc in builder to not require untrusted packages * adservice: Refactored Dockerfile to be a multi stage build. The 'build' step runs from openjdk:8-slim, but the final image is alpine based. We can get away from this since java runs in a vm & the architecture of the images doesn't change between biuld steps --- src/adservice/Dockerfile | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/adservice/Dockerfile b/src/adservice/Dockerfile index 1095220..78b0452 100644 --- a/src/adservice/Dockerfile +++ b/src/adservice/Dockerfile @@ -1,16 +1,22 @@ -FROM openjdk:8 -RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ - wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ - chmod +x /bin/grpc_health_probe +FROM openjdk:8-slim as builder + WORKDIR /app -# Next three steps are for caching dependency downloads -# to improve subsequent docker build. COPY ["build.gradle", "gradlew", "./"] COPY gradle gradle RUN ./gradlew downloadRepos COPY . . RUN ./gradlew installDist + +FROM openjdk:8-alpine + +RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ + wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ + chmod +x /bin/grpc_health_probe + +WORKDIR /app +COPY --from=builder /app . + EXPOSE 9555 ENTRYPOINT ["/app/build/install/hipstershop/bin/AdService"] From 34227a64a6f9125e4728bd94ff1e71cdc409136b Mon Sep 17 00:00:00 2001 From: Colin Nelson Date: Tue, 9 Oct 2018 10:43:06 -0700 Subject: [PATCH 16/91] currencyservice: Optimized Docker image with multi stage builds, and using alpine as a base image. (#70) --- src/currencyservice/Dockerfile | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/currencyservice/Dockerfile b/src/currencyservice/Dockerfile index 769e464..7529674 100644 --- a/src/currencyservice/Dockerfile +++ b/src/currencyservice/Dockerfile @@ -1,10 +1,32 @@ -FROM node:8 +FROM node:8-alpine as base + +FROM base as builder + +# Some packages (e.g. @google-cloud/profiler) require additional +# deps for post-install scripts +RUN apk add --update --no-cache \ + python \ + make \ + g++ + +WORKDIR /usr/src/app + +COPY package*.json ./ + +RUN npm install --only=production + +FROM base + RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe + WORKDIR /usr/src/app -COPY package*.json ./ -RUN npm install --only=production + +COPY --from=builder /usr/src/app/node_modules ./node_modules + COPY . . + EXPOSE 7000 -CMD [ "node", "server.js" ] + +ENTRYPOINT [ "node", "server.js" ] \ No newline at end of file From c6b825f846a58cf46b3eddcab1de0d392d0aa88a Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Tue, 9 Oct 2018 10:52:47 -0700 Subject: [PATCH 17/91] Run skaffold fix (#72) Upgrade skaffold version + manifest. --- .travis.yml | 2 +- skaffold.yaml | 49 ++++++++++++++++++++++++------------------------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/.travis.yml b/.travis.yml index c79b0c2..d2db4fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ services: - docker install: -- curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v0.12.0/skaffold-linux-amd64 +- curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v0.15.1/skaffold-linux-amd64 - chmod +x skaffold - sudo mv skaffold /usr/local/bin diff --git a/skaffold.yaml b/skaffold.yaml index 9bf9d46..ffa25c2 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -12,11 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: skaffold/v1alpha2 +apiVersion: skaffold/v1alpha3 kind: Config build: - tagPolicy: - gitCommit: {} artifacts: - imageName: gcr.io/microservices-demo-app/emailservice workspace: src/emailservice @@ -40,30 +38,31 @@ build: workspace: src/loadgenerator - imageName: gcr.io/microservices-demo-app/adservice workspace: src/adservice + tagPolicy: + gitCommit: {} deploy: kubectl: manifests: - ./kubernetes-manifests/**.yaml - - profiles: - # "travis-ci" profile is used to build the images without - # pushing them. - - name: travis-ci - build: - local: - skipPush: true - # "gcb" profile allows building and pushing the images - # on Google Container Builder without requiring docker - # installed on the developer machine. However, note that - # since GCB does not cache the builds, each build will - # start from scratch and therefore take a long time. - # - # This is not used by default. To use it, run: - # skaffold run -p gcb - - name: gcb - build: - googleCloudBuild: - diskSizeGb: 300 - machineType: "N1_HIGHCPU_32" - timeout: 4000s +# "travis-ci" profile is used to build the images withou +# pushing them. +- name: travis-ci + build: + local: + skipPush: true +# "gcb" profile allows building and pushing the images +# on Google Container Builder without requiring docker +# installed on the developer machine. However, note that +# since GCB does not cache the builds, each build will +# start from scratch and therefore take a long time. +# +# This is not used by default. To use it, run: +# skaffold run -p gcb +- name: gcb + build: + googleCloudBuild: + projectId: "" + diskSizeGb: 300 + machineType: N1_HIGHCPU_32 + timeout: 4000s From dd0e26806df53d88a05302389e6678dc25ba86e3 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Tue, 9 Oct 2018 11:50:14 -0700 Subject: [PATCH 18/91] README: add istio mTLS instructions (#73) Signed-off-by: Ahmet Alp Balkan --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aa6709b..72a7a09 100644 --- a/README.md +++ b/README.md @@ -138,8 +138,14 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). 1. Create a GKE cluster. -2. Install Istio **without mutual TLS** option. (Istio mTLS is not yet supported - on this demo.) +2. Install Istio **without mutual TLS** authentication option. + + > (Optional) If you'd like to enable mTLS in the demo app, you need to + > make a few changes to the deployment manifests: + > + > - `kubernetes-manifests/frontend.yaml`: delete "livenessProbe" and + > "readinessProbe" fields. + > - `kubernetes-manifests/loadgenerator.yaml`: delete "initContainers" field. 3. Install the automatic sidecar injection (annotate the `default` namespace with the label): From 3b6d3864a0fa66495faa6b9803078710d1013398 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Tue, 9 Oct 2018 15:54:55 -0700 Subject: [PATCH 19/91] grpc: bump health-probe to v0.2.0 (#71) Signed-off-by: Ahmet Alp Balkan --- src/adservice/Dockerfile | 2 +- src/cartservice/Dockerfile | 2 +- src/checkoutservice/Dockerfile | 2 +- src/currencyservice/Dockerfile | 4 ++-- src/emailservice/Dockerfile | 2 +- src/paymentservice/Dockerfile | 2 +- src/productcatalogservice/Dockerfile | 2 +- src/recommendationservice/Dockerfile | 2 +- src/shippingservice/Dockerfile | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/adservice/Dockerfile b/src/adservice/Dockerfile index 78b0452..7b41366 100644 --- a/src/adservice/Dockerfile +++ b/src/adservice/Dockerfile @@ -11,7 +11,7 @@ RUN ./gradlew installDist FROM openjdk:8-alpine -RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ +RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe diff --git a/src/cartservice/Dockerfile b/src/cartservice/Dockerfile index eae7f06..ad2b1c3 100644 --- a/src/cartservice/Dockerfile +++ b/src/cartservice/Dockerfile @@ -8,7 +8,7 @@ RUN dotnet restore && \ # cartservice FROM alpine:3.8 -RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ +RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe diff --git a/src/checkoutservice/Dockerfile b/src/checkoutservice/Dockerfile index 4f6e616..6099109 100644 --- a/src/checkoutservice/Dockerfile +++ b/src/checkoutservice/Dockerfile @@ -15,7 +15,7 @@ RUN go build -gcflags='-N -l' -o /checkoutservice . FROM alpine as release RUN apk add --no-cache ca-certificates -RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ +RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe COPY --from=builder /checkoutservice /checkoutservice diff --git a/src/currencyservice/Dockerfile b/src/currencyservice/Dockerfile index 7529674..1e60cab 100644 --- a/src/currencyservice/Dockerfile +++ b/src/currencyservice/Dockerfile @@ -17,7 +17,7 @@ RUN npm install --only=production FROM base -RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ +RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe @@ -29,4 +29,4 @@ COPY . . EXPOSE 7000 -ENTRYPOINT [ "node", "server.js" ] \ No newline at end of file +ENTRYPOINT [ "node", "server.js" ] diff --git a/src/emailservice/Dockerfile b/src/emailservice/Dockerfile index 5a1bb22..7aa7ec1 100644 --- a/src/emailservice/Dockerfile +++ b/src/emailservice/Dockerfile @@ -26,7 +26,7 @@ FROM base as final ENV PYTHONUNBUFFERED=1 # Download the grpc health probe -RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ +RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe diff --git a/src/paymentservice/Dockerfile b/src/paymentservice/Dockerfile index 5785d35..722bb47 100644 --- a/src/paymentservice/Dockerfile +++ b/src/paymentservice/Dockerfile @@ -17,7 +17,7 @@ RUN npm install --only=production FROM base -RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ +RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe diff --git a/src/productcatalogservice/Dockerfile b/src/productcatalogservice/Dockerfile index f941605..82deb04 100644 --- a/src/productcatalogservice/Dockerfile +++ b/src/productcatalogservice/Dockerfile @@ -15,7 +15,7 @@ RUN go build -o /productcatalogservice . FROM alpine AS release RUN apk add --no-cache ca-certificates -RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ +RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe WORKDIR /productcatalogservice diff --git a/src/recommendationservice/Dockerfile b/src/recommendationservice/Dockerfile index 881f12a..3faff32 100644 --- a/src/recommendationservice/Dockerfile +++ b/src/recommendationservice/Dockerfile @@ -6,7 +6,7 @@ RUN apt-get update -qqy && \ ENV PYTHONUNBUFFERED=0 # download the grpc health probe -RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ +RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe diff --git a/src/shippingservice/Dockerfile b/src/shippingservice/Dockerfile index ef44642..2b80a7e 100644 --- a/src/shippingservice/Dockerfile +++ b/src/shippingservice/Dockerfile @@ -14,7 +14,7 @@ RUN go install . FROM alpine as release RUN apk add --no-cache ca-certificates -RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \ +RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe COPY --from=builder /go/bin/shippingservice /shippingservice From 51da4930aef87c5a1192824407c9b76b5ef8e330 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Mon, 15 Oct 2018 09:03:28 -0700 Subject: [PATCH 20/91] Fix build for skaffold 0.16 (#77) Closes #76. --- .travis.yml | 2 +- skaffold.yaml | 49 ++++++++++++++++++++++++------------------------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/.travis.yml b/.travis.yml index d2db4fa..4850744 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ services: - docker install: -- curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v0.15.1/skaffold-linux-amd64 +- curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v0.16.0/skaffold-linux-amd64 - chmod +x skaffold - sudo mv skaffold /usr/local/bin diff --git a/skaffold.yaml b/skaffold.yaml index ffa25c2..b1cd87e 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -12,32 +12,32 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: skaffold/v1alpha3 +apiVersion: skaffold/v1alpha4 kind: Config build: artifacts: - - imageName: gcr.io/microservices-demo-app/emailservice - workspace: src/emailservice - - imageName: gcr.io/microservices-demo-app/productcatalogservice - workspace: src/productcatalogservice - - imageName: gcr.io/microservices-demo-app/recommendationservice - workspace: src/recommendationservice - - imageName: gcr.io/microservices-demo-app/shippingservice - workspace: src/shippingservice - - imageName: gcr.io/microservices-demo-app/checkoutservice - workspace: src/checkoutservice - - imageName: gcr.io/microservices-demo-app/paymentservice - workspace: src/paymentservice - - imageName: gcr.io/microservices-demo-app/currencyservice - workspace: src/currencyservice - - imageName: gcr.io/microservices-demo-app/cartservice - workspace: src/cartservice - - imageName: gcr.io/microservices-demo-app/frontend - workspace: src/frontend - - imageName: gcr.io/microservices-demo-app/loadgenerator - workspace: src/loadgenerator - - imageName: gcr.io/microservices-demo-app/adservice - workspace: src/adservice + - image: gcr.io/microservices-demo-app/emailservice + context: src/emailservice + - image: gcr.io/microservices-demo-app/productcatalogservice + context: src/productcatalogservice + - image: gcr.io/microservices-demo-app/recommendationservice + context: src/recommendationservice + - image: gcr.io/microservices-demo-app/shippingservice + context: src/shippingservice + - image: gcr.io/microservices-demo-app/checkoutservice + context: src/checkoutservice + - image: gcr.io/microservices-demo-app/paymentservice + context: src/paymentservice + - image: gcr.io/microservices-demo-app/currencyservice + context: src/currencyservice + - image: gcr.io/microservices-demo-app/cartservice + context: src/cartservice + - image: gcr.io/microservices-demo-app/frontend + context: src/frontend + - image: gcr.io/microservices-demo-app/loadgenerator + context: src/loadgenerator + - image: gcr.io/microservices-demo-app/adservice + context: src/adservice tagPolicy: gitCommit: {} deploy: @@ -50,7 +50,7 @@ profiles: - name: travis-ci build: local: - skipPush: true + push: false # "gcb" profile allows building and pushing the images # on Google Container Builder without requiring docker # installed on the developer machine. However, note that @@ -62,7 +62,6 @@ profiles: - name: gcb build: googleCloudBuild: - projectId: "" diskSizeGb: 300 machineType: N1_HIGHCPU_32 timeout: 4000s From a815e029ab9565ac3c245cac6d6c473d6ca009e3 Mon Sep 17 00:00:00 2001 From: davidstanke Date: Tue, 16 Oct 2018 16:25:57 -0400 Subject: [PATCH 21/91] Add GCB cloudbuild.yaml config for CD to staging (#79) --- cloudbuild.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 cloudbuild.yaml diff --git a/cloudbuild.yaml b/cloudbuild.yaml new file mode 100644 index 0000000..9992da2 --- /dev/null +++ b/cloudbuild.yaml @@ -0,0 +1,17 @@ +# Cloudbuild.yaml to deploy to prod +# +# PREREQUISITES: +# Skaffold builder image must be present in this project's container registry +# (see https://github.com/GoogleCloudPlatform/cloud-builders-community/tree/master/skaffold) +# +# Cloud Build service account must have "Kubernetes Engine Developer" role + +steps: +- name: gcr.io/$PROJECT_ID/skaffold + args: ['run', '-f=skaffold.yaml'] + env: + - 'CLOUDSDK_COMPUTE_ZONE=us-central1-b' + - 'CLOUDSDK_CONTAINER_CLUSTER=demo-app-staging' +timeout: 1800s +options: # Add more power, and more time, for heavy Skaffold build + machineType: 'N1_HIGHCPU_8' \ No newline at end of file From 73ebd4debbdb15bc13a976124b96340bb2eb9ed0 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Wed, 17 Oct 2018 15:15:28 -0700 Subject: [PATCH 22/91] use stock gcb image for skaffold (#81) cc: @davidstanke --- cloudbuild.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 9992da2..bd3e4cc 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -1,17 +1,17 @@ -# Cloudbuild.yaml to deploy to prod +# This file is used to build and deploy the app into a GKE cluster using Google +# Cloud Build. # -# PREREQUISITES: -# Skaffold builder image must be present in this project's container registry -# (see https://github.com/GoogleCloudPlatform/cloud-builders-community/tree/master/skaffold) -# -# Cloud Build service account must have "Kubernetes Engine Developer" role +# Requirements: +# - Give the Google Cloud Build service account "Kubernetes Engine Developer" +# IAM role on the GCP project. +# - Set up Google Cloud Build trigger on Cloud Console. steps: -- name: gcr.io/$PROJECT_ID/skaffold - args: ['run', '-f=skaffold.yaml'] +- name: gcr.io/k8s-skaffold/skaffold:v0.16.0 + args: ['skaffold', 'run', '-f=skaffold.yaml'] env: - 'CLOUDSDK_COMPUTE_ZONE=us-central1-b' - 'CLOUDSDK_CONTAINER_CLUSTER=demo-app-staging' timeout: 1800s options: # Add more power, and more time, for heavy Skaffold build - machineType: 'N1_HIGHCPU_8' \ No newline at end of file + machineType: 'N1_HIGHCPU_8' From 781b6df8a057eb347e430f8bb4da4aad07acb6fe Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Mon, 22 Oct 2018 10:03:38 -0700 Subject: [PATCH 23/91] Update README.md --- src/adservice/README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/adservice/README.md b/src/adservice/README.md index 6d41ec3..ca1fc73 100644 --- a/src/adservice/README.md +++ b/src/adservice/README.md @@ -2,23 +2,25 @@ The Ad service provides advertisement based on context keys. If no context keys are provided then it returns random ads. -## Local Build +## Building locally + +The Ad service uses gradlew to compile/install/distribute. Gradle wrapper is already part of the source code. To build Ad Service, run: -The Ad service uses gradlew to compile/install/distribute. Gradle wrapper is already part of the source code. To build Ad Service, run ``` - cd src/adservice; ./gradlew installDist +./gradlew installDist ``` It will create executable script src/adservice/build/install/hipstershop/bin/AdService -### Upgrade gradle version +### Upgrading gradle version If you need to upgrade the version of gradle then run + ``` - cd src/adservice ; ./gradlew wrapper --gradle-version +./gradlew wrapper --gradle-version ``` -## Docker Build +## Building docker image -From repository root, run: +From the repository root, run: ``` docker build --file src/adservice/Dockerfile . From a79a4438929374e222d283b3cf85a04b7eb58bef Mon Sep 17 00:00:00 2001 From: Colin Nelson Date: Tue, 23 Oct 2018 14:44:29 -0700 Subject: [PATCH 24/91] Ignore .vs (#86) Fixes #83 --- .gitignore | 3 +-- .../.vs/cartservice/DesignTimeBuild/.dtbcache | Bin 542302 -> 0 bytes src/cartservice/.vs/cartservice/v15/.suo | Bin 5120 -> 0 bytes .../.vs/cartservice/v15/Server/sqlite3/db.lock | 0 .../cartservice/v15/Server/sqlite3/storage.ide | Bin 4096 -> 0 bytes .../v15/Server/sqlite3/storage.ide-shm | Bin 32768 -> 0 bytes .../v15/Server/sqlite3/storage.ide-wal | Bin 972352 -> 0 bytes 7 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 src/cartservice/.vs/cartservice/DesignTimeBuild/.dtbcache delete mode 100644 src/cartservice/.vs/cartservice/v15/.suo delete mode 100644 src/cartservice/.vs/cartservice/v15/Server/sqlite3/db.lock delete mode 100644 src/cartservice/.vs/cartservice/v15/Server/sqlite3/storage.ide delete mode 100644 src/cartservice/.vs/cartservice/v15/Server/sqlite3/storage.ide-shm delete mode 100644 src/cartservice/.vs/cartservice/v15/Server/sqlite3/storage.ide-wal diff --git a/.gitignore b/.gitignore index 2952864..60433d6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,7 @@ pkg/ *.swp *~ .vscode/ -.vs/slnx.sqlite -.vs/microservices-demo/v15/.suo +.vs/ .idea .skaffold-*.yaml .kubernetes-manifests-*/ diff --git a/src/cartservice/.vs/cartservice/DesignTimeBuild/.dtbcache b/src/cartservice/.vs/cartservice/DesignTimeBuild/.dtbcache deleted file mode 100644 index bfe1ed84ce2953ee07a4cdaf41c2fb10245dd136..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 542302 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 W)i{_qS<=s|>@aVbhj3!M@85Uel(Dk_ diff --git a/src/cartservice/.vs/cartservice/v15/Server/sqlite3/db.lock b/src/cartservice/.vs/cartservice/v15/Server/sqlite3/db.lock deleted file mode 100644 index e69de29..0000000 diff --git a/src/cartservice/.vs/cartservice/v15/Server/sqlite3/storage.ide b/src/cartservice/.vs/cartservice/v15/Server/sqlite3/storage.ide deleted file mode 100644 index 56758a88b356f5fc284d2b23256cb2a77affde45..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4096 zcmWFz^vNtqRY=P(%1ta$FlG>7U}9o$P*7lCU|@t|AVoG{WYA-Exj6ruvcXxM6cPa`}(ik9}1||lG4cHhoHg*S!t^5Vv=(A@H zF0PpOTZ_-{X79D0bq3}+d!Kpddfs2wsX7^(qL3$(DR!FIkae;5D*VGs<4Autq%!8I@(M!-lI1*2gMjD>M9 z9wxv=06KsYpuobq!9dIYy1$V=CxCicqJdhs>fc*~b z_tXyTXR^<2w{6#ba6dc%55f+32p)z<;8EBKyWla{4UfYU@FYA1Ps20tEbM{3un(St z=i%(nQiy+_{dw#&yZ|r4OYkzh0{h`rcnw~MH{bvqghOx`j=)hk2FJn26YvB)0Z+ga z@B};oPrwuK1Uvyxz!UHUJONL@6YvB)0Z+ga@B};oPrwuK1Uvyxz!UHUJONL@6YvB) z0Z+ga@B};oPrwuK1Uvyxz!UHUJONL@6YvB)0Z+ga@B};oPrwuK1X3noe_5S!+RDf6 z@1;|Y{aw2@ziC>aRa5ruui8`2VEOnvvKb=gp=Y81T@Xd+bJ&ylM9BXdV=Cq~-T6JaLdfQUY zaQXNLvKb;4qP1{e<}=|f)?AlzI?Knc!!G4mXJN{zCm*-Q!jv;YKK`L>hKPk_d8KT| z5xdB1t-UejSX*bxsV^V54$hP_Qa=8XY=($MX{-HQdV@8krkt+waqBHjIkQt9=XL}6 zzO~P$oKf=ek7YANEF;U-5u9?m$;Yj+H|1DEbINHbAGhA+lrvgB{*7#gh-GDYb#_0r zteswNlPR`S_2r86sAe z<&Cl#N9-%FJt~`V#D#Iz%3E8==1$p+BTkano|4TFv5G8jlFc|`KY8sj*^DDDinCVU z+EO-m@pQwlW&8Y#ljW5^$!3UHRhBo)W*o7VR=+J-q0+xFL+IZC diff --git a/src/cartservice/.vs/cartservice/v15/Server/sqlite3/storage.ide-wal b/src/cartservice/.vs/cartservice/v15/Server/sqlite3/storage.ide-wal deleted file mode 100644 index 854c462721b62b844e81ff6328e75deb71a600ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 972352 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

oHhcS_~el|9fD4Q9A?hX z3*3F`jJgxA+D-P56UqeeY(#KZWyAN0bEi82z(jrm@BwaMd?@S z!dLQRM_c)TDY)0Fba+zS%`XgaxL(ZclC#6B;z5fEn`pQ)B<)!UtEA17h3)ZdVy<>8 z-YIEzqM2f9?SFnqrm2y)EWy-+r491rW>DaMZ zITqI1TT}|>Ni2VQm=-ZpJmq0QI|cW6;%}xv3cHT2tx0*vd)mlKICr!^?MQXYcg z$ec+3AfK&u#VH0kf_OQX-79P-l`84Q1j&A{EO;i&o^wh)IDKY#D#Z@Amb8V%%hr`* zm?fZAbYQ_8FI!xC!N2 zLo*47MsR1m3l5E6<>~d{vTUYn#z`;t5ao@g7R(lTU{7 zW_|kZaz6@vUhjpiUyCzNz>mHO{T})b^jGL}(1*j(2jZPi-v|f2Rbcxm(3kqOenPE+ zYXtPW=wG)Ak^f1poty}&K%X6JqU6fA7blZTyX*xw9Sn;-Kr45c=Stj~8w82hDj} zTOK{4mx`u*NpG{@oIv;%(Hlftdr@~T7ma-Qq4$Vx&@b*1!M+kY=f{Vi@E3@tFAcp- z@a6!2uju#q{6f7u&=~hnw{e7jUbL;x(BBkIpC1SPE78;!9Q0%r1mg!B^mNfSKhO(A z+x$SECED7%PjrW9Yv1jnxA^=*y|MK*qOCrJr$k$OKpzxMeImcmcZjy-y+ia}qOCsA z_lvgaK|d6T5B<-g?enoy^k+n)KMwlqKEI`ZEZW+Ga1sylA0zrW{N)HgO>~g|Y|&Of z!Y>w0`s4?Cr)ZvC9Bs*!qOCmW5z(|!IOy9&(}ocr`uU=%pSa5e_ll-|;Go|j+S&v9 z!=kOdp}!!S^1?xXRW$a-LI00vt3UJ~L|c8KnM1Mmgl-XS^A9~wbTGY@CE@U(ANe6& zRX?wN6`Pk1X`vr^q#n}tQa|v+PNa=|WKb>ue&~Rmju#MjrU1Va1muS??hL_l0cj~) zo(yD@CbH279^}mvz|$@uy)*q^RS%C3nWRk{jf~R;_;m?LA6?M>Gy%GwB_LhKu%w4f z^2a-c_zWgV_f!G=O9aR{Lx4ZLDWLq;3*hJ3fq#wwdo2|pf3AS^+63rzu>d`L1k|yu{_iFF zr98s|fyZ1L%C{UUFh0C~Lv_<8myd)gGjX`AFQU4CBR3$Odw?LQf7_$_|w zX4#d#tT$Mqk9XO)L#5rFWWh z$9>^wCZ%BVXHVF(2RAsFvEjDETPd}|edTm_O{$a=`Q`8>UG2ij`oi&1Gw{qPA5SM% z@V0esrY}8tZZ7XNe;MX8l%hV_j((*aSZ+$5!B;s?DTf(0R@$+A=$si%I`LeTr&eyG zr{*lS%S8O;HGCpYs~tl6F;wo9NKgawUmna3UX|1 zGO16*Rmnw2UDTjyB z5*UptaR%E1!xd~TY^%l-PhFt(s>H=K5Mi|Gl{iXUrg9m!rc7L`DotWgPYjuC(0MMc9{0d zPDmZ9MG7$sC0Lxw#OV`Kx{Z0FwxiTO#5G6xP5m01pzMq;yx~e)d^53Ixx|T8d;onS zy(WGO8p$@i_(}FUK!^B;jwOyx6`gk+I2~~Y2l&z1rL#!~j*jdy0i8F(=|I!TBpe5C zSU@Kc2TdoBxOC{C>CBM^9Yi|l5dob>Xgbup1;nSLyg-ogX~OAv-r&>v@pQRezjP7_ zN4I|zSbdfYe?UM_kq#vE!vb`{(J_9%fcQA*PYK93@}R%z)B5oSB)`(HmESJBT8wmJ zu?IAVxV@gK@KpltU7-_=gXZEi_;JviMUx&jg65F+H2tD41DC95E02yd9|N@dL;r(l z23Y#>I@Yfff}L@c&BsJzZyfaJL?asq{RPns*l^I_7j4sn=0Y@EAE29*QS`+zpqeL| za2)j6qNyjO0lhU4evxQCtY_^Fofb_!QZgavyF?QoxlF+h4uGy_(`q5tI5LcIaw$*M@!p6letq=>Z-1G>$k ziI0Qk1C+t=oM>AN@pzk^sAaqaQM8BPa{(Nu9xuNeAjPHei5^F0@zk1yUuyiC~d% z^08Qee(i#}0-h;kP}h-pzJT(jE}#Q8CA|v-#Jfm<-pEEbbYieg82XR~G&&QHG~k&m zAaCeK7-@i`Ghx^q8FK{4CGVt+d}F*QcNKrhg}DjqK7qt??Sn zz1ah##)MK)V$+yBG$KY`~rUA_^ zB71KklZs4Ev8#v>rXra@XL`_FXl!rmwD*n%d2DQ^vx18%!CgxSC1*s_WhR|s%A|@` z98xof2I7-qy%2gjVr_IA#0@c#5mHtoRIC*C}rqe9l`i|ll9~7YGDv*yV_NBVw>6mxk zChtRV<@4s)(AI&a!YO}j&9IuX2j427+`+Lo<$|rR^l4kBwycqXALYm}nlc6lY<$v1 z-fOl^*M~(vw(lrt4|J-i;=#zORh7;~E>o>5pE0&G{>5tn=AmP|pWSTDT8dd4sI6v4DIWRFx!qD3F8`8N}*2bqbL8FYNr2SERhw`-vpbkb5^lg;$&8!XX1u>;ZFk>pUUEgc((XZqXQ zR<@nlpNQ}3PsXx*q-7wI9%ye{-LFqiMfDXdpLrY1g|7uQ&b(swPrmrmJEQNpZQp0! zJoy{fzGBk5>u+x;isMDu7#qtd{h0Z(tvViEk!)m_4j>lV_MP$UZn16E(c$=kj-jEn zcXDxUJiA|C|LN3sb(7h3iO5jKpj`E2FwR8wCQ`a&M7inI_rCOvTAj8oe3;kw;|Q!? zF~iE5kz;Tjr}TZLb#_$eBRv*A%q#Y!j$dcZO;h^B&7fW=I(F(Y_-7;etd>q<#`F!~ z6v+;FpAX6-`dF{dVk+u^u_B%F2gj31y|iSH&XjIwQK5;;_gNPqwfvdR;sD)$MZOE3 z-jPooEj{36-WOq5>_^R@x|0K2Q}LvZquW!U)+e8k%9`Whe6=abk@koV1?zolzT)KT zoi8<2I(@$=)0gViVe;fqSKP}?Bt6FaxPY5b?|Aq6SZZ5jAU>M$MdfK@Dv?`L8PAA9 zy*Isnx9h7+`UKN%j|QQ@d-NHof_=hkBiZQga7BxRZEedV-dEMUn&};9rS2(%@${JY zStNb1xjUUsrSmqy0+D3K|6Z{U5@+eBQYkE*4sVM^O-XvjGaopXr=Fg0Z#0rj z%2=JF=}Zbvd3ySUb#z$uE!;c0D-+e(e4(m_$&9);sv)|wBo;|~;x>&&dc`o3_3q{w z$djHZTR-iW?L5!E_;4&Ws!wtGpS$xpZCxw&FQ$xAdB2{xKIfd(SLo0wvn8!-zl<=o zCdpW0Yb2{`%=feO*=l91)Q<96r#_tOZ^jGP6Yu?+()Umd>mgpzY>SQP+EEB~du-rb{Feb?I4syC&!FWVDIswvb341AbOtX{=}BI?fF zv7{=J_uTO9D$_ybF*m)*!U^c^y`!{aiI~S8NrM(1Eqx2i`|Q?J9;r5By$i1jv2851 zEBSgDIC7mYkkX>%5unwIOP5sOjl#L?wW8^N_6Y2_1e`Gm{b6wWw~RNyhXVLP;VdWN zf0w}WpQ|n*{2K&+)L;dF;@vA?90UJr1y<%;gg5#AAJDJm;l6LiKk)xXVD+q$KjR+! zX9%}CEEY~*9e>U~vup;=x4~Hg0*?pq8-!c=pHf(p&%;s_aALsp9shc_S>qwqbL3Y0sMoCJ4t@TWeJ?|9r&ZdZMxqH__HhtKeE`9$VJ)eVnw}7mh!6?GE^#81Vmr(#3|ze}5p|9}2g5{B0oJY7K^Mna&h$^Ri61 zwa;wf)+U@yur|3Mz!Mg3^Gi9~^4%WbVF}&Jxkk9PC+7uh-v3kjqXYV{2;}j9#3RzP z^Y4YD+h)O+1h#%oQ@L9n>H_$n;HToZx*ZU1^ZRPyECo|`^-7n41o->pZ}mAr{>Z|A zfpA-Y+JsyCd`kTG*|{?ye~ox-9@h%D&*|%Bf6Ko~{#J)C%HQIgNw;Ywgj;Si3TsNUFLCiBV)`;f*a0rue;LtmD<=Li-E z776+V>jYuJrGhI2w5?YQt`S58F~P9lV!?U=^3aF8O%hOc=)|%(b&`BiXUPjXwhG8o zr=VNVCD<;wN)Q#0mxKTry965r3kCB9rwJAdE*EST^a}a}mk9<0Y++z|99t0=eS-0b z6Xahe8r?0gmBY{$8L{I7n;XGq( zov0SH3b0GN0RE+d6@m`I`2zA|{opxIz+B!%0(hW_M;z-9Kj{$8JR#|95o{Ce77(`6 zrwQ9C*daJwKo~Yz?c?YzN0I0E3#|Ooqwn};^GTn@j|m7)N;BP3n0_!*3u#R;mhrO-0oIx!OXQL#uyJiA|EuGBH;$voY+0x4C;HWl@8%{HA z62#f`Xg9DpzzwUKGImKzRp4IZ0Iv5wWhaAWL%xUs8Ej|r-BAFki#IzH^r(Tw0UR&YK# zh!-xjBbRJ~O?!GW>kXci_00s>lb22LB$JtXGBFM)@8rqYzJS@2{*+rHz(Hvi%A83l zY*xriPy!QIw%m;+pNyaUOjP#@QlCu1pftg{=JN1NKx=f>(9v;w7VzNbX#uuj9TdCG$POk0+I^f99r4Eu0|Wq+Wi za=!vMOqgd8{n5uK4ix`8OOVo z_c{)ocM|VF`>t;gPG5kR1pN{E9ys2eyo;fEM?v$BfsgkN?^)h`#D}JD!uuM2-qCXe z^hpTEAuB3q6p%i2N&r9cmk7oL^doS*>u(dlkAr@`pcz6A`hEdB zUq$~7*Clv^XsaLe!-4Q_(H|F0d>r&=MbpngJ~U%V%8&f47ktZ)uOF{J$#9(Cn3(bPTYO9b|t(n7s{AK!y+gplhKbolWtz0(gzAHt)e zNl!msAC>#QY<;26#Q4+JN9bF9n)uL+Lv1*9_hq7O{e*t4X!OU?r)6Ae?G61I(Kf%( zkBX-LApZ&hV^8u6-7om5XwuV<*Khxw5bQ}fefTLdj4j`5M6;FK>K74xl4xrm=!K%G zUpVNqeSYLYcZxIZt1wU*tpIC>s5s2Lzn2 zx6fBh^lN;6q274(4L%M3py17-ZGMJCzgM(<9-$u*Jxjkh=>HZ?KOYDEThX?>p(p9# zvh^Q&x@hV*j=nTo$*n!17mA)vpd9qMqHX%nTSZ%YL0=}C`hkOvmc-vL+UiUA-6izv zMNgJL`6v7>qS0T~K<#}f^g+>9{vOev6m9JT{qH5T9d{~72eLvT=0M0l4*LIzw)TOp zQQ?t34!S{fke@sLZ21#@ifCKkq1!|U^*N^`{(8~2{ez$R9BV)5U81Fu=b#5m;^SxS zW1mCP7n>&s-5Puxy{X&Oe|Rj;^NJ1tWlR2N3ML77-=Y5k0rhCHfb!lTAROIDgK-#o zFA|`~N&$MEAwU;ZJC7ef_~1dW(|o*5zogSCfQNS}d}j%ezg>X7)D?8!EFc^mkj1+e zUCHzHWHs_ z8UNh^?A#;3rmF?;^$C#I>i-Vvmw599$URd)IxzwMa|GmrwvN2c_33%~C7-AJzf1Lt zz849w*OdbJmk3CYxd`&LP(XN>0RD3X@LeDv-KYTn3w?Tpe$iu#06o?V$j@>CwmVyZ z-kSu-clDm`B*C;e1`xz>jb28nE-#@73jq~A9|yJ zvhEPTf31M|uo2#~u+AV-w^yufpQduh+M zhi|>U6mc!70}fG=|4`3 z-*@NuwI_V=RfBsszvu0>|5*RInPwTSHx?aD$FpPJZ_F$V2k{==jJ{iI&L)wPG_)wk z0$s*i$2F^F-ZEKlUq@e8M_)%r*N$~-!<)OV-mx2_-XYlB-RZHx z+7;f`)!o~%yD5 z`@%il>$Ys`>FDe3>s+^ev&Y8ox=kJHdqI#I?ikpooeRD3 z(ptI8MzqYE4tH%LY5gG5%VJ?++l!hh@icT^D=)Msm5lF^Fjg*&p*?g*$F^|CW@W+; z?%BGj@3O7kp7P<%JGN}>_SE01-3akamQ8eFl?E%;#^Qb6f~N$=BEw;dgQZdrVN*sP zS?OV$;=Anc%1z<5ULu~Y$)AUKUViyej=g>B^}naPE4;m@_p)Ae>AOrMI(GE+ZR3~7 zd7VKF*Vb+&0gti>3*Z%>XfGN4!r75Xr1o!%X_Yh++Zs;pOYMnq19&EXlXl0bzEb9` zIeS|-3jSPB&t`!wgM*n^c5Mv%XffHlr#;WLR<_xhmZ$b&NGwbJEXiswh4y(QBAJX= zs|U5gBp;>N+ZfgJD{$zuX^D6wvpF&xh$hedk+iw$-P;nA8m2U)x>kR8P=cvsP=r|< z#&=UHQ^>F4bj1cE+Nx4PwbZb;{ycF=#%z%3+|rX@l$Jnq8+B4G8*%Dc_4~4ck@lU zVt=z8!M920?nqjD1o9gB-d%}=$z!kfWkh#t=fm!TWvi6qfr5m%c0*~qimzFh z$nZcR)Cw;5DJ11>tnlNn?=;u?+h0t&el%W?XoCH{1*xGNuLE zGPpIHX7`o4LdU;x=d8N%!glxzixSbDCH^7GaUB5-NNnPtUORI zr4}k*yD~oZ+B37dLm;3Tav&yXwSxDfX&Vvsfvn zL|HpRe{({Km7co2VKdmE~iBAxuy}42KqKZS;CsMm23HsU5@~DA8 z8##V3wq-E?D(*{3x9!^aIvDF17)a|S7uVj>0dN1X|MevA%RJ=ML%fVyY}HDOoq2}E zB+qR59Oz4#H>`cvYXF-aEp%G^UPMQsC+GW^<3)OT=im2cBdT&~KPIKE>lt?N>J!BQ zzxc4WLwntd)QJ5+W*|5<6zKW+qu%c1zIZy79M+Jb7aK6@(DwE{J@Jf2B~fiv_P6oo zL+Q{|3|%`qsE>5@c5leXfwjVSt?*{BX1-R&C?&6?AHZfRBUL^yU?a4h!ZQu2~Z`+gF!>`@D10_AJyp%ixDo8xzU%w;ii(vnHnqA)3kg5$M z8tCeQFq0W!KS}j7ISf(g`a@9)elNlUj3h3prbZSewC!W-v{bVex(W}=x{}_#q@7P<+{4MjI%!l7m zZRU@eOa7>E=B2@}*Tg4to%ajgD1YYE@&7mB%=?2ge+mzBMg+{cg0nuyyeT~U1w{#O230lZUT&TbsW`xXt4o3bS^eBjNDhFW{S7)}Egh zewzHy;eUl&eeMx$%isVGd_5@q}UWGA_PQDh)-`bG< z<>V_SI9s~$61-pV8i7ssjRE{_@kl+7XS3qka+xK6^m&fp0|Ic;x?PFdI`DDPR_5md zJpU2!|7O7d`vL#Ul@@Vh0@luKy028;u{n8vw{X$~e>7l|?*;s;R1hclJSPV5Rl->l zBW_aiZC$!fxV7OO!pT=m@Kb@Z?4|cR{n~t0SDCUvk7I?C7WfMkm-PqYzAAvfMYyfQ z9};e#osHtN^3y`V?-wkUOsVS0Tp7UE2q!LSvG)R*;8zJJUGRi(>;}F=Kpw#l$ls=Q zbAab=;Wl3{7H;_;m7eyQ`k8Rz#st3?e!P#Lp-v~Cq*>)53Mo@<0-H{$+I zJht3FDcrURFBgt|u=9Thc-|f0X;wklHvG%-xAkO>{B62dC?V?J{erXQPkxcPPB`TS z{&k-}F8r6mX-~k1gxmITxiV|Z=r+kza-K}SzhUj16+bvKuM6b&I{DjlZw~OkTypBf zJ0{pD`N*Uk`-CfshhG)IcL(saaBK)avR@^jTo(!k1w(=Zf`1S^SMWALm4No?pn!Zm zPjHWbbjkBv!Rdmt1ses(zC-YK0q?eV3U&yT1urf%@5K4OA9+Cs>Lxl-9@w5bPdQP} zlndobJBmFQ2^I^M2v!JI3N9Ax5<~?9f{b8PuwU>j0ezL51UbR$1aB0)N$^jChXijG zyhHFF0qLo`iVMOk1|-pRC$rwOpjD#2R8n*|RF-XeIH;C%whW2#_*V5wlW;6lMgf=dMv z!EQlTaD(8Lf>#S(D|o%&{elk))(DWrvvaPXT5!DJC4##Jgxx7f`glseBR;-Yzw>-N zt>0Jp_`~{@!+iO9fxSPjy{&uCMM-o%L0=nf8E*bk^I1)=X*#BHq~VJV?Njfb^1CV9 zC%3ecyGdgpP^!58JUuo4BI-EOndK$of~dt!P`( zuT$TgJjYj_^6O`SlRGUpw|2byi0Tj<_Abov4nuoKG~2eO zNbA@YkLXk18GZLR(^kOE${7dtL+{U>P&>Z5>Phbn_$wEuOj%G(YQ}br4xw8(cS`N} z`A3rlHNf|-mGO2pgx-^DtQ|k;h?`E616b?w+;O$zi;oIzG;K1hOQfV!=TTvzP8t06|Ry%(Ggzv>yI)$J^Pv~Nzn21Bi}75?~;_*F?8Ee@s225X5p1?cdoT|yyM6} zF81o1Oq(`FM0LT9R-XpE=j0wbA{QR{`d83!b1LcIB7%Z*bFuSGN+gbDankm)$svfOcUwvBD&B!ZrN5ue6*N-v}VOB=lcCu3L zchuhY*Lm)94YlJlkJxkK=To^>QHO5j<=T0~s$W5wiYwlzcr_2myraNeTjM%H;2G@} zTDo(O0;8GT0c<4Kwg%?XQ19a0iM8Wr9R=E%TN`yzn(iXg#tU>iNGrVjC@9Rp6VGGt zyraG)nxn_`=(1bMeC9vWi|aTFs$HOHyV9C&<$wcqZ|9Ni0Th}#Muyt+`%W&r%b*pfFsZ_#yK-+UmYsW7; z(yxai+i60=+rgctjI}*k2LyFGmS<$qQSq(~D(hW(?&*nst+|slhjKI-Q)|0AI_Z^k zT;q4PKIG>GzOrfO8{2NUY61Hqs%!obYG~9S=bQzc1^&-i;I5{V>c%_o9W3jgJ-yST z>RXuu1#N1)V>&j((%wjZ$Bef7w70dFerSUIK7|R)K+m?g@A2T2`l?ll73a70|Dg6; zE3Y~4f8YI`uiw}EvBVH}sYSF?iaQNCzh`b9x+?h6(Nc;}o1Zu~~XT)Slzy4oJ?1arYvB_lZV}LbyFk#|h6$x>P#(Rep-E z^yD6?RFY=Su9a&0OnmUh-c8H-TTWiub9S7*Gv^5{NAT1g+?;;pY$fM8%?+->dm49X z{~$Ircc+>&n8-8t-I}{*IeExwNXmqC%kzg0K`xsvw`+38ETzEBxRmxT-QYuMWTg@3 zAmKqnP91V5sX6^>ZV(M>N(m2n_lj~RbK;Ov%LF+KwJol_o~GV#2AF&gNdwM#j(U0o z@5C(l+cU3!jYg`~7s@_S_J`uYy^V(Y#c#HN{gmuugl3N@drH~I$$ru^1cc+*Q_7x6 z_CDgExA?z$d_6j{-P@|3biiS{!tp zBGSjgL393sJ-s;SlSE@<95i=Y+Vr9A*$R1k;he8P9yEJ&FBF2^aO`#ETL`x7prfL( z7Y;fl+NKB19hX)gXn_35+w;fn=tKFkZx~x(FJzE!02~>l3sBzdD<)lZBMxOpIZ|en z7iEK;C=>F7ZIMwcAU$~D0|&s72QTTPBWaTs@z_&K9IG3$iANlMSriNA0o$QB`Q;Z| z-@f<6y76=GIkW727~KE*qF$w!Vf`Cw^6ygar0CE=$1z>yQ+TaUB!eiMp|lGo7Vs-b)B>_*dcuLQaB?J}F`JG$YHYrC zG|moSL-fXmypye7h)*yhsC#UD4liwO%J5EZnold4sNT`V4CfYoU+oc&4f|6$$OxX{ zG$$bQryaxjkF^B0rR2ZRq7S(wbSstB!@DR+Y4B+mhMl^p$?nO}2YVs|Tat+}&)*V( z@Pc|lDFI)udr4)GJzw?AI?hn;6+!)@ezyyFPN<6;1o(kdzp2MOE2rqe#DAXP{|Tu7 z)a70Q&jkFR5>V&o2)^m#bM?!!h(B_Md>nqhtHQIxb4q(lTKHe$rv?3rK)TQNarip| zJkJmKKP%wBLO9PQa;6JM2lU@092xlEEU^0XO!92Q$M;-#mf`6a&hrnB!!9`5SZs*Q zg#zLMKM{~G{9h~}F8SiD0JZ>suYfiS{NDt~2LFKonYaeYCoSXldE=?V%?%FpE|F^boP1+|{uMVtpaWw9a}NyC3Srz> zf)?n{*9?MT#H9aDzD!@fIGk@XkQ(vm`GFgG!8;*>{mO~@+t`eLE~5i@5|U$XyD5Bp z(&V!Erjvq=u&o_2RN@SVb6-x{vkN+NYepe1w`_1D2jd}npH?QeWb|Zjx+o5@{nUal zJyU!cGtq}GmCF}|xx?Sw0B>`PmV}raOt|aAenHrB(tkI1eVE=cqXcq637}uOZ*jR; zIZwvREheR-HsqV$Hsxb_^1+fd_p}7Rr%)V&u?hFR1g&CqnJBIqmGZop8-2Km#@yA9 zohT8WFyt~CVsv7^uo2WOIO;MZ4n{;~Y-6l%a>Iz#YD9|El5(Gw0Y6g~1s+4gfi8Ol z=KBGrKAIXtZ78>W!msy+)7;oY9;u6!xTyn$Iurczz<}i2SZ3sAaz~C#O)#a)wQ7w4wY-b_fNR#W>_`T zv>^o_YbEo20$Zz1TWs#!Dt=<@$QOyhb`34aKN5yzIY!)-G+{(NBpaA^qEt3Cxia-| z)U%Sg`N@vccS)`(Co^t0<<_nTe70|ZP>z?1|Cy#@#bNCKe- zLS9m6X@pclNO)-}B&2@-XXc*0vn$CV5U{`B>uVqFIp?04Idi7ospO8rZ}~!s8jlu> zm~cxAG+*^KN(*$tM{bYcFS(r5%<3=JVCAKeopS!y9CrZKhrJ-lHjmj11=1UcQ8T@-cp?2@Gr;vRON!+{79e%`zvhM51 zxRo`UU($iU z)RJ*OwENUWy3hx56@5Zl8G7J;Y~0@rw0>!FmgV`bk``0mSdB>kzg})AVf1qRmj*4A z)#c0%ppVa|zDA^PZ@zi!TVD4RvYgjeoHCxao^PQg{X5I!+#uAV-R9%;bxmKHcF)?s zn1f84#sDS-Ql3}n((`Bqi{1Jlx39`FGIz6IeiF2T1U-?RM%69jyl zBFA^{6oHMQ@r}Ji!1pZQ?;`{$fys{+-Y($V7yri#P7&~Z3_VeBmVj?k==}s22pA*4 zzsZ7Y1o+Q)^TC4q1$@h*&ve1l0=|v;&Ydmzk-)yAtAz9IkAKJ?D)^Ux?|S@OAlO3= z`S2xt;xb7z-}TT-1&f0BM~dd08tlV!wBTgXj0K=CG-D#B-|?a^7ma>A^@3YOGcJIA zq3;XcH;R5zG~x3=|FVeYE+6cLd)}8xQPK_i1Oa#VU|;BF!D!Kp74WnQW{74Sg$J55 zKZuWh9Nj1cd-G)c55q+Hae-rR8rl5KM{enacba6~CIjKfUMkuRB1H6EqBj$+ANT%# zA?A0Rc;AU=MM*inSFc}-9;{y;@(uUw5I5XIbB~V2eWmEpqRDH-^&|oJ>X@xh6+K(D z#SMCCL<@E2Q#6QXyaxYI7qp5d?Rbb_PBgaSJ@h4_8I#eE8>hNOh~?cg#k)JAd4INm zdveHk#P3|eL!!wmyk9GLS_t~{Tp)O^h<-^ld6$RxoG)hKLH{w5$N!52{|Me+EV@*I zoBy8`%{gSa=YifSqKO~$UZT+t|1K4b5N+wZPV_X_m_)aD|%P` z@<88EM1Nhh%UscW?$)Jj@F4%HXwnaTpt&c<()$Y0{}fGL=lQ&#p9&%ILmqlN(Uu>s z5yHZIEp0FBVPu@IcpzHv2+zF5Oe%LDzQ=q(-P>0gMp{Kfk}inj3Y7hR^vSp5Xe*<+>;^dX|H zK7?K-y1#yTpidDkFWm#ZMznKIcMtRzMVNc&dqrFN zeMR(RqH#}pLq8qK3w383eOEN;&-Lc+gjhR+OB5p>GK2 zM?~Kl(L#GYD)@?M{dW&Eu(tsHh$nS7`cWTZ7d6MOeLx5DCAtwFGT`V!dcebO_)U6K zCddcG4M2u;=N z0Xk0@7%)Yj&(#9-87e^kr2@jQ72xlQ0_5mxkQQGO;Lk__{!bQ=hLwWt z1oI;LX8rP>yhJ<~3Gjz7;13YsZj=E3>ICRX9)KoqkOtEPxIbQi?g;^T;L8H|g9Z3G zOMu&p1n6;#fOyRp5MHYQ|7Q!Z+X4al93>#0=L`A@E)^i(UjRKufIZp;=zF#Rf2sud zvrvFPM+&h22m$i@3rL6S1jOaj0`kl`0@C7Q0pU&+;7_#x_h$--|LFqwpA+EE;R4eA z8Uf*bQGh?w1=!^?0_64+;Lj8R`X3z8qxFkk4FbYl8~v8+m-w6^;C-_I_h|ukObUqi z1p@4RssOv+B*4D63J7U^o2=`F|@&^it=dl9# zErL?P$pYM8D?qMIfWKD?@aO9S{5?W|{Z5L0@6a#uO9aTT65#LU0{ACHbd7$o%Z&o~ zozd?){o?O&0>ZghfF8#PkZTg)?{WeDJ|w_y7YcZPg#h^*1jyYdAbzI^kk1L=pCurk z4+!9YN`U*zqTes*cTd52f4>*uJr}-OCL#=HaKxa{(pKtJ$TR3 z+;$hvT<_AakN&JYZ6nc&XRY%3{naybzn$=>d;a$7yFc6aq#L*1e$>rl${q+-dASoG zg7YZ49OmxUNwFAgy1yWdbyD$?rEGjmO0*!#ubpz|aRq1OusSL}5K9**>6m(*nD0)| z@k__jE%5yot8WE=*_Ivh#KGQjN}Pm{*fb%}X{XM6XO|mb2YA<8NVe zmrHPIV7hL3qAj~LQ5#{=(y!=x1v|Z80dQDXHo5>!3((91e=I*|on+D}-SXDNt!#Bp zcej|WK2fi9ZA-W-$SN}(t!R3bPC%US zlNGk$g!L%_HbL*-3vi1}gTTTaA)N4e81+SG+_FNBxPad%92xKd!m&Bw<1hYT+xGjP+A~CYD(Ye?yX=H}*3(E7aRyZ4$G7$T7!LJo^{V>oCLO?>LIrRCFiL8X~_^ z%=U+{4kE1{KzFMgY85`SP|RkwsTbt;n=t><-HHlZ>vo*{V3r@v=7C&Hm{0IJag%1f|!Z3)o5Mgygq50^&*s5t~)=x&6q`H&Xlz} z%%Sxxxl->))%fNsboKYQ;TIt?7mE*eyVAc~4dmU#79qFzc~E9M{kn+a9OB(DpNECo zm5&I|RtT-nYUo#}ec}4Dp5h+6@wZ&16iZUbYtnV*-SflMa6S3lRqrtUnw`F^*desS zH~(&r5-G)69`d@+P0Xssv%WoP#4IkWdYIGgs$F*_*2mVgvprIT_Q7r)x{@}?-^xgAx~3Wy%DS3{QfsRm z%oetS0b62)Oi>);I?HP5IE;|vQ^W7eizTcjwKb~H)SYNtxcb;ulbBvc$E#h8W2xEb zQiRfkEvTh@o;2FZsNdabb!l<^?llQZzL!T2?<*-}8k-IlufjDi-euR=6E^<&_v`n= z>r))Mcj?!``W3B(D@=NdMHnwH)3YBwjL=0kN~fOPu=A81n!YBX9MNL?)!2RwqB^E@ zU>SDgp~O%~W>f&Wt$IIFRLY3`8o_UiJ{ z9_}ms=s(zl(Yf-%qig(_W7DA4J3EKHaN@Z;eS6JTr(Ag1=dZoujk3S=@#ilEj;lMG zYtt!ChD=m>e42*3bX|N%jE$)2={jxQY-uYZ{TV+IQ)XyN*GI(sn&w2dRr^RIn(dZ( zzpLxgy2{jtulx27k(kHWb>R;S(^DxLfrx3^TNslq^^$hq3{+OD%Li^#*Zt2M1% zsa#^Cdv3Iy)v$Q)YyMjIs%Ck>$@?*9;q01h)m(p9yHFoDA^r|p=RlM{9x6@+Kl;j! z(fsaJ#*6G>%#iUU#*S!amup;z#uR)9;f!}N_BBK}GT`jGH2gr}j7`CxE}U^fa8@}Q zpJ9Dk>slu8_)G!rz!{4(`6l6vQ^8*q@EK2IToL|70`un@;pR3W9f%uo z`ICS#F|pi=O~x$2kJcaK-yzy`V^)PYBExJ2IAJ|0u&`bX@K=Q61{og0IfNAF#lTX25YlK$}z&*ev>%el}wTOQ}$ z{0Lp5a?+$3e_r~`o2Om5^$-7=81&RD?@oDFvEW<6-(gKZ-tG=BJg1}UH%;s+{$30B zdAwhLd@p|eV-}1h@g3{;6tVNvz7Q?M8hzuiPZZkUvF*Rk-@iM)me>dCS8Rh3hW{F4 zheLb<3f~a+wZOgyzSOagh0He;-*7#Hh)MB4HX0OuRtWR&~ z#sw+{M(N%7BHC(WrY;fm4q!QdmQ&r6HF4bFz50c2MNq)75 z)_H;m$_#mCL4aFcBkczZ$cN;Q69kkQIhzxlUoP2kU03Gn>#{!eV9ejStm*i=1@+*Fk=P4h&qkMn^=z*-s;a^CL zq=C$j3v55&N9VrwiC?Kb^nBbF`1DqTRPkI;+vTI=XzcZMPTup>kz#zR9&WyAw+pGolOs8B)i zKu;G?0aDpPQ!!If@lY8aD?px#3_2yC!liu0R4ENe<85&q5oG9x_?KsH4eN7 zkS9FCM-Rd!zPv*gdtfW{Ca%~W+t8uGCfE|dAHqT&9KG;^Ux0=Iz#nW551cRv8@GgQ zew=y2Kn;?dJGe`Iq%J^By)KSBuJV9oAN?T7dg~%}g1W1W%KjX6f&#|{YpCoXsqB)r zWU5lb1ywCs4$9<4Sv!BKh^;Y#Ce~0X#w(H<0ExY3xM6zIEmx|^bU+=}o@h^WJ(h}B z)mm+psOQ`&H`bs-t^BE5RmJ{?$6ZASSLIK_ibM0m6jhZetqJ2aD>8*W^n&&kL7^mr zOcPKz!D|F$6mT*C8HS8S4~Wb`Mo0@x<_+Ow7-T2}$m8}V0hto~Cj#R?6X16VC!--l zfgyu||3*OA_<5?p_&MPeGGs0j5H2`=nE%%bH+iAXAATt)=!{MjDhd>ZiExM)86AHp z7`Qh%WGPhU27hqVlUwvy-+Kxse&HVd(F1wHrVzqMAJb*+=>ydGuj{(p@#Am&gMr1a zqmsSHcQ+`xN>QbmV}746YZ?q1J>LmnuXfkDH0C7zu6ApXx|3;D7l1~XhL1G>c0P;e zhNB^#6V95&A^3NNt0QR2Se-#5ZtH@4gWc1cvC<-Z$Jzzvwb6nZ&h@`#7TfPM=Qs2x zj78xaV#8aSWq(d<;d>i>=&HBx?y%CO&_z6hY2BDmlTgR7gAsQCI2FotvQ9zFV-}VU zh41+JwHL8lW-5Iwe3*7R0P*AO5xR|ZHsW-_EpygL#9Vm()L_poP6r!F@oza*g0UG! zfP4<~r(<;gmX0b~5GoRA!1)B>IF5JkKB82DsR^h>c&v7!w8OKSl$wBd1EODOYMYS} zjXX8RegfQ4GvRisfZB}r)ROZB78W(+QUUI$O`z)q$m2iXtQi6R;GXZm=*`3XX9W09c+f8iOrCGz*96phJkW0ns113b{~{n>JkVRp zqwxJsqKOX=?+1&5FT6FI4=c@0`Bc{v>ObC(f<=jjl;0pwbTz3r`46sny4T$$7w%Jf z-r%XbpZU4delorG;j(6L^4RGNnR{j`y)xR0ut4{()+hYmtp8yqazU%kplzuKU8spi zHZtf~T-SM@mT0P3kxaL{Gjj7|lfFxC)s}4L5`?0L0V&2uML0#0DuBenz>NYczLZ69 z_(KE~d+?D0`~aUMFt-%}jyq)Vf35&skms?)=S$nF4KfCaPC|nd7S#jq@t=%=d)`~d zz@OD^LrZfrKGn4}e*B$Q?N=#}x1^L;rjpTp!*0OpyvCLP`rRe{e)G)F`(L!}+i(2+ zf3JLK?JPxrVI4md)27)e&H$p1$Uq14N9%tZo({+gY+Mxfnd06Ql6H->K&+uG3G?yLu7qws($#_Q;&v*40WAtQer3+KD;j9uF3A2`bz{YWC? zjdURy5eqM%fKNx!FP`r@vPgK01p0$Q{fMPsic4l8R9jTcA)H>;cXe$Uz30Z=Ss#ON z`7@c6SjCg5VJsNKWUB)QL;5WaP2%ub#s^VG?}!7T@!8hX2b^{3eSG~mES=(bOp|Uk zapJ>n5#X!zt}qq4UO>_HxJQ3Hr%xF^^2jIN9yX2| z>ls!txI;s%W|DryHLg6cAZgHbx|x_`BR*9MH*45*G#`I_`0$DAKcnlqspzue;ldwl z=0C$YKsKvzCu*zPWa&pJghx*EWrdtm{80VyP=!#f@PN|-QI)`>Gi*3jOMd~sR4sIb zM+%UmDx&HeFQ66Tp<{fofYyok&@%=2&qJ4Iu>g7ALmwwVo`;Teqrh5F=o1C#$U}$v zGy(eH9{L;s)gM(Zt@4EttskfRrTR7f`V0SpfQ~!z{RQ_3%oYQLe^o&Ic@O=tz&=_A z3jdCPuz8@rC!p#@9{L3VRXX$_!OH@BKUnxL1lST7B6vk$`p{gwD?ne|59e2i=|4g= zA7SXn1HGMS-19&W5>0&cQEsAljNV=)VUB48lQo-t*}I-Cuxzq&(q8~A%~eZ5Of zL3G!>ESu#&H{>+#m-=pLo-QI6w6f?S-dXKGB&;aO8ty}aY=!wTIY~kG0w-z6f|#-* zqQQB1$FskHBto8F%#0h71sSq5K=SbmUr&Gj*toz!7hLn}t&hC_w`8YMX|UC(%^&YO zzt1sF83gmsn*B$W<|@uSc;iUC*>2ftJZlpzx>NGK{ncxq{ngShm%rI-&Q)KVGwh<9 zwz}`@WtT-WNJ_uiZEdZK5+}ANvTfcI&(H-Tnl$npC26t$%-O`DWrOJ_7Sy`0#rSn_ zOG&gqr(jQiRi4rm4`s(5KJ_a_Sh+t$IEhDjC4ni+WFX2s|2@}a^?ID9br2$Aub)Q=k{Cv(huHS`}`Y=?|6K4dfRmmJo{SN zg=JB6O}?U5V;59$ zn56hgkM#0n0&I~&$#4Z@UgZMr!gMNG*C9W3`B5C}V!B#mgY(h~BAsyt_G|F{u%q{m zHTf}(e08E(r)FqRKpvUdo=WAl$aB4HOZ|cj)-^*`wCQ0(z0) z&qjU@7JjyX@Zhf#m|KqVMF(1f+l5p6qQeaWletH@xxH92$RhKYU|RuxJ|{qb@K*)& zP{BJTPYZy&eMP{3LVRlR;R3!U%zv)dv-l1XPS*u_Hbc;2fOC+^wh?};a0@ph-0X0r z{HJ9j+z#>S=HPa%_*AU$CkiLN;{~S$ex4urX~!ZXf35h$9e-{UZn`}xoVdXMj&NF0 zaE?%hkNtlxKCK=6*8==);pPv=L(>yRh6g=)lHy|@bbx2}A1FSyMShiV7i8R#OU9a4lgT#Kq^5Of^2G<{|8}XV zNl|;KMaik8I=S%<0XdLd_6-3k3;wWxk^@c-Aor4U_7jksaLZ#Q&Po~bgnszh2GzqMScZIg%dl~XGyEC9vB7P43^DqX1&r%g zz4(H$;tx`@W2D81W8_SvH;o0 zlAB7(vKQHjN{H;m13fhQMIM?;9shXvJuvz;dZrNMkmvnEffWt1)Ug5!54v7p*&G@m zds=v8MY1S7+z~hQgNHkK#0wm^giW~ccn6LwZr~xKX8?a}Twwg`XAC;!jCrqP&$7}) zudRQ(b)PM7+x(?|lSOQLHd$bk1vXh=lLh`e7C7s$@uj)Z=WVb}iuuc}%Yze7<38)% zJD>i?Z|qw6@^-^^KlI|uR$p^+<(h$Izl;tp=wSyUAL-HOb(^lGuGKhF{-Zx1To4)y z=fkU}_5H5?Dg!N9e=2Gs;|@~Q_kVqUlVDX#ot$ZRp%(l{<2CLxetu%*TnW-oR*%@L z5e!?Yr#v^E*7_iKW~o~dq>&gc67s`GZUuin49{iJR-UCj11D&?(sXT_(88gX`kG9= z2Bg|kiM)i^8nbYNC1^G?Rny4Uge*O1mL9p$iJF$S>}>5l@NOAK4%~Cccb2a#d+0w8 z6G5X+2ZbX}X}sy<(n#}_#n;)q2#0US5`Z5gpy8*p&?MkX3!JYwer+Ve{Qru0bW-q_ zBMtcK!=IdhuS?ua79h_&Fg@{u zP73~%L^>eD$b-orEgTtiNPwWJZ-Spb^_xZ-4gM=*c!o9^Cz4`ti z?%2yZameBy;qncGF2sen;V&Jk)q9UC%~h`1yvsMj$GfzSj9WfK<%E*Z^^gM1m&`cg zuP6U(MdOm^hxB^6-w`KYb7?y9-LmRvK$vV_U0J0G4e!H}mZT63!A0cand8R=#C`$3 zzv1?4IYq{CQ(suqQshwKqzb9SW2wk5Ji5B10;vT(RA6q$3&-N{4+(HfVNwg6U;HE0 z2y6Acv8B0*YuYw&3KgtA)mT9=HSzYj=R7^7s?VK?m!HWkePr0Po!8y;eA((~upn?( zsU)e;m}W;dnN=;DYOhbs%y2Aqy=od&qZ;6jtCsdwccStz%d zzL0kIP&1t*g7gJ!j0Srz5nyll%LLfnK3gb3@Tr0N3;3+57g((@MK~oAK9A)I(h@L# z@RKldi^r7a2CUv`1E*(nE_K{|zSp|sPd7eTcj}wFPnvwk{aX!s2g@!11Bs=`lEwQDy-1FXw+>IB!Q#O3Bb$=QP)xG-uM1M9t8=D2z957K|6lX5pz`40*CRQX;0nH@vbnP5aPrtfNR|7Q9Ix5-f zF(DP1x+ZP^jj=($TPoazt%QZOJcXgl;jl=pX^I;Nt|83-A>J z$`EeolvvmCjED!Ha!0iUP6G-J-WuUn!&^D665sr(7H;9z3a7RwT*9RMQkL4it7Z!%F|K@E`PgNtWbLvR-8T_^HjOQxxJ)UEsOqsqTcC5W^|kTe*zTd~hD_N{`z_La7AtEy+~piIGMRM7O@pXstGRYf6Z2{1u?5Sg z)zmNM9t}^=Sk=acaD7eAt7)rinvv8!6`6T8`UZ4+$Mu2MCV^_rFxRzdw!Xt-GZmbs zU?g1KURRe$=q?M0N*Der@{RgdTEi3jURk64;MrtN%fd`TQ{eUb(9_Iv)F-RbDSoSF zrc?F$0G*-hITqF=Gb@wX#Nu>*w~%tAVzW5Y!TO`c>3KCBwTZ>j0+^phpLvPqbVifc zibr%$h)|>ycZcYdohJD)r#-8f=tZoYi@N*6%gA>=l4S@V;n)Dv(^XldsTEXAT$}2co2*mf#9h>ih`*$$gWB4W zNj5gMaf``}RW*G0VLZ9V4qxA)u_PVzA zjC#x&cjREcuj?`z=JiN=d7{N(%3(^#<{DYjSbW6SyO;C0%A}>y+rkYjIQEj3Zdil2nJwJz3Rd)mlVDrq2f)50W^3HLKbb$p!6g3mO*b_(iYr zBIQJeO#-jwgKl!E^~oJ+i~*x{aRCRhLhk%@7pG!SwuV11?b6B9j2heeXSB3Lo1pbIBaq4eA zsP+|5$MddC2=dh7=c#h1odV~+W`;4qo5ZKS2d|c&vgnLmPwtvjw=t&-)~dJo=v}z(3kk?!Bh%!XE(t z7Yf?NM>lx=gyTQq-Y)>heOf>phyOk( z;1>x;27FtEiya7ene5515BlsbK5pT+h`&?Be_sA0PaK~Xj&9&z7Z68uI9zTC3xBwY z2Kx{ei(`l{IJf7ZKlWKFTtPVgeEotG-$NyU{9FMGUrgtNg%cM3R0_b6uN2?>-$FQg zqR-xuJYlgHoBjnj`?iq>?<<`6BLBSfXIKpVZxzk}4fr78*a4foA)Mhm_}2)>4&b*- zdHexqA2{iS|DTNF0)LHUcF-^Qy~6ngzA71Pg*}H0*YV;bGf99=!Qrzoi1@z5zkjHis{6=6hkIJo;my7~3 zyjHl`e70n;Cvmw%e6#I!!ifudtWz8r;s!rB;?EU6K{#;%M|KB+SZ?dke)`2O^8}Rw z+%FO&1lWgoGU9>$ygOJhO;9D6BREumzw-s8Ns|EGsAmTX1`Cc9;HRSCj>IBt{DeM4 zFj64ZolfM*l;A+Y34&n)>_phL0tUU%VYXnZfN*$6UaUz(4$f zK0q*8aFBqsIZAMt06oxehG4m1Xhail;!3=EZ+f6Fw36HX>IXIQ;{r1WoH+BS>wmOh z^S)d5+PU{ndu=ggix*3d>-+7# zyO!j}Z}^yHwb{KckyRX7Z|tIVi_&k;#-3E`+^Hlt`UA#!e!D&vW=0FU`3llUVRN!B zlg_3a+RF7&Sf`G6xfZDDQ*liBm}Qwn1D}d;#T0K@lp@;0QMA^ny>rKs+`b!wUQrj= zjp3i#ZF+UyG8fbVyo0fQZlS%+`v zQX5Q-qExTjHj4h!e1?CMb=mU6HE68$Lr%3@)rmcbq;!|KEY2j{7}&wbS>JKJr>xSw z8ubC){@04SYuz*mrk+~D<$+#b+9mHU^bsuc9l`or0a6yOrej+Zft8<`y(!old!3 zt|+%;<48}d2FYS)sQP0_BtI_j#G;e>t*F@g$BfJLDZRT_*)#gH>Dgp~O%~W>flU_J zcrB3IWxvwgsND7+tS9?l>y2uP+ucdz*7eiq`9nLVjJV+!zy95ir~GsK0k?ej%p()M ze)*kwWrO?xVSy8Ou7j4w+ByG>f!o6zD`VueO^n$yZ@{=XL(wcJH(aP2OXrv8;<1yo zRPfpjeYyudJcjIIt2Ewr-pGsR-#_HR^2K-T^48n$JpbItQ_KFinKz5Xk@jN@9Lv$9 zH4)Ld2cGFBvMaSPh5ZR_nRF^-b1+9sn?I$&ExYXc(k(d%*jjOwZ0lHD(-`nj0pI19 z=Vk+?V$`eR7w2eY0WYGV)xec{L&2dvx(c#BS;IPwAh;!mM04QfqJ);Kb?4YG5$ZlZ z?u45LZnI!nOyFDLi|!pCo~#L6EUn436#6l(qb*U9$<&|~>E{Q7Diax9^F=<2R(C|l zbl}z<%#vZj#F9+PZ39TKBFZH``M@3P>T-m~yu4%heLYHgzhuPo@-Cyr>rnu_j5t*- zE3_CV<2l@V3Kr#@{QjeWXC65zpPM39^rN)a3<*nlqQKnxqE;>QiXxJyiRN@|35xiB zZDCBvhluEQy!Sfr0kjlkqvB+pzi@~Z@dfy@PROMQylFADD$;ipTU zxlH6A6Q6lX>SO9(aQMjLmO0bUN}hRL_*VsC-6@=~;6E-LJ;B!sm|I4Ns|4`DZxLAB zzax2MkpFpr|6aI-We2<<^O(T=+*Uf9+ZV*Ay}d71~o8pOIs%~r`ut>$ygj~g)@IoSlk0*c4I9JVZr}`aP$AmflRynB(CU|3vkvk?Gd@vPrfbvUEsE_ z>_0e?877=?TzrL_Zv0|r;vlv=JY<4?u^BY^2AQ2Bn)aLg$va?60rT?MPeHr*kpGDz z{^E{z(CE9D06D_LR^(CgCwUkf4H1kGlnX`+#t6m=#tFs?SW~dSfH`>P&j$!d^Drz6 zhqx0KVUuUTSzBX$kYU0H3eaUAf$0E_>~H~jgmi%}))`%g3eb07!N1davSdte!oolN zre8!|&|g3}W(RQdADl3VJ2-ynL52Ld!05di|FqzQmn+FHz5ATkOaC`Ln=G(lEpSEa z{-vFXd)L2bbNvh78#AqS<*Zp)Hnw~$ix#?B@jeR~mKn!A_p9%H@Q{D}BzePwCw%kq ze{D7Wu%^4F?O68a7DyuKHV?Zq_I$UZU^OaB$=$ofX=d*o>W*crNcnU5rfE@dQ*%vb zIo{x<7N^%)w=~Ozvd({XbsCadIo&un-Pq{6D;jOosdtT>kLQ2%*KNbFUrlSPbL`)- z(AQ%uy|&ZqoMUy|GWrN}A7h-brr8pMOcs`|%ssRm_uV z^>yX@Dy<4v7~bz`DIHv=2rOyQ1#X0cNK!}gv0KcUr{_0J+$D59J^M+pL3gfwzjggG z)7!N?eN~S#Q80d%P)p~N>|f_l!7lN2`tr3FM6igAEZ`)&(arI@(Z}(-iLc}5Eksxr zfKX);-JsFt&8qe4`VP=0i+pP8GeFUpt}6wj-R@BmV@KbUccR%SeeEaqs5+afjH&3o zcj^D~fmgsbzu0r1@X_aHJ}uBL+BoF03HsOQ6hUd}mhDGT3)qpG(SC*?n^JOSw5&+# z*u-W3ZZRw1FPhZ^l#{~T5fKPvm{#?C)b@lYI@sqs(^f&QywfOWw;qNTm z`grFHrwDS6w?7w7A0PZZ0sZ@_0y?PZ1Ak}X7Ox?~P3N(~`Bp$?2kDGGrwUk~Prnxa z&81$q4IAE>8Ha#R5;%a;PS@7DE*!+zUld|z<<`aD+sr~_5Et+_dk2jai!Li+6 zBm4;A>~TPcseEjGDB0DrpR9PyEdzg6Tv<)>Ld9PwwY{IR%93H)abJbohc znE>BSepBfiD4QMlQM zyg66EJ4I1v4f^ldBlSB>Kwjq^X)SZRFz4%+vW6duvMU?J4;=`bFwv8|P925~Df6V0 zea8+KK1e|PDh0CyvjtUxIRflS`C2SkB3LSD5F`b}2Rn}z950wDm?x+akapzrLj>gU zeFR4d4i{k4i2_Bxi{4|!O9*6QS6-u>tr{!I%gqtZ@QtH(oGJKw2S3{3itXe!{Uke2d3{(R=JPBEk>TFSf#uWrCUr zAE@601o#o!NhB)e#|7Tp;`aS6JL~(~kai_y5B1t=yDbmcVziJ=&n63OvcM(_Y_h;6 z3vBEbI6HliuFAP!R{xFBr*kh`6O&tpGA z=tB;1H;kC|eDAUU>wIy4oEL66LQLYLqr6uRbv}74+PqXi#NXzQ9SvhR+=uQ_7dNj$ zynWv>o&R~B9|+*XzUwjQ!SFyFYPS2Yem5YH_qBhJrTO${>wG`)=>E}#r8`t6;3P)6 zw(#i^(rt!MmyRwcIAAh^Bu`fo`RM|>(Y#*}`9pVXa^NRhkZ}t?A)GEM_%Pvwg+F@= z#}9D2#&o}->Gm7GJiu2*?~(bdz;x&*e@thwoge(3Dj;0sa{`mUNI2bX_*Vo+bhD&?OOp3k2n%vy2RLhZvkP_)wV9VeM->1x9K}RClnp0 zH+aedqd*?9m`+ z<43y}t?0Zb71BhsX*0ia>#Ki0^q4Jof8y?cR=jY@6I+~dc<1${?PWW7se+TAFtY6`TaN47IafaOL_0LVkyKObD8_lbfHzYALAP zv)YHNIjrIdEatTG2l$2uijvsMVUb4_fk&|cUVr$ZM=!4X{0}a;=%`&^x%kv~E?<86 z5oO=)o%b)E|0wWH^{Qs9G>U3VkFr&~XAsvR7OW0;nW-D2>br>B3vOyy76b7=P-uQqc-#Abx?IGvhF2X7o3O9uv8aXNfa`OEG zDhdkr6#@!76;OYHRZ3qMZWV&zl#+1*{G~MTO^%;dGT`&f7Em$4uMtogfuAU#k^(qC2LIFCX=Zyj@ZTzCMl}L2PJvxD-2bHH);KU6+I)U?^iXI#}s|1nPGmJlW zAHnqYduQ!(+5;~+d-a{rt8`cW+4O9(z$Od)TMMkNJ-9SivnJD}>G=4ss|h|T%Hvf6 zt_N;k4pD2-d;E}7p1kG8v;KVKekaZO{ovo6dH%KMU$yN5MV2dQQW}7@D{Sf=#g#E! zT*F=O{yiMK$-Mj9(8H@_>|XAb^21+^!wuOz`PcIsDm0$m1lENCr{d;;H$-5SDD=Jp zda69o(*#s>JkS8WJSs|hpH#S1mQ>ov@&1zfDW#p+Tk5+cvL;|_>a{MFou}*XA7tIs zXL&Ox40bG=P(D$ue{>25$G36LeQ*qiJBZM2qW4Skmz3}E!{dMU@}fP5w4Ac}U$)<= z;X7ZLQFhkm`L^91Bpn@6?VHjbt`2Yu9nw0H&~2gCv^VNRA6s_BoqclV8I9z|Mn^+FfsfSt{;{V32J=6G06#Upp(~^xdv~IhmC1%Y{ zwzcV~#{%y7aa{z*kLylw(u6L8lO_}jYT1b{!gSuZXvMKKjl<46F5rglgBO8P1>7FQ z1JwfYLhbaz&6XD#r;uIbf8If%J^{NY2Zb8t9TcjRX9tND@It@y>_C%%*R5!vLteB{ zfoVSP#a-6QbZf`rv~JyWOL-PFEKa-C^3Hjcmv(qYD>lf|3s&l!l`3t8ZDB*R=lMnE zmgU{(iYK^5&fip_o~K{VK=xSBlG0hF{@BOrL?i1`irMiR1UYks*cS@#Z>)YrRMIMR zxp7U4FB;W}8Xcp{Qkt5Ky2^ae=t|A3kE!x%mYoDMPSn1NtUKIvK|}OY(b7?sUD}k? z(Y!hnHZfPnYsPN^D!P;|yGUpID*Ibh@*x_-g(3YjZ7xWybW5*P0rx*zV^pJ~UR!h! z=Mvp-C${^E+3L>gEZAl#%#ZWN$KGsJND=?QYLR&@VGG~-9)Er@NW6?c7z@I$8dcHu z@J(=w>TbSh2MF#KPICa>Bmkc(xHQ7)V}DLyeQVa{(~m~}7y<8@XJnlO-we?7v5^@n zcwF+($PX0Y&wheu0v&!Qw}gvMtXnsIejLd3Rog~WLs*^S(*%ta+%G10x!}bJKS=m5 z1AjQ1lBNpX{vsKgL;QI&k_X>GGU$xVYr^?O=eLC8KRDkyd>^3y-r^H4_~0KQM;7JnuPH$5vvgEK%=AwD`F!$Y_{KMVY1EeN_H!?}T$ zzHiI6xP|_Fqz~bqD0y^1{wU#e0l;sQ40b@~b^+gsbSoYf(ENkHC@}tO0so%?f4knX z{80Ic-`Ih{Jn{+t5I6XQHA*t@k+Jjjz~>8y7qX8^#_aa2aQ$~~&z1hz8NWD>($b4T zLTt`cFF+odzse^3Vv{9ef)my<;rI`p3i#Q8zgoEdJDIZrne&BPK0jIS!Iuio7Z48f z@cZ|UZ8Bdt-^AFVG2ovX@GlMcw+H-h2q(R8`xD`G@xb2=_**HC#%E81$#c1@@mu7E zJT_IZMu6SGe;vhzbm=YI;bX3qzj(6l?Mb8a} z;>N;ba8%}VG=raplOMqM5!jE73mkU!vU}3!%=#iWEGZe<>l1I6onAUq$fjqL1vXh= zlLZPaklS-wX>M$8m-T)mfArHNI!Vp#+-BQ_HYCU6sjD zw|nmR4P~F`ej~o+W25B0(dWB&9F=|hp~hRUYdm8Aecye0OhehYE~D|@B3$bc-k(&p zV4=H{LW|C6^6bG_7y@JQOH+s;z-hYRW02tjjLJKjB;yOs8x(v^%hb}`kh5lPD8uDP zS<3z86tVSw^O?iz?%Va37d-jRhbNyo^`g!19b5fc**BxBR(cqL@uuXnCBHU3AAt8i za>(ToiH!g2U)Z_*%*}M=xYhQa?HxHrfoJ&;3%G7fNP|aw7;5Gxlb51zU=N8pR|JVj z|Cv4k?@6@D0{A56A_099Wa1Ut6)gh(1qc30o85HXu z?rY8;zN_K0a5~VB12(48wY4fXA7C2Lm(5v`2XS8Pf5h{L-*CXY>*lt!{qUN%A3AKi zPrP?{*=wcwycG{dFdJ9s3-zAm0$p^)hBDm^;eMm79uXDIy4p+I;NwLjN@vMwWMif# z!xL=TFLdc&Du;28UU#o_?P%9mi)ysft-c2@{mX8>^sizso1$TyY-PLF*|g|t3*A2B zM|Lz&rTb=50Y_t*g(8a*b?v%~V?|2`M{=`*0;rwrYI+jX-y1jt0G^6946B(PD<-Os-E1wz612kwyg@w#20e%e@{7-~a_kBh(goSQD6i!&91uNu; zx`=nv#OGU|xI8MH`U?Mt3&7#8kvzH~f1z;r;Fk$UPw<-pKlc%Calc7^QWv5F=TzV~ zezNDubU0RgYrOT!#f9HriccMi&Id>ynE?X!qnJLl5BM`uaCn4|&@b%+dVzNe7y|+S zT!7y%++pRABg*R#V5Up zSDoZZSLBHk{vtG;cSfmdkb(&9I^Ah0y;ed1=b!iUeaGsE*K|3 zp7srYuq!&#o)QLb0N#b}6OW++c+mR@$Sc?dz0ke8u#n|FHUkI;8|cA#e!W23 z;N4Cf^^4a?nqJX8S&Xv3zh!ya^4QddxCU|ES{Th0+1V@X<@2W?ArO~!KVtRc_(q_AA2SgAbKF=?XqlO#CE2%+Vk6I&PnkJUBAX1^)a(II{3x7fzl8|Cey` z8908EPWZ!B(}as|+ly&#_Yh7xB0o_$`3d|m;pXQ|xh3!5mOF09f8YtpkZ+M^&lGtL z{50X@Iq=U4r!D}$GLXMnxW$Y6hD`n$;ieB`Y=n#3cZHk(eU!n>?Y6?rp1TXTum%b@ zn~xQa&iFG|ICchKBAl`So)XTOANZNV&4%3d1CRLTgd+ofxnw9yyt`Yt`TvY?3-=}A z$RhKrfd6~p@PIx_B$MAxxW)Z*3JbTu^}^8^{Ek4M5t28%JtRK%LFQ@U_yhh+;iM7x zTY=2qgyR-IZI8KS?9=#*1OD;CE&nVRZvL+kPMv^1mj^P}2mG%HxBT-h;nXR}za!jq zo2t0zzq83qA$v#o@0C%>hve5p5Z|d{C`-7!eX{tLPbNm?h&+G3aQG_(Yb8TD#pYKD zM`!SRgj+th_L#E#Pw7Uwpy#h6Kb35~%7kMp^x0lGet=IDlV8I9miYSb>cOYvzva~z zgv&7IkqB<7Xz910{rK~u^({11VuXeF9;{U z;dYh6wQ}?s;Z`0`moWZcDj*Fh3-=1{2xOiL@Qmb%Y{_?Ir$ksZx!Ekm@bc%JskfL@hzV}7vQf5w=(jl!0q^`y%4L{ zOyTGTzJ-iT`66D&DqNYx`M-_$rZaP5_=)^-;Z`RMm5kXWA-C9;w7WLKpAToN|ai@Mj6o0errIFu@NG@MDFe5B#)1!8yEA9^xl)IZ0rCt`TlwohRJ< z|EzHHpY%5T`T)N@zzL7?%kR?x{!`)R|8D~PZQ(l#kS|d^j9%dAMOe@~icgxtpDRz0 zhkv|qv;RurR$eX^PJTw_F5#A+Ictpi1b-e9-|9W?ZX^E?-gDxc{~}$u{4S6IDR<T3C;;2eLr_@oQ+69TvUiJm7ID3Hod2hsys z{HI?sK*0MUf^mW>!O4Q0V6}ks{IuX)!3Ba#1nUG>2tF^kQSep4V}i#8PYJ#$AYH#E zC=o0XEEhZ^IA4H`uqF8uTkk0tBp5H4AZQm{E4WVZWx+(j0Rr;w!Gc2sQw7rmm4caq z%LJDTa7%qi{q#w}Zi4=T5dv&Sys`5f!CXO`V3nXlaE^dHdy(K`!GnTt2+kDXCw0JJ z!7#xX!C1ipflTho9eHIR!6?CDg0lqo2_6u9M(|m|S^@ckys@`nxS(9HNN~2`e!*7+ zj|ln-(0PBsJ%VEe@CFI62evp~K-$7<3Gi%yXN30=nC_ zPVqupTrK(n#54#8c5y9K20p#tJCRB%v)kJj%|f-MAQ zYx2f2L9KvvK3zb$9Vx&bGX!bDmV)=|hVXEAqJVTUcNR_<269UU*wW;V5RUH9X9&V~ zj&w7jNpUn z&`)lO7dF5~`w6hqrv%t>Cjoh6Ujg|9`(Yc>5<4C(z(&X&DZr-S$YWFT0q^nSvob!uRdu*P1^b4;_}5! z8Gns=`QoH*6pE)y{@Hf+E|-7(McXqP{mSgb$$K2I z-Owk>zx2StW#8Pzrv@&nPfW2pIa|eUGRFGEs7R5t9h$C4=}z_h!E7g{H2bMBMM>D! zYGFEF8-{+e`qjp>jQjPAZ|(H86H^K+L3&GOdZI4bT$2JzxBC!hwI}OEyG88&cl;(=RUE%xKAdC`y# zBx}8&)AifjthLX1B$_dV)-jWAh&RN2RP#ciqO}k#8hlENYyz|@8;}yr#YYT8Q>-1W-a^N72A_v%K3tq^E5mS?c{_OhcwRtplDQ2`; zbEfutYB_q$(6*pDj&vtcCFIU~%nw{ouhnjymaN|+IxCZIZ=KdLEzwl7BFVsbWN{yN zw?DFm0dsduWJ6NZg__-4lwP@{wO+ZR-tF+$ih-=Ll=69=_rs-ZXi&%SrGe!Da(^n5dtl>-PL2c^xoXQO9YZixMX&eHXPe^zZV3=^By5QJJ72rGb9$Yn&ybtlPqt z*rd+8*OpJiY!7J6%a?{IfuvWA`CX*>sCE0oFZ~aSLXcKU^8)`DMF%k8k>Q2nvZ#BR zURmL@H1o;nBg0MkNz2{OUv-9RK60Ek|}_rzf&? znPe;VK%BKC>5>;2pYS?%B2!?tB6gsle^a2MW6e*jlX2Dia|L8zvuVmKnw{5-eO*VKnziIW?o3erm6ug5HOjZTa6r|0ETqF^ z-3<$r>^yhIikg(pw2c|m=rb~zbZoIgP83aT|41YoTR3$zpQAaWBCdT4sW=K%BurFg zJ3L>n6jDVlyg8kS)+eaibM=HPjSjOaSVTbpjtYVZYo4kWGGvpsa9f>`w~Nij<5#Q+ z>k8Nrl1g#~MO2UjH}1`hRd!}<{6=RWyXMLr15)L(RMbcn5OGK{td<3+wR8o~>YKS~ z?bdPmJ#tOD&r4()6Ek&IZcrB%^P*InmvpyKM2>x-j(BWfQ*T1y=CzLA_&U@J&rj37 zSEN$fITQCq^5*qRCsZ7*#*ZUJ`mxa{@4HN|4n$RpGe*o+CF=v!);%2xoIJ@N5~CG) zQC+SW7rgQtk<_J7qryAaRUl0h`Qlp4i>%?;>~>N$u7j4twxoww#SVRdI?K0F7UffX+p|$UXeSQjy;YA0JF-4esM`nzPD}46 ziHV7NXDw}R31hw!?>c1pcU6_`*|u~u%3BRev#Xr$6m};f%+P%^^pB#sXK9jb=*Xw4 zGjF{+ea0(a6*Zq#96?R0CAxB)AJJVw7H(K`SFxH;Ms$bV1~?UA70TB0CLfD@>UQ}W z@!jdX(V{hg1(~KQPbrSBtjBvr>4tI8c-{m0pw_mEy?r|Hk8r+W*WbNEc1HgoZc4g8&!zjd`T)1fovb+%1wQ%8AaHnMvfs^S8ZEDLcEwXESpjIMXBNWx(;O*1eMWV+{!Fi~=$2n44|HU7bF;2}O4e1R8q*nVt!$n*ePXxb(q(>o zb8SM)_p({tTUtL|xqL;!eLOCz9M`RzMe}EM&+kE{>e&@zyLF%!<0ek(>DBoCC-n4c z;@Ivr)2>Wa;ysy6NupOWoQzQzP2HPSpKkVs$bW1ss;)qDucZD;AN^I(`A~etNX;7- zaRxtF{lI_(u$zDx2k@;0jHK@>7$?|40Dp#n8UuWhfDvHuugD(;QNZsC{A9$^{JbaN zpA_&*G*ZGK%Rs@!0!CZ$=TQLzE#UVBZf_B7e*RN@232tTErIFzl=#d5;r5BZ?aQLg z?Vkdi9c{=0TM0KA{AR!i|9>VvdLlDKIJN=*m2ex_Iav7a5&yRV|Hy#Psu7cK3;1&8 z`27A!e2e=9!uJx7u&}pC2Qr%*pyC(37_+b5BeEJLxfL*u# zLmX7ke8k6i#a%ylskuMjVe-2rf7|1#d&WMu!)41)c>IQe7wviU_sX6s^;K!$B03c* z<`j&LxbDn?_{hKxt-W2O?eHu3K5x}>=1jcgE*=GORj++>$Ly$Y)b)kiF0P$5<|hmK z^nDh))Y|9ezEjd2Z@xNabXekdx_7+Y_0_ZhTLT)^Zn)vUp{e(Yz&uu{dD!-;~iK2_Fbk5eJf3Z#n7q^?z)zo@|6yAEBf!L($XJJX=LEu#w%+qD?otCY;@ zld1=;@=C8S;G%GXb(eAA#cL_M?HsCi8us^WOuV4e=&}vH(qJKHg-V}2v;=Rcs8U-{ z%TTH*`ILBS5^4$NsHz0Wz&}htjRJmjgi{0E9^up&nFt@H-#z3%^5ud@1mL3uKZ)?M z`h7jZ$LqH=l4nkDQG_$ERukdOtDP&rABO5DM*KsBUm~C;LpO%-snLkn$cUzfyg>jT znN~6Ihd6F7ocJP7?F^1gfAOtGUM@a3eC~+AUd;au58R#;xLqPX_Q1~vBN@W_WFUWf zAU`MIv)<5jm>@p!!Jn^*4~`Bq#K-pVzb8I8{7Z!M3)~#wFAApxfPbUhf}{U4;?t7A zPYB@S*EW$nX>p$bTOso;0j&)94+ZA-1o=t6A&##KOrJ{O@b$XaN&18Rk?D+dm?->D z0!zC?6t0C;CERSjOt|?;OKG;1Q|CXwQzD$OP7&Bt4QqtKiOW5DiJ#~|Yd20nTqNS= zYH@2VEAI)1JUd1}ejP8spZx{oP4Xo9oBU3mBronPz()9q&gRGab>ClZK8$->Yr+QT zvG7ZrXrak3=wxx&N4TZ=f2!y3Zv3N1Kw5_J#!lFuI1v^-7V-2@1*9+WM5mzw-jOaN0(`1)bo@_s9{2&>(Odc;;nCarAnxQ0Q{=}5 z%Ia_1{+-wR9pdxB^j=#o+akHyT_u~j1qcZK2hUkk4=v3dw|2}1{%nrg&GMqLlk#Zu zt-a2l*jnec>KVTrE9-A;rnHm^z|LTNV>?cLa(Cpp`A>FP6Nsh z_`7kSMTtiBe$=hffRa0nvwN-^Yph}@bA=O)X07s`Rxu99h+sl{xuQY1d_dNnah;cd zt1e87>kTllp63^8AC1JZYixzQkH!&aW)g|n>IP}hOY?hO)LPi4Q;7WQNXmC|HT)X- zqH~Yv`i3m;XmL7n<^~EGd@WQxuWP<9<9kOmz4p+Jc}oOEm1>V;O{~eFNK^e$+-Zh* z4}PS8Y6|?H0;(e3*;&otZ33(Q&lFBofjmWou&AQ=NTbT4`QW^0Y9I)dWKDrS`9i3ooB=#svc^Uq5Ae z^2slK>DkXTWXpaV9qV4Tpo`05MlsDyYBqlkp9L7LNGKLwlx%EjD-dQ7*n5%Agwk%7 z%w30dTO~u6GDcqk@ro8c5W260s%sh&{@k_v4r3K5Y{aeJ-Pp>BhghyB}2`FIT z?+7S3u287JpeF@lw(tS^MJLvcGr|GR-O`4O%ooTjgyRlv{(}gor?O9z2 z%CZVg{AS!4kOeYRwn<-R~UJc>Vj6n9$HB<6q$`oN-IO*frlI!7CspboJ@9%fJ_OV z5KsufPZ!`0{1O2L5&RAT1p@pD0sexsxx0Ua|6ISu|GRMWbCP6ek&#D7GCg4&FFtyK z4-kL@LjKPHe7>iGOl6c8``;e*lqnI@b93%^Q$eZUt9&@< zhQ=*8{t+&}xT6450Z{mHOXWvpBK2GtovpJ=bE7(^ZQvG`!z=Pr*m0qqchjz)A9Kmm z$#pL!UOIW)37Zey<%qk=qT34!oL~-n$YPj)C}R>HXnW2YFsn3IxpwO=QU3VPXU;Dx zjaH>{>}VAG-s9KZx9hi;ePZF?b4T@^amMb+@*Ow(R`&afM6Fh3w`c`_lUCjHn^K`@ z7M|&qb-a`$Iz%P3Iy^1>1YvdRMmB5bLQ20$Q8kinlUt5%PH5$Lji^L{H0~QE>yLGY zs_(T@avatihFmOXGK7sr=-TK)33Vwv3cAT@TcZ%XG$G(GoL2dhmiu=3lNF~y{1Zhb z9JDyiliCxC_WaFAwnna6h1VCj`e2$`e6U$c|7!JHr#(f+CzjZ>*@ay!MIPj#7y>-} z(th%QQw>qw@j#CfkYCBW(2Vm?)Oje%vjkL8JkYfQ%iqvV0*XEl^oaue;ekF`5W2rq zG*uc8@9&R(jecARZ9EU}0jfu;5G!N&PZ{JL)e+SmRT6qom02H&xFSnc1Q2iBpg({- zRhJ&jkRKNqz5kv=vitq?3BoHa`Bty3r*HA{Cw41)L+GYwlLabf8PVYdU1`O-~S*Or%k zCOXY7@6_KTrDcH{QnVSs`5HA`k%;|Vm`Sh}l8p@YG1q%Rug862_|N?Kb(i&OMZ<5w zgd&ZIJ#+xi7C{3;V?tv^14`pU<4B_ee~^H_F#Mc=1_=JK0vaj!G`=)u;5^pQhK*H~ z_o#vH=Cd)deo+X!2Ui0?m+$cP|o*4=^(r?=S*1 zExz?Kgys`~83zoA49{6p=a=TH*B-Qi%abi~EBA}CqD6A?ofom)o?CLk4>!AS-Emcq ze*Ng9FWm9mgRkD@-m=@G0SWUa^rf5iYL&^>rbLDntbt&%Zb?gGl{S@7)b#c4#_#h> zG^530Zg4Ne@q~37`L%Eb1OxW7=T%fzc_(g9N<%u+td$~(`T|LDsx=^>^8o8vqKdcG zUDnwZXq#89+p)%~1%4nhU-aWM{~5Tm$FdL|RXU#Z9w}GgzZO`BbU)$4BR=24)Em?d z$45BwDFO8Y_?9Y^WHH7QP7$~csD3{!pdLYn0XSs9uM(Ks-f~Ns$L#>&=mWm3aOwl_ zFADe=!0jUf>J9L}2`C20d{clw@Zli?e|z}@P5t&fv;Y|%_&mEvhI$Ek!bb*O#ddt+ zfNd;Z@NtV9Y{NUkqo|=X#S$AsBa2@)Scp5^nBR2z!3h^z8*bwd#EEd=!&_57Psib& zwV{i!Zd?tH!~OePQ|~$X>WUwndi53^*FJE{oxM*U`DEGs@f~_yhPd6WKJh{zyS8q6 zM@x;40PSWzU|~|*7&UTuV!Rz98`Zfi=Ft#&MinTlV>RNf1=sQV>+WiaBPNcST&clJ zc9f~H&E{L_#WmUGS(3^giVX9;Bm?GehM63i!4J}WVcTVc#l66d&}Nm5{_H4^(_Lj z6Egh5$Nl93cw||g)syFH{AbO<8@Q#&Crr6ZnQ|64YiXU0|MVHV->qx6yl325o!`D- zVshLwr%%1~<&IPDFFVG!ta;bYvAMP1x#@JPKPxljxUpqpMDt0$&dpb@6jgi3AM-_E zYk+E!G$4KWj>qQUoV zE9uqm;eNgQR(+zn&ux81_P(+AC*2WHc=?e%t4cbvz1N%B)_-tt_5&#EkqdQOTI%Tb^t!UMq$Ib+hcX2# zG!v`pn%J~do=Mavv&+Vok1L;4d~NF3@`=m*a!wOogfMFCd|FB8sUOBFEs2$FT7Q{t zXe&QKec5GW$Ci&NA6KjaSGQ@;qe;^1bw;?obB~hTfgi>Q-5w;}s!eJB4%Pqg0O`W6 z>2949OLEIUjCH!zu0f4hYqVb@Tdr**Sv5|n|4>sVi}gVq-FUk&^28bSe>z8%${z+;_TmgII_zq%j&r@ubJobhh#+^QtE`v%jd zCDE3RZc20Ne7}VMz#&E62F2I=3sy4OzeTA5Vce!r4|TWjaTyN?E^3>u{DEg6f-2*DPf03wr-kN;*GO zoz$34>olBlbsgH$we1b+cXCN?mte;%o8<*nM>s*E+k8?<=gJQg-8z4QNlI&aT6H*3 zBBS(B^WQc2iOckz&Ve^9{~_oJo&8F3pIm>~A7ORYoK+&pNT^aqS7Y}Lrb@K7*KQc9 z=-jL%x7`NQCTiPdmOVRnEy+#X(2BTDM!aR-A4ax)=guX$u^WkMVGn5eMq{&r`2=z~ zLkFYzfVXo8%imu7(6ASFTFH1+pT67lD%o9sHa(jx@PFF^xqgdEbK^T(x{L{JfTeHo zv1YcGzW4a#KdybL>W0c64|wQ++1uA{|5nR)p52~d#=_-d87;x`i@{jdmej&8DCz(n zh7}nutu5JKZ}%UO1mivF~ zy?1~fRlWb8vI!leH-QvdC`${yZZ?I5goJEDAVgua`y_eD?mo-&?1n6;uuD-u1XKjY zLQ}v378FIX(*&^qSFv0L3pOklQBly}>vd+%%sjgrxcB?JSMo=mbc%9StGa{-hs5r8bDX? zX{#&dN}QE~-LBc|hPke;%D*z_)gfoD0dyT=Pw-Wj!{d-xtd_;Yb%chTq)U4UHz_DF zW?tz{_e~B#TAamsxPbxjPCPTccH0m zx!-X$VR2>U@HoCwY*yfJvR>2Du;y6*clBIVY7EUqbH??VHFCjFEQziiH4Q9(uDi5s ztb`|eiJO={QQy*ZE~QC#t|cvVo~K~+!+faVm!%=fOh4n4tSU{)|Im`WW?ijLYC=D` zV!Zl7$a${hx$#QZYr&^3{Lu@$@y^2;(BDQUXCUC3gsjO&P&T7bZq{7+#fqWxzFzWDcc+P zJk;lLo*xP96zwd1jyD6i8prFp^_i^CV*UBtuM7Bm&kon~Uf?rX&s~+{vtz@vlbrx= z1P;EvJ`sEz=%3dogD(QZ@wY2@0{HCDpXX147{2GvfH;`<{4c;~g#JAL7chSQJa_+q z7=OJ~#FJT+UrK;m`A{ zIQJR0KhJOGT>Bc*b9W|+_U(tv-GfYD4&kQeQHc5C`ToG2fXo|z2Y{b*uC4w&{|)E* zZF+nDd(LBe9K^Z17RB&9-vY&$pPp~ec}&lPIiJLNjF0DsaURpdbN7F6kmk>GzZY1% z-od%gjs1DuyS3tZFXu)7FXP;D8%^ft!Zogw8?UA zT3H^<1M}6o<~7Tj^|28cKjUOL+NM8p_4Hf4JwdFuo~vWL3_~63q<&b(Ous3>B{}M9 zk2Ywp(9Hy(8{?avj@=5y@2uC7kGVFVA>xD_-RHqFL3_rzuWVx zDernwd&ly%hz&Oyb7}Z!gi34I@51(l;|34Cc;{jFYX9B^!Y7q_8(sa!auW8e4G%(- zn-mtPeCMoM$5vlic<%Jlx9@uNr&pfRz3>P7j_*%q*>E?#yEcv82HcVR_)4vJTEG4T zN$`vp@w+?fu5q4T$;9jfP~~mt>^w7NRjFm3zRu|Gt@bCYSj^P;bMcCW%gScOw2*o( zxA4WIg~!6}xeJsmsPgF`$``yR%XTi(8VKdZ%czUU)6yBB%U*$}e9c8kD-i+=}Hm2}#YtGU|O5|~=$_j^? z``H#3!X?)&2I=RU3;xBG=q=NG+Y4eoEE>ZpZnN6Le0*0W*q&^`KW_y)7}sgEmfiEB z;1xT$vLu=fVb|nh$X>?zj7Jg}+eub^wBUBQnNbD53c|jnY&ywD4EPp7?#sxu2~{`f zjhpEfv|LV@@7|lNwyzehhmA4ZAigLY!Jn3HKY-9XQV{OcS?vl7CJLUU>lO==ba(IJ z5(`mZce?rQNFk(UqTn(~O^WVF>aFeUs9#VH=V49KOtxlDJR5p>xU{z|q-kMClA@ci z6LCxMl=h3yar@SD(k2aig`x1yLb}MaZZ^Aa=d>(8lDd{fFI%n``Zih-f3|qGc6PT@ zz@ES%hWw}kp9i-UQob12)yh`_yJY!mX`W(N+z#IWncebbz?M`Ur=x7`lphMWRg~Wb z90sU!H?RwrKML&9<)@%;i|SC~kH8_2az7EROg;&2H!t5G9^H?x@oVk7>ne)=GDxul>696S2li{VU+g|Lkqit^F z8TlXKQGX+v{210mxcQ_%2Nk%(X!A^YS3!P0+#!>4;~LZay~ypMlshDjdG|0phV>LY z=GVXAF|W@fjvL@k`{IxcQRtyOnje-Cq7YzO3cLtIEA222dxL#IBQRZ+TW+*>GH@v7 zuy!wCy6CszYU{qh{L)WtFfNt}!_-dw@tSdQ_-8(NuHX7+9;xg3M4-NLodk9VrseuT zoe99VOY_ z=$XmX83?XslAWwGSfXAkp%xTPn(u6ua=h6hwvs= zQ+Iz8TRU`jG}ZF!yaC3xFnlz`k8iMgoWJhBTx(|khu*lY)Up{}J-z*GO~L0E+Iwdt zyFfMNB-?E?X|86Lt2I7;!=LOz`WcgO@Eanbcc}5ciYK!PU1Zv`*)u*EFsE%bd%w(G z=5`fxt9%h=T7Prv( zS?&>9;BnCkmQl3!buDOHSrW=U2Kj;&rS56{$=}=rHV3J6FXFYF(&BPYOR%uik)?6V z5Juk>7BnWk#qie#;&;%=%ws65@n>T{l@lwImEmY$<&qy);LUI=rScYFC6X@yR%rR@ zz{(^44{C@y-UFTiqT3SO%A`&g@cv3(1y)}91t99Y1s-j?8g65u&W0(s5?Udx#PXX# z4C{7y^#2Zc^#3Vr(`Li?0*Lm14Iab#RcgOFk=rmmQqZ{-9UB&DF6pjBz|29`mjp9^+ys8RLSJ5SGVE!ELSJ z_Pm1Ii{Q~V_an7|H{AEYWBz`iz;A)au#ER^z;oTjG?Am0$>d&h&=9$uTI8|OSI3Sb z%Ap5V-8?O57Am#+XUMX$ND%x$;dnxkv2+5X3${fq-D>#>6`2UxZlwln^0C;aURl&j-_ z(E2U6-Pf&cixp0N*@RN-1F{vZ}|SEzy95(<6jzaxVwhoY(DyJS~s5kUl`9WsD!;x z7gX{M<=HMZ+2Mad#hv8&TdAz<>!~04hT%O!@|NUc90}*ylgR%Y1K(*B*7&nQ@=nsm z!%ASMZbgt!DDcT}D~$3fz`JI-gD(dc@}q#2LH<)}nhl?W>f=CkI}>i>q|QmeN+fRu z4i@EYAnKIi(KZLiHh}6_fyD%H5s3a@29JJT36FmM7JIZ)f8Ph9&9}g#|NoWRtWM;n z%_otoGXc0!yKdzl1JSL6U2RkT84%Oqo&x_O+yRmHYp*({&%+@4^Em!^Z31{4#Ju=k zf&U=Y(d`dFjQdaFF<#HW9i$o7-wN_LI1VXhV-}IEbuV1utazSSb+`+CohrweU zkAlbia@HuuWez;rkCR}h$9V;}J`9d--3UIqEx}{F+@Rkug#+RkM`x2_IeZ&Dy1f=2 z-M$YV{r@05mW>Y=_?_@*r^nrZ4Z7h?0*+aYtFtD~gUw`WO({JrCABFmnt0Ol|_2ib1OZGfv++fRPYr`PQ zr-_S7OOFp<^v!2G()=EM&>!!)={rAL^y$Xmk2>M~pFd%bt8d-pGhe)pD7fM$S)o*1 z@)_6ItzaDG>OfaWC3^$93eK^Y>#AIXRMbdTu(@QkRHx%wv$$r@HH2|}+wfIP$rV?| zx$9rP>SrV?U9;nw#AH=rz9wtU>!Mucmamy|HC=J^cnHREJF4AXe&m-@nMhGqPsuC^+-I(aRvYDPPo z7kImHv;p-M?_n7r|8ny8s__OY}E(O-5z`7JzmjdfjU|k9@ku-M+Z_->d>Q$ad zO2?MTWM+N`G3hh^G1xQqyU)Dgu3aAb*j+oFeAj}je>?u_@yRWOtJEszba(Q#@N{al zut3I@Fl)Y=E}w}CJjmneYONMNl3w_}_{&`%;zjZ;n)*dLMH@!Co_fJPf8Bm{r{3|) zUesruh3^%t(cK7Fb-1u+%}KVVYpFHKW$*gx1I@i1eyz^wno>IPc%-X!&PPhcJnWIK z);SMrZ+IeJTuGHXAL(l9oZFtHXoe&u9KNm+zA%w|=tw_CzLL5($ozxlVX@J0D@KaF zKIe{Eoy6j*8jtfk!&-oBjnRZcQ|8_7ml$6=li)D<_i%^D@=w5>rE(~(%trzasrLXA zQ|{gCgp{w~I638)bDWU!k8q6g_3>E0^z*Oy@9Kw7 z72Meg;~!^$jF0I`a3L+sTe;yGe!R8P_DeQBecXj(FWvKHTlD{j-B0Rvj8;aCL zF8aX-WD9XhJV<)QWRA>A7k@Sg7C;N573z<`!f4^K;8}Pq*o`1Qf4>cGVO8fVzyc?q z04%8T?*j{|{0g933;wCVLLcTTxM+b^$DiT(+XaD@+CuHzf|Wu2Dv18Hz@tCgr}~IO z9AaE_qd!)*SRvwkfnlZ%$3f6+Uf_|%2Up*9&qE zte7WT(6Ik!vNAsvl$UphjX%44S)s)4pFMp4PsQ}OfU>};hb#b3LdT0f|v3@Prwe}>1F)5f?)oBTf z$-|;I*W}v8z1&LM>~lolF~icIW%^MHf#qoucmv#WY5AT9w>&Ao76qr)r+{1GmK*t9 zaP{T05n7Jaza7q{z`qKyZm9DJ-0SiWprhRL)8U3?xL-@T@?{12*#-W4{83+jo~58# zzApqXAh!-GABX4GPx+h2Bz8`aQ=pB@MDR4w?U#V=tYZ&=2?hR1!nJ;B&kp!0*U!D- z1Q+;Jxc(@=41Md1`ppHMZj__`0QRV(zVFK6BybL~u8q11p?>PmHR#*+OaQmR?bzhA z@js^jVz}*dyqQ3WqTb??cBlRA&&m`uhJT zppNNw9r76WTj8;s+zsb{(Emz-zl6-Z)9u5^9f;`XGw>Lf=ixDbCB|KyE#Wb&NpRGH z+{bI`Xy-o2H%R3N!(*EGeeIa*H_-D#qn*xaCd$Fxbwz-T997?k7;r(JchMDagXWw2weRM;0ZWt zfjv5i%N(LV z`azQt{GZCv^7a5Y9vCnAsUXTb;l@$>Jj2(d9zGdzIF$D0QC<6+I1qB3r+^D;FI8Pus=8$d;)wG820_32b>LRpckA6 zJ_K$99|m`V&w|ZCGiU)MQD|#U;HX{ug2TY!;Ak)%%m*`oy88j+Ns$SBIY;xsIC@RJ zSwR0z0$&H}90m?OOrLpb9Po7lW(8JHR`^d%*2rG8hYv1CM~! zU`t@!jQ2e7X>bqt8n6sC0PXbLF!uqrO{QU#uMgMX+2EUCS77_1+d1G-up9V1uq>); z`Wj#3=}}oReA7VL$H3>nLa+re+-Re2&DYNW<0JnDFfQ_kfoY|iuK{gWz9HBP>h zQQ%n61ZINM!L{HnU^<$=OTg>F8DJ^s1O4DlKs#RtmVtMJYk+Y-6RZO2oDX!rDQE-j zpaYaZH>iMf!5hH^;7XuB9{{(2kAlsBaWTKmTitkm7PubhkKwKao#4ITeL(l>b%FN- z!!gg!0hfZyz+1r;;41Jg@R5{THr@c<0xkz{12+TXZoCJ;Ah-@#o($(Aa4XmfnBEtI z3xN8UfH#8=0(HIqc3?ccegn7>+ywYd^-tV)@Sh8A?%w-Xzuv(zGw=M#{K<(EZ*6|&f_cBZx%=e3Zrt^eO%~oY z{(Czn^G`TCwbt1J!n={ooXzaxB}k_5in3F9rQfM3)O_y3oNPyUTiiF}b;@j2*jC=P z(}`C>DVy9XcrUG!&tdYAcQj{oxBE^eFB#@fkJMem<#eVQjXFc(1YOwlye0fSscltx zc`&}Kv)S12j*F9hejyW839lC#%IP)&&>nW&DU z{=((_!|=JVr$-C(^O)|#CE-PZHHhbzmStC(S5){0R(@LHYe}K*jUdV=lM5HEWg(lg zavx)uJV;#~rs=z#Ax~miFP;%MW?#c~iY(=9s6{>}UL9*r$hqO6P?5WP{Zd|@3#n56 zxS$YdP_OgS+S!}T*e8}pflX1VH_xl-l(bbL4YDT`se|-W7vWkKR$4Lgb83Y(mZC6| zCkuH>w= zv)tQH3X&hZzMfmz!V~mr;k3KGv#%rfiULc6%KPCNNj3t>!ph{sqgz+l`37R<23{=` z;@PF{<-IHFqsWWxc-YxjWA*#6D=iv1;*}A-D!U2Fhz@+ueoa?K@~ZGmD=8u;nfK-P zdJB`MGg)kt)BFL>kP9PJ%f!Wkw983C;-MLf6hiAB1-+K0`k?uuQ)wAH?q^}d*ZT{C zJhPMCdxqA%I_dBVUUzw<`kn3xRIGZrXym}GxS{8dr9XG@@*#xRtFpK)ppotzslwDX z47g#-gUk_+>@!~IDdHACBV3!=*%qEUCi#%Mp$Ct~2MM(;6NCqX;dx_yZiPNyEw^UC zL29OlW?DY3guaP~;p8+45uS0{3!d1`0!G7= zCWrwk2<4g2f9W#H9dCwD@Z~9Q?DHq6Q85fjgC^l+1Arp0t6`#--ANa##J>$_~hD`EbUwv|lJtTI=PhkMU}nnR$1SBt4E2Li?Pw ztV#-{jRrZ{KO}ZLq}NKGfhU%jkb%!>>%n1`(COY$MNu-yOmt#f5`Dq5bWvVYOd~H1 zU8tvbL&PCN!tmECX{D9MQL#LG6z+)$!L80g;9zfg;=I5{&(65{L#4Bxa$cZe^g*M> zzjNG;W1oer`@K>MTzqI7A9jArUN5^AiAv9>mb)gn0H(I2qte@5>RnRnSh?h+K9|?< zVa=s{IdEpBle?KE`G=X%@_ROoeD<7=yX?;=ZRo50q>WO9e&i;(^J^UWE7$FP`PK*(z(VVFk`AeiUToKf5xb zy23f7uBD}Frf0W1M3mgmjG)`ny~RsjUH7z!}NB zaDp)YT!8UsPBs8eI_>~=0alX3({p(%*c!;4Sllw@=N0%%@aT^dfX=(A?)=ddu9M57Bcw3hv-yamoBMt>Vuz;iPPwNH%TF7t_~C zWOe0}LDV_0z?8l*&_%Z9o!pGtJ8?(>R$B%@tN5rk)e{uY!uRVCiWyfDJYs)u3 z|G~c>`Lj{uznpGJ8oep{(p0MPKN&W#;aU6~J-24GODp`AESsAp!$Vrlk*=qM$Kusi z*4nl8_EkrAn_bOZhFkB_w0>6QCAK+sEia!wqjh>~6aTsCVZ6h*t;R{_ykJ;SocTJV znVnDBNjEvz_=Zta5Y}ciPcJWHQQ`3=K8M!UJ+E&m!(LH9grRmJou259dy{#lpTD)f!s}2OO6BEI^7KdcXRl{_^eWQDVZQhCK%?O z*xY)+NEhbwy|hXf_mp&0siR7De)ECz%V%|Ww3RyJG0nC4%i0e-?C`@1i8#NtiT_N5 zR{MMGj^?#>xC7isGDo(^=QholH*%g2znCR3m-2M-#0ag?m!VhdywT-I85@1gt`%Kn z!aROMMMls35@~Wl$+qNgE+YRB@i!Ndk%;&kMR}>NwO7j_WfyQ{r=S_Ft+D20wKA_P znaC1ifye}Dx4@2pJ(ZgG`Qb*-qT1p{e4*=bgfhd%DE--HIUKMZv&r8HY?$(1gbo3e z?*S&Hd=|%@Q|=%<@(bY(0o4C6uxppwt;l^Q?z26+Z{>lU9tR4aMS`{4<6%n9YXsO z-TKmmU9b9gz+;+xt>E^@aED#$+z*d7`;CJb?jH*JZfg>47(XUY!=2%l3H><|zGKQy zfycCJhsQE70FPzheFgqGxaCZL9)rhn^-FlnU*o5p)4)r}%@_4Yr)enPI86t+Yx<%M zyA?^1cs}BhXccx9|^QWel*Y?`LTeXUT5GPap*Fq0yN$c=>}Hy+ z)W!|$(lB`J@XuYi*H2Byql(-EBc5WCvdTq0GdTD9j@{p3>8Q8pGaPnGVAN4Po z^q&LU@uA|i#w4mJ+nNT;zPZ*UR{RqBs3+E%PJw9$o}DF4*RKb5;4|23Ll!2JA$`fz zLCD109JL&}cGxy_0(I2S*3dzXIBNMn9*NW$=e&KsUMF<@qy99od&A(|;XTx=ZfqC{ z)XL7@nB}E`J+N~v%<&-!I(qC{)AAL^p^il!9hlTGIBV_5>bN|s)_78dZ-6l`$jBcf zCu`%3wIiEz8(aA7P?(Aejn97#Y}+un-`Zd!YZZI|$Wp*y*jHZtF<-WMLgS)x_dy3T z;4AalFV-$4HyWeuQx1Jqi(qcyDdie3)^m4}6umbLY|}8f@2i@vxoyp@tkmcUx%wct z?@mKz^8)w%?e6E!d+7DYI%m?r+Yg%_weh0Sz2P+o)n0|)!1B_#!MOv&pAxNYy-4_e z`o=rm)in5_EB`cp%FfsRZTw9iZG7N{w>sBU+)2|p8Gp))zkzE`>=-{daq#xx<)nB| z_wQSBK%1GYEO_&*#)o&f|I{LiRX6dxo1l zB2JdqhD{`f3Fh-DNEc)p?CiF4`ECw2bhL68-P`XI4A&!7`g#|&m3xzQH#y4|=J_2+ zUF4To%3CjR(KOFWc@i|Ouk3OU)-&OIJY<%~H6iKcVe(||B)vLBIi8NFllhdoonPwd zWUZ`E%A&h9UrBs)bw4J@LtHQwov%q==Xi*6JRMmlhLHL^g2`*XQt**P4|*;N;Kn-g z_`v@pAF(n|7K(t+xJG(bTX=3;ZqL$^1?rV^!m?17^7JpL_SIOR-VEn9K3imxUJqAk z_{&Snoh&pA>jLwT=&9P<@>O+1FNB3;QJ4iE1@oyCd3Z&s<&dv$xw6sn*bEsl92QM< z^VR^%jPnIP(cuCsWm8S}S)BOBWKWfMKC;ySE|!cAGOdL!>|^5>pRTEpU0|9c><43| z%VNW7ymaM!Q`ge+^1ezR&&GS(d6lER6dw3B)oLst>g>;soy#jkXhl~`N9J?9<`|w& zYmFfH>2`WUH_}ztyobd?X<*Hjp8jfi`HDPUvLM*AjOXmbJW0Pu*3?;U%QGc9Vt=!? zexH<%;4FKxIqX_tYH0X1m%farn5@Jlz3jO&m+lwTt7@6`HiJ9t^8x^kHQ&?rtT^KsXzf2sAs9IGXq zp2wF`NEddWOZPhBTd5>hGqtypzg;t(Th<|>x(0v9HM)Qyl3GiRqQFYqjv*J4=jd6n z9&*+6>xl1S4Y_8)%&w*7Y{&|_r0a{Xwba6CX!T+(ipzPMJKOqdrOb+YaoQ)(ESEa- zx>XCOdY0ZcWh)S}>|htA`c#aKY)cnwhAeDz+S*ryb;~R%Sw;uMBHEtNF!%C(ARbvH zO#-#hc~Cpn@I;<4(-naDflC`Q+K{%)e3o~G)*~Kma&#F!8XVtz({vUTl$Y^JjO(Ob zVI5>)U1H*MlAO6zPiho=_RY#;nVkD{AZ3+~{)D-7c&J|RtQ>aNVnjh(o&41TcFYPn zlngDZbC)jbtMP@yQmiAHSMdsolF3F${!C<;*$LsfiB~nOrtwfsRyVBn!;GfXiPV!C zS>+yJm1CIp+ND{xWtz1m-%=}uEm`A+~bq~96 zX}jMRf9+sDsNhPtUc zCO;}kQit@OIiHkdF;^!`vQsj%m8WuI<_K#}d`2CAt~c>sD?Z=#o*+ICp9c5&tngWP z)baUqe109*BKT~0cc8A^XWa1_vd^=lTWEIQ;j?3(}myL{=QW6nC`&$m9c?Bj2Ie!aWi zK0f^x2(Ii?TIS8@?g+VC^rFaEy~ALzTLK{u8O%awdGa1DgqpYHwXhcJIdEEDFZ`D?jR zp6a{AAe$HXkMBPDz%%#H`x>IdX`#~9zd0$<2dBh zP9b#`I;0_|h0Ea!u4yNeYbD_iJuf&*Texy*xQzSI>heQ32zmd2Qt?-&9`6<)wX!f z8uu!1*?GfmA!0C_yjj)T&#hvzytOs(@V*uCOU}Y=Q#EE&dRFux8M`Ku{!Z_U^dP+O zM=2v66TfpcCq7hfPVSbZEgjwIs4o=`D|e|pWK0^1W@11-_B&sbJRtXlf2xFsbo8H0 zuo#4)rmubFFLxG}12A0S?EpL~+;fMg+F_G{tePYu#sbzP?-vU9j>+u~jYJ%))vYd# z!ql>mlDvEnYLF-Sn-A$QK8ysifPHtNQk_<+LC`xukelMNU7$CzejSPAIX80RJ7#U>(|k8V1LS!2u42x9U$ z&c;y%%F9B1>MYqNwG0z1=wqe3Gu**PCcr&U+c!rBxwWT-JN6iEeujz3dO+2)qLB=R zoSF-LZHP?B<@rogtq!b~3@3=tifW~A`HFb^m-!Kv$A!d8Z|$=ymhV#4Zr_2z5V5Zy zCw;|`3&{<5ota504>K$l{Fn*p`x=E(PP)fteo?87ClBTYy>f4|*gsalWX=NR8aHbB zL|^PQhhJc2B~!-3<>k;?^W>4uEV$jv<};(E**G|h^UU(1GH(C)h)GC7&7&eA8~`55wmTCiHuy7 z4&bteDfV+&sA}adyQ-D?qJU^$6 z-G(}5RtuAZbyo^$o~*yj?&`CMXGJs&e8X&hb}bzMOfT`(6E+EH&*xf35|x=Bs&-g5 zG7lWbAI~jpyeXo5Gjr3z{7TX%XNoPgX^fwi%`UIZ9jA^KRhfrl*QVIQr3J5ADxF*G zAVP6%>gcG_at@DWD2$b!tT9ZVHYDw>W#64w@*rrzlS>X(84Zv~X(`Su4js|lWy@-% zyjsp~>*s--Q&wzhpJ`$+U3YRV6Bdfrj4;_n>58rH%reF>2g9V>S=>!Ehu*iwSjH@% z{o|=cI$9g@;xh%Xt_)_O#k!CT21*^YdhIKw@j_XqF{^pD_m4@4d~K2v%CIZUc{*tG zatJ;-AxXmS`pMGTnQi6HFy&C^J()w5EG9&RF*G2a%J>}cTj>z`5$oxrW z&9c)hhh}th_n3FK*$1^V%{V(gOmI?PXI{Rd7Kt-=8SnM6Jy|T>P2sT-oo(S!UbWiR zA3iDFS_=C}~|=@XKy_ZgILXj)H1Zd&u~R*R6goq1IVg{sQ^aW~~Z8BfNpEFP^rktfw_ zdRzb8W!_~^pJpoZEZ8nCotNMS&ku=A>t9@|Rx(ScS9o)?G@Y@CyOxBf-$}{NG&D3D zD+Q8N_-dw+j5NcHMJ}s*qLmDe^NYheN4C0~)l8d|q!m@OR-^fw&$9JZOwaq0a+J+# z&hL1VDi%gs>7FZg5q-5;edUgpFs5O8ntRs#lMd-Ul1(o(B&=_fr%ybxF+6ur@r}a# zMZ$E5Pj?kQ$P!2V!7qFD5y~hZ;>bF+tZIacnx#ciC5dU_QtttW&>kPe3$eY2Oy$qK zUY>HTqRHa{buFL4N@aXF^Q?lqItC_=QXfpxj#jyfY4u!swb%gOwq%ihGHQPs~PI)9BsBxy8H7^@l zWyU6{mHbT#SHVBhn)ZSxMsbW8iqeqMFsx}06O*A`%iPUlXt<2ZHDVO0K^>uz(~joL zYNtyMoGzSkLNctJ2vbSwL_HF* z{+r*)9bC9=i~IHQbhte}fnHEa6x=(puat1o!t@wY6%@rAHpa{8{D9IHy6SwgA&&}| z>SlV?T^PPCSSUsdX(0|c#J>j}=-)%8`j<9iVRu^}Rj2BEWJ63@*u8?m4cmxjVP$Ro z8ZISyTU}T!^WRJg(_l4DlIAlbnU6@0=M5fj2ZP1ZZFGsT&`Jz?%M6U?ggFyCD-JHB_Q*6fb9A?|oKG_TCYpiZl1o*`V&K1}hPTD?}D z>j@)=(z&HmD&-DuU9+6d7HWo7uFiraiOTK`WPiK69+)R{SY20}+s$1-Z1n3c+mFw! z4pY)QQz-Ex_k2XfMCoOG%9q3WUUdBVTGW%)E};enJ0_aG&Wa-vnc#&K~gSe{+GK0r&l3^>@KG z<7gOt$ahQS?}0~qK3U-3fRl8=?a$!GSAYHhH{Iku42*8KgGbx;#Ni|^zZ0EGBHL1?7aPwOIBMbbE_|N}f=Y^1H z|9o_Orm6mEaCPKmILRCM87P}~KLN|(rknf?aKn`!hHZwcZFAwKm3&2kUy0|IPt)om zj;7mF@M}1lR`OqvfIfF!0=fz|oDKKcueP$Xu3*DkvB&h+o==jB5qGhPG4YnPPY0FU|7Od^g0`dnBdlou3XJ4Zu>UcHI1h`)?}5m5yFU6c-}gp2rtLJiaXAhA3V*cOw7Lhb zTf@4MbjEo|=l5fOEGLhmV7QCGqv-3WZV!WNo9TJk2Y)K}VY}1Am9>b~X4u zI+i{C-<*svzO7(q&Xv1&#%@5l{AgetE6Ur)jbiJf@o;c#Zlez+<{~z$c{o7r{*j z-M$rWxshK7x8BMhppX%TVDruxAKSzq;Gyk;ZP+B_v5u|6VC}IS?~Oc`#fy=vqx{f< z{^u#U+Wb-QHgqiO>U&A!CF&yjmiG*vsOv4j!Xt_7mv$fKVhpOlYF z{)xf1^~QH2Y%q@6zXT7pN4^02wL$xr!c9;4*>LTV_n>b&sQ*>`kMcouVjf)rCo6;g z$Kd9vZciXjcY&LpWw`CE{9bfox~)R4{mQ?C0VG|h3qOQdmdv9|2{-!rZn$};|39J; zF<;ICzfapfx!*!Gtn1M^4X*w2v*E^3egRxRUwcfeC-8?$fjY{}Zkac%EpQuc zm`4P)*?8SsaQoMS+XoBsF)24LkHJk_{oEww%6G#5m=1fu@hYUrA@G=1XX22k1)G14 zTZW;*pPf^#Kbw%hoQC+mrBJ`7;g9hR^$1V2!Sq>-oGw4e-w2QG-gR*OSO0wlep7+( zR0!+6gr!^koI*g_Z#}vd{n)?mi+*hDK88G&x4Fn;yZ063=AGgG03PetpWxB{E6E6o za?q&}5#wtUBib*F-SG7e2o)9sJ~Z-Iw;fxHXb_#e`<4`NuB zrFT-8trv#-5Jnmo<9;{kV7nn74bg_Pz=hbUpX#52C!xLK{4==K2KB#)Tg!m_*XVE> z^7o%`{kP0KSkU<{oMZ|519)OO>(+p@)AIQmxaldM0*`fbaq6dW?}n2^Asr4a=*)nd z{<^)A#MidXv43~cFt)d!M5b+y<6kJ$@f&bxx@phF5X+nC_Aa>k^1bjUwh2eUjj#Fs zVRW=dozK7xSN>(V`6xew!lwLCZ~+mFIt~^=+7_V{11F1?1^bO0j~Y(Ood0c4ZGwv_|0DZam@2K0*du( z2XxGL-5vmse$IrGEJ1!!!JmCeK;!-s@EyvG_R9~#{@8EMfyeahz-??3&Vt9VKAg6n zmh%DRF^*S3)Uoc|3fE5gm*Cnae;gj`<8KQ5-6(61<@W9P8PnuL1^@4coA1WA4Ljwg zc`uyk1U>-A+rZZ!o3wS#vuuy&`f1y;1ZB(NPrx_u)4HjjZ^vyc5ATK>7yW+*9ZrMJ zsTglwzZ?14aNWw^2G<7pW+ybo?(%fAOV?(#npmi}nZmoQSD zmGCX`$2_w9?@y(+Y^(D#+{XC+8E)IIKUWm`zUN3=y4_&UyCJ5-{op0SigjT#JdE~C zgva{01)iHGhPBCryo~Le#$9`EBZ9GRPC_S^;S4huhBVNd5RLd}1m;7XwTy%iDIl=Kh>IA@3{Qw=mX` z$zzlJvYZ?RH;?2e!?jKBUV=m?@YQh3k8<~uv<%2^ft$|qFBkZ}WUlsakNkBL@-#dW z&&_N5UlYxA)8;K8h9%zIr$?9g5A?eQjPqxRwXQ?I_rG8Tzq(*qm#|#Ww0HeJvX3(SHXrSv4Nr+Y26MV_5xg-O8^d?z?a_%{L}2^$lw>ffC%PZAi}@k)symQ{m<>za#w<=LNoc;AejS zsXuJApEBK>w)VAtOZ?5GHO@kO^wY4FtIVaqr*TwAxi&b4vu~cm(R5V4n4{?>-vq?I z{8L2CbTK|h!!5^hzxl2ma?`{#H7!0lAun_HBeQ%M)&t06K79`!>%))nC#Ky`3i4;* zwp04K*~BD`An9+aCPLP;riqJ_r2twI<|v*B9CL%x04{TUE3GAX`!Es;W56i zhnsH7PbSgy(=`s#IUv`Q_P!IunHahQRmILwT|ib zCb(r${wcU=E`Jbi`pO?I@W%`M2XN!7&Mg>bI-4&~A&>sQSm4`E%Et$9!g$j`{SGhz zSO)ek*gS^Bv5Z;=4#q82B7}7q+;lM98Sq#JPJ+k!b|yTga|Islyr7`J3U0dT&&uJo>XeiKbiY*qO*%oV>eZaZ7ap*R2Tm=3K&Om-Vcotp;r^2;Oo6Mj6 z!J%L}I0w81+yZU`Uj_Gr!*S=go!h}zz%#(|{d-`U-;gk01GWTPgB`%nklRi_!SPA( zL-1Ab2K+l8Tmaq$-VNRZ-VZ(iZUCmyZeS`XgR{Vgf%5`KgJXdE7`uP*$zUNk2fPuy z6*#Z(AUGU1Gr??dHs}NHXZ#be4E_Rm8~n52bKpMkpWp=KmvTH9JPf~!HKpbabq9iRr@0)7tu0SxaYFqS}X=eQNe4*avsUcvcJU@G_&xD%P-T87T#{3?#U z9L;ZSr&$R0TCTT4{%i0)uqQAM+HD!EfEtKp=IwC(aL?-bpcO0t*Mawd_kv%6XzOTf zwA^e0EH9RgnC~%9%}?!r5G==UyY*s{s6chsQWu${4L|QXMX|DgK@ZR z05OlJ!2gcie2BW1aoztGtjV2j{sDGDcLJCQ^vm)Q!r&PFi(&1u3W$0}F_9su6}^U(hqxF7r(Y(zL4 zgD^+WadYr3^p4=#_rUkTkH8tAAKV5$0_-z)2M2>=!3V)dz$d^r!FY6JCT2m;}PIU@HFTJ%aH#P%z?iZtN`w3-p_FY*cV&_ z9t018FQa<`mr@{JMzm?;M z!AHTzz#ZUWumQGg&Gl`-wqSd(1K1IGPv97GXRr&H2quBaU{|mQ*c0pp_6GZaOTcpc zT>(ykuLf@h?*vo8w~>Drbb)SA0X^Vs@C&a0f#W@Z|6wofqd6V}=7EzzH#iTx4cq~~ z1lB|OHQ+>W8F&}?0{8~_8+ZY%Pdw+Ndoj2aTnY9E!KXl#^M}Bd;6m^$ zGSlY}@IR@KvCdiVt#`H;#d>F*vpx7D{#qY~`fs~@F1Q-p1UANftm{R;i+-AL=G{=g zZ0Dn2Befev|FqS1zUXgkBeb^(zwB#myMM=V4A6elW~6rNtH_6j8N)NIVmL3MyB@I3 z{7dt_-aqR;fb@OMi0f^~f{C4B~L5{OI z{)A(U&vEdv$UY8c!tDoZfd8X5;?LnJ_vkf(5B;Tm|12w(k7*p${S(JqIerox4}UY51o$7WeTAd$?2A`&bS!6l z9|d0kUk5)0zXC_%=yb3Iybc@-bZa`AhQEe$2x)4%Mt(jr_1*{u!3DtcH-QVmyVLV) zIldRXCq2K8NDRkAcU*4uJo`&EHf0JV(<; zxw6Rxz7t%3t^l6_p9SY4GmiWp^?C3Ppw29CAi_hzx4_|?YlqjL0>1>$fCIR85I6*! z2Ob4K1!IW7XpWYfvq1^IjN_R=S+P8Bz%|4C6ZjAKVvhEoo~v7w*^Zeu`w6)1ABRyr zU~h>00sgdcRBtJ02R9+}{QVqn0oDW0Z{X-Pen`E1KD0$;HVzb90USEZ61b4z@=P zyGUfav8BsolMkM{zS}*L>d$fyf>FuKU@k_qp6`!z3oTb`v>%lyUYU!&G zgk5-Lzwi!8a@`kcvX>A@hLRt+%;JzPvCo#vhnI-6GZxP~_KiQ+-`b7}`??)~V{5th zVD>AHvkw3p0_8`7O;g^I9+f|fzB-POq}=PC3%T-(8i=S$TPi}`lzAm2%lPzqsS1pE1lZE+i zCSi!QHI>NOTf;Y4(kq;$jF;iU265qyaonVP1)z{NKW>@m8$QF^AR4CZodvTc{%mH< zT8op}Y*t!~V$ux~`GinmQyRV&eL&*@OFGL-{aSR5-3-`QslyKkWv`7i zW_u9S8p-{9Lz}#09ys&#FTQu*fBxX@&wOc@r>~hkZ*b4u4juoIhRloHhdK|Ecg~W( zbr<4Wk0V@a4dV;mY4z>@bZ6w;dtU0S^C;D;lSR)*x|aH0jAa@|ofn}VB-`KA$uqBu z9`I&3uiGbkN!Q6M6<%O3q$gXy*$5<~uk|`FpxJ{N zu3l1qmKvMynIAu*NVL}a9+aeR#?Y2R{jaVxo7q41HX*i@YQ=aJcd<)+rTNm10MTQ@4=(a#qb#J zgfw1;6}kRT0Lt{o`}kc`zB@;S@ zHS;$%w3Y|ssa($QX#d1{fj2Ju(Gzd#IKX8IqZ-DZJ8Gi~H@sqln;`3c>r!A{3j7;V z;H|rLjvJivuKi!-(KRz9jjfgTl?;0Fam;lm%>KhuPi=GHtPgze$!VvY`=jdhqdUew zo6o7F4qE2Yr?N*9_up)mIByCMBg{VnrW9g+=%lL-@s=gZki zCTyQJB`gzP;C7DV!cjjHsnsd?kh^f5X-k z+2Fq*%XV-`WMR+qggWF;<1$Q;&i5qpG%lr8rOu+jNsi>4xs?)AMs9_a?2b_YyW`x6+l_6WW_!3%B=^Po*ogC!PWp!|gfcbK&aC+u`<%@>y{H2Oe*Y94W+} zSZ>(%#PTL!4=rB+3|D?8aMU4p=HMk`puPJ{6a73Z}G7$ao2~mv8op5b3 zUSEPcQjot3XuocKim(Ak`sl`=Hv9WCI{Kxb zFTtao&UVGTaFuP;*%cmbJ1mt?!L9z9FXo4%G{ZGMrkSHAM@Htmqq+%TBG?V=0rmm= z0Y_;?7)`vPZWh(;(c`qu!|bA+g#I?B{hW;)0X zXJEz3af1g8G``CH#Hn4KjbM7EolQZDn|^=)z1J*#+p(X$@pTW~vD@X(bnJKB{WtWF z-ypg3!GXyie^z68%w~^XH>&;yYG;ibJbK`;S2?P2>v48DXAkmpC&9dPJZ+Qpx^LZS z^gqs=cKnKeeD#daKX~hjCyw7ViEwl}G}gw{0!Y~mznB7^yye{TxWU7(JmFQ2bzzU+ z;wOKTo!!6J{OoU*ym!mC&%Utgqt)-9ab0Qjd)_eq8)K757hJM4R$JQqC(kFG`Whxo zr`hPl-A6P%(1EilOx;O-%bcku&q4SCN9K-45Y;f~NOh83YU)mMf8xc&n=mHHceN=c z)Xg{80FX_0Zu8vhCG!@^ziKfl$_qWdoV`z#-eQ#bHX= zA~)>cGLk2`vDr3+xyT1n_NYlmn$0T>-O(IfJm`J@plE?boK; z;S)LP<~q2x$^FF&{Ry}|l>U4j=vMwM5N&u1ZtVr^jpEz^qL4QBByz9YSeS;Uw<8Vx z)h^}wW&CunuC~~7#2(FjF`oKmytGfQJ?4|#`2l_=XErZz`pmm;U9r#SW+iTSPr5P{ zM*MwXQP;SE^X{GYvQ5{^Pt7i`RM?cNvBv@Z(!OO&4hkP|A2JVn0Q0c35=Dx2P|Vxo z`9C>h^X-0q&e5H>&HwWJA3ZVn`)&R(b^IM0CHhf)QK_@@#BRpYK5eWub-R~Z{ALy( zyXq+y&U?zqW70Y0)#dK#=@+l^>rpbJtEac%O*jqvs?A}$;aoivWpk>%OhV_^>%H0c-Z{2x8GJM8`~$hKgmw0Rhq4sw8=h)!M>SH{w9`&J+gu< z*)A*4uzgl0Jm|nc-Ow=*Vo#Hs$k^R1*+4Z9CfS8Jy&;QjDx1KQKKU80%N_L_^=W^u zki{k!h1d@{O;Uy38`BP;Qq6WxZtkpl)w@P_ED!wy`=|$Bk{!S*)%5NwzZ|aSEqqe+ z^2_W*Raq7thm*p!@U@7x&blq1d3wF7++HwGlhSWBCR@+P&4u$oYZfEE8P}5<(@|=V z6~~?1i<{PyyFG3L-4Rs7UUMOHoC4@*>F(+4O>XYOIXmiQg0Q<@D|@!)Pv7&<(ybu# zkwltIBx8viOFGN2Jz|t5yD^?X7o9!HPdDodX17;5(~lU&ZA(>6Rzt85B<>EYkj>E8 z0xe2X|MPk@r^KeS-arRJZ|;|IlO2s0RE&Js2{1foTu=#zOou8MG?KEL`kVw8jAUcL z_PEJ*ZDIFH8>f&U7_*4alqBZL%)nQ8l3>|o8%iD^6hA|dXYk8?QlOv}zAg|qKMp6a z=y9S&Aqm^H7jEfW<`%wpqBnU~C7TS^?M-MO9e<8Lrf_24cMh;mvpsA|dWB)Cm1?;EgJwSWpZNR=?eg#6uPloFl zMXr1@{>QM|k;k|nfZQ>I;a*)xAJ@J{|8K_rm_EMOZCJCx^pxxNEg<^Y2iH%-ZAC}9 zI!oZuhAZ(urt?|I9jB=C3k+V5qk8`0nCWzkF-??@N%@{|_g9PQ{4wlw++v#D2Ul1A zCj3`N|K}C_`D>a-`s1E$(VrOwo!=F7RwCDC)ArIrT$Ul{e+ciOlye|HRpD|uLpszp8V4svvhu;R&)&8r&wkdxE zKg}=YkAi6Dr{Tt3`B4S?AH`2~{QUt~Zq;!%EvCs9@K~qLL|^~sfI+x%m9LMEdA$O> z1k{mFLylVTvk@Ns-+=h))^zjz3G>48_gQ$f-!Ifm{w>Y3RbV_VN4tSNzyfeKm;h#h7O)t+4w!CdfHT2VFcz2&>UjNNU|J|U9FU}S z@inf-(>NNxV%&_=n&R`{iA%KMK>RViW8P?o{nozV-)&PPVVXbx?r>vT981{d(NW-N za4N8DnlBzr6R(>u=81V=Su+3TgJobQm;p8byMlhOA25w$xiNk9)B2-K_d9^sf{9=@ zmZ(RzkOM!JMur3AGrNFurSeF9pQea&QyvivsxL?n>!MTGw zzw9$9W?=m`&jeR6)s}QrdRg?pq}H)=$w_^D-g;*GdC{4b&W=)bN&fZ#TJ3zBxREcu z@xs9VJe8`JmifYfQiQ%Qkj&KbhCuOCwT(UlZ|d%@`0*6pF3F!>H9mIBthTw2_wDfU zAN+Icg|puirnvMQi(tQdgVz0P*L%srRUx0`Hf-H`xq$k1!c{&HDm> z^7y-Gc7+utm%Q5V`NXvojXd2icNLPT{i&&QcbxIyr}uvC-90}T`^V?cpIW|i{8j1u zKG78m@Vj|^v8^*MuIGb*y}UA+o@SR@TG9)AVkvczgctrMG^!+L^?FXm*TRMHI4Ybb zPvcGM_%kc!a$@$xTQQT|+ouJlZHW zW?}2aI}EFUyc^Zo*}S5}D$(j0%||TxzpsSJ%8gi*Mj!M-&%){Ur(96y_6=q&aXqGweVV0^F$x>#P z5|{b)8dsH-nXOU#T+TZ1vmf-ryO^=lj}F|QgUp2YXM&rc{^Vv>Oyuq1u|S#7&X1_$ z&kUIYisw^PIfroFd8`J4vHoxQi6W=4aec;~n4tng#)#`0C z=Gal|J-OZy%xpAkA`DMdBo1MDpU7K#Z$=PF$9ec&b-`;rNjo!849~!1?c=85! zZ7^~D%SL}?^v-OaGq6j;;IU)=7fZ{)YZ?Y8{%?Bt|JnzzfZ2wAbi=^JhQS%5{}-e9 z|Hq<5rKQR8US4AhuZ(Ns?gQI53?B5VCECDl4TC4XYM~dp?UuQX;X_ybtaR>T9h}d5 zS+^aUkkMPOHD=BVU&Ae*8%7hw7ZWXRTMX>bFnI9VmzvtP>A+?UgS)IHwrS8tYfWO+ z=P9<0`u4z%4TFcT4eiGC{%+p8Xm3pSOR&Wl_rKn5|GzeB)2nUgusmo;Z5{Q?fn6I0 zTh@l6mM?3mHS+F6JMVb`-U8U~MEEAqJ9w!E7!2A12gl9gAX&8rRU*D%<& z)|tl&y0F@&8j{mBD883sf*v!lb;ID^YeTNv`}_67kj*y?Y~C<9d2KL@7p~3@CjHpf z<aP!(w@GvXgdx6OtmozdP6jJWHYfa~di7jkK;)=^w z-aH_mgMlxsHJuv<7Dmj|tBjUi02{3Q(OT2QV5PHZX(bNET{|$TVQ|*k(8LTeZgH7) zxJf&>&A{#rgLBrBs!~kALY6y<`8v1%PNZb>0{g$_h}n;A*>PuBFTjd~hQ(v<3kwre z8u54Wb~Rr9ddu1n*Shgq90~Cv)aZl$c==@y9o;hK&eD$`8C>+`J-#z=^R16vNOanm z)ahkWP?^afCxx8)Nv4Y0nB;K^$cdjah;k=>y0R&za+rLoG9BcE(Q@2W!bDLSjT*kK z=GckPPChLooaokbeO$${8eEn}uw^+{ox)N>+d6_9-43_AMkqb}t8%r*zpnJCRU_-? zQ(Ddl`tukkn&eI<`BUb?t$59&3tgOPbdt;ST|u10QobLU0Q`AA7q}40pXVju!W(~{ zzY#cD<%na56CXF4%cNrzERYfs^50-4CJ9`YDxEMvkSgG?Re@w!~U zOlaZEW=wEb-+3N&&7@c$JVtJ2$<35&C!bAw@zL#Gm_OI&@yuq-XzH1JZM_Jyc+f@Z0hXfb)|Ga zgQniO)#;^WZGD}+nPg_UTFb@ZY<62g;z_zkLR&XmNc!4SYw7I1Qa7(+_;yDtH_v2# z^f)@bX&E3#e&L^Ykg&(&!w*@FgVIC=VrJ;1zTj*c&Znk*JQCQc$RC& z{iTw(DT+QG-&R|Jtp!)9WX(=^rKwcybZd={%&?Fa-5sUXbC;PdEeV}p>Z+_N&2M8T zjFgsoI+-RYgr>ta2Ne=^x_R0cUJvC}kfQOel`6x>Jemc6hhAE97>Q&zSa^eLG+IFO`6N>F<`!RMd2-&Q)#K<&(?DiC$@t7fxUsPqP(%deaF@=OPTvr z+6~Fw^+N7i&u^ss0QkW)m&y+U?@qbviNBq49~9mL>{jQ1GHz`_^=Cn<5N*?6 z*Q9EjJ3RP&M;qLCTCUsgq+H#j@JG2eoSt(1ydmY<^SzX7&wr)-P`GQP?GZv)95+q* zi|80H?LM2ZHs@%#t4K6uqABIBnZ2_h_giURSN@+VH|{G7I%5ku_Y~x37UYk^jhAj8 z1zUlA!P7uH<$na5rTkwUH%a-%*c{~p_+uQkX?DuB?LJ_dE8h|Q=%-;iteFN*LGC(k z!@3Rrnw0+#9_{%9Jcc`ybc_C!;669h?T6v!sr;#e&WpH>}b^Iy!cN5T0<+lUtpxoU~O!G!C2sgg_ z1K*`EJuUz4SF4}e={re|Xe{$zfSV?k`G<*=d2Jj&4Pu%1dNVK#!!sQH*WUwyeoh7Y zr$5#i;Eg+zc)HD zj90QpyUF&<_M_nxm2mFJIP%>J+-Lc*O@6twG5z#Arr}YkJIl(;rIC52yQpWm&<@Mh zUMaU+O$OTWO6fS^zp01XG?2{;yy=d6&i=>;-}z^M0~w`NGF`8};K2PCf62cU4N? zY9)Evn2&HtO_{s??sN{rMKsC$Ml!RKoEI0`IODOJd5=Ccoli;TWrq6Ttj#i-ngfUV zom@F|4f4Z=$*n&ALJ?1B;L5Fnc6nB>@xY%)y9?$1Jl_S_s&BWdzF~P?$d#$9yEiwj8aLSb)?=PdDGQ7fLB))D??(OWK&aE_`HSiuBc}v&G@)OG3BD%dot=!&H zn_cN%-coBVFYjL1UF+dv4a>@G{mdo=EwzOmY#PFiO!rBw2w7EX?qSmewn*aJ71i?6 zzFuxC&+cO3i z*gWM|b2NPAw-@+V;G3rMZ*jEjtFt@)TSw(j0PCpyH^4e1e;!2J{KS%O4a1?n!(nxz zf68Ye*LLOpyynmP=rG0jEA!mC8SAC-akyi+)?3p-o7Fdd4sA>qybo?1?r5*}Yu}aI z^^F_c@4c^imFuvN!0XpgCDWFxXTD?6p;tfr_wRS#`o3$oI_alZ9&+q{<1Zbb)Y!P9 zx2dmpg==`*(@k4=#LpHZ?wyhBD9XO&6x>c`h}e^6dHq?~tft(Ch(3V|f5rK3sUDCZsS<{UMx`d`1P?kwDNkfxNn3BvG7=;6>&e%dHL9GUZfiWs^qi{9hZl zGq)QUOX`9HUWdcIGgM1pb=9y0JyVC2gwtmJY?{o>R@DXd)u|@k6chZi&LO%BrYaJW ziR05d=4gFM7|W_^^IoMji8A@>j=(07e{bEuEbiRVHVtMms;5o_p)N_LnU<$=@^w;V zJB1w%R@$(QMuBYnspw08>Pl#hp!EoEgz0iW4DEa`j z#b6KB>BVwT1<=E%8UQ8;o)A#<#|!pQT|gBu0-A7|cJK-T{Ji69fvN+1z5u^eJ+t(O zs)jGUTZF?8&Z!bqPsm{uf+`2RK{!?1lhhi7}qfrqqYR1hBUv&6Hpe&KmZI6BiMd|mh;{Z)_k(am(-jTDC6O^{T@a^B09y&F7+u=B8sfH?r_u0c*Z9{9GyU#R|V7B)`14;Ds9_ za!Uf;T^+%o+H_9G^&e$XApROqRvYojMhD6s((Gq)kWO^Cek`El41R%tjw9)KkATh| zbUO2N$m8Lc zt_tD7M|j}mFLZ_mj?R|vz{#V~(Vt&{4(HdVb(D5a`bKpR=SRkC_^4(@g>9(tx$)x< z|L~i~9=Z4A>z|ml&wvB>d*w^D11id{2o8Xkw`fyg+W3!Nye6g=?pqT>dy z5>8>ILZ}o@A%@Ol1$~@wzGu(@UJ5a~rNob|kc&U`w+es)&zB=Iup9o+7h6$j;1Av4 z=RGudCDO?v&ftVa*x>lb9)@EhaMI%Bs@0{P$9`@21}l#ZpTZs;aiNB^=mnV-iP}t7 zd)M6Y75}H(GAm<(qDh>G4_S86epmgbbcahGEkF15Nek9aK6d-ExBG@;Xs!xy8*o&b zqkA0l91)KO47K7 z9={K8{kZ&2ekR`&HsusQxUFmmohb;%1y=lO^dpIR?_We*`}KLU&w#B<*6QcK{yAmR z2~4sM-e8$k-ugG6Qe%^>c>~-P;YsOkGnDTDO#aEIv+vrp&lkV4!#iWQTVD6x*=H_! ztL&-#N!C0mkr2Oz*Z&QvAyS#iBwK2mJKX&$A=RCEp6yT<)SZdWBnc$-F}0}H&4Glh zA)=zCX5WXtJtYcvfHsDTxy0j z0!l7)S`1ng@N)%}PVfZ+c;HV6-~s{>PVgjy}7mPfDVj9`r|JCA2+z^7Id%oA>FWTaUZ( z<-`8)<^kF9dzW1lUE1j8^XRKOq_UA)(Yd@4QhY+um99dfpJj}*d5V)KIZdtYnk#Jf zI~MXLZi5m-S6>sc{=^DC74!*k#F7qD|$BvncK-IwLs|7EF*T2Iy80FMqy+o96Ttfx;4J zG;P|=*TQGcLB>8Of?F`c8!bcqsad*ymXB1PwuibVEeEYTJB|AcLR$wR%EBo!3B-s*GaG_&5b|=-!y$E-L&0_??1G|jF+|=vEu<}eP_-0j-7GRU{a~;rpr3f zIDagwZKD3%FgAF$X}Kb2lBL}i(6nZ}S-!}&OcpV6LRnV+IG4;Qej6woP5pbec;aG1 zDRR1Q1nsH|3nSazwof*lCZ&a)h}IyfX=#+wzqUXJHobCo+6sk2X#NDWcBeNRU)es| zH4GMM5(nZ)3|XQHt;vODC#K=g$D~ESbuOfgd^Lzpe2$i1c#_(5i*Gj1vKTaeB3m49 z5I?7_dFz?x#KpG85`BQa#zOXDmMM%zgBSIS)8B1f?GurIb=k38q9362LC z?$-p=c09O06qs#rmq-w`BJyw#6oOnH*V@Q!{&CamhMxzw-78}5>3UCXZEhADT6pjS zq=(2Zp4gGv9Gem^{1P9+pyr1cJHvw5GRv+45}Ay* zL_p%fJ6J$Q0jdN(QHAK?Jr9}53OgAYAY+pO$s~rasm*Pqlqz!k=zn(kdbC-8neDxg z20QEe9(3s3MX#KGK-ZU4CeN1-+nZjspXLRQ1RRJH4@?X@UKcV zYj8qmo5*HM# zUr?bq?9jbT-ysX0;Gr#>hXv}dYUbZF8v(Hz9g&wws)_lmkneZO$My+QM$p1P>6P2)zv zv`S1r(UF)8etq^@T94nl99GtpYY>wwr(P=x%1vd#F6yQ$@A0FU;7tSC> zxnLVr?z9Eq*bn{r92g|J*^pxf%vN)S@1XbPf~0V>!|qZ5Jj3Fh+wDy`-~LqDi|dgD?kS6Mcl|c_(N~x5ijgQT(KK%C%o8%?mBj2@MN%nv>GF* z5R4N{5RkXXzsN-v{LrycF}lS8n~WEbM~D+?Nxqcmpxt6|fuI{+;$#qX(e(8~KoOQ-0 z^FCZqc4{!aXF}pKDl^)1Q^%#x?p}&KS5#-`b5Vo)qiMKOnd`ZyPIh~G=)@EuQ8_PY zs@MNWq8yPJIrdAZ+I7cyfiMmG6Wvg_pI(ckbh97h!1`!F@fgI32|bpu&UDetCdtdV<9_t!Y+PXJp|jWB+3-*s z;|*n6O0emR1Akqzu;12wuk`B*;Qg1M&cky3OFL(*>FL2eZLbW@;;vw{Dv_;Q;g*+T z0l#X0-kyIxXx-S$2Hn17+9$ss@nQWo|MT>HWz+nqW-#r~R7m`MwMb~5Oh1Cgu#7zn zgJDh^ni?S-H^Whr1q{^yj0ZCuV{T-C^Vl!LNDLv_a8hSuZWG-}yJk!e51-op2tUgg z8!pZbUV6!C6(gq|dC{dC&!4t@M#K7%JC^MmuF`OeG-?tJ$-twxc-4a9OD)1miqSHA zFz-k?7>>uJ4Bs>IWhOJ;L86&S8I@xMjnOfN@Qrsj;qc?;mr*<$%|cqkOyM4cB=dhF1HMs8BJdoUVbY}&j!nM^NA@s~l~M6GVh zar?eFem$Eh%(lZ6f6J=a1Y4MG7*)j1Ovl*hBU2d2fX-uf1wXTIuB^0kzYF*8;jEfJ zrCCw*vgxZ1TRQR^k3aa#eP2BH#nk+rMxOt|E0fAz3C>;Xras7*Tl5lYnY_KFH9QOu zAI-_t%r}QL{MBl}KiEzaJBhH%n+0v8oObLab<*Jh$&OHl7PsrLFIz$o(dVbM-op<^N)@n}xFPTO>J9%F~Qp*UjHd1y^KdMzDEpV6MlrdrgO zZmQ20N>qro{f0uQNt+Xq#(}%QZUNQrRSNyiQt)}vnbo2-2ElxN#HFc~F2S+^A!-*x zUXiu5YjM?_rq*motP0{2-2)Og{k+8LxyjbX?23?oUQ=rUrFw-9LJQx!+YBOCva!86 zk&doWi@hm0nX;xX(a@la*9(l}cW@R2$!_aRHqp`+iYtiK;&gNPsz`!GB=*82S93>1 zkf`B$i-@!^nbEx)fjgBB1xE`LSQWRb$*pp6n?ge&Q>ZC|hl>3-!kJ>BvYx8ihe~<0 zU|#_h{;q=e1hlR2SUWpH_yPfb;h}A%(#LNXZK z#|xNx0%s!^4G4ZY0M4dm62eU%j^k%a44zYBI2$~S|9as};lRTh3K}uOe;`IbC>Hl; zMMnqt--_{^BR6qDw<`rqwSia3FZv*}L^U%NH-5Jj&NLJF;23>!48KS3;7863$)Q3= z&TR2mBg)kXhSv(mR>(X~xWy5F*b={Ih;I5%lbd(&UoN`YLC&!8_=Rxfqr)BIG5sGG zP8#9&dEpk9*MwV|ekj~@7$E(PzEfZm{EijgKahit^5XbpT9>}q4jF`tfAS9fW;z{X z1r>tv0*P@tqX#yiVH_kFBj7z@khX5hO}}(h$^}COG_=D7qXfhWo4`;0CI66?Lj>al z*a#i53Hg1nfUqYBCJ81BSYLqt(6BZ5L_ufYTxn_NcDZAExDnQYE@9vM_Zz+cX#Kl; z{I0s>nTMC&b$m_ZYkx?TZD&2f8JgRknQEaOqW4XY%pNKT3LuGwVKE$TB8ver5_BHi z_N*<>m1uFrX+7O(mJ!0s9{p#?6K~8vxKDcNzN?1}{PW>|8h7;MM-EDseK%NLP_@8u zSGJ~FJ6cj&lBSCy{l(<|teLzQRIu7>>yDY3pJ>r}um#*9G0q9oOr3x1w&3INeGC_r zmj%&dI*VDoj8v;@+L!8p)?}KOZkVd2$=w0Ux&+Tm)!${6S@&N7`XE4-|0sw)54t%8 zlmcN7d4fV=6+DH?@cV_6A1K6@Kfr%2ps?{gETFJM-$!5-(xMpNB%Cm)JXQt2;N(5> zCt>6S6m;mP3uu7AuM$wG!Cwu2aepcpBp?sJEue6N-z7lT!hHN&(Fn_cN(UbDKKY(9 zfj(3W0P#Z~(!;fveeFhl#;7*?__9mhIU{|?DYLe?_Li58p@iTpUd^n` zPOEIPDw^ULenITlu3;qgvy##2;ziyCWmCN^cT2Ws0lLJQGF36H`eZ?(G)!?B!el76Rzkg@)dyvsza*rBkhxjM@5-=5hz^7}oee^K5-} zs+Nd5eAHrImLzn12tg&%jma!FPo`mN2~xBxB`nGFRPc26kuGLvY18+#KA^eE0qX2v zS$=DyuTHCV5CKaft7a-&>Ke#QMqktQsh0dqu{hlnoJbUWyiQNGx7OQANB21!?D!9p zF<^B2E$TwWyjVLx(Di$wyjZ0@5W&fU^&!^vB!MoSpm3?Zk5Z^YbkIo{e$|X-jT~Ur zDvNK?yYx1U&SCE)bnQ5cE#r ze29R*E});VP_TzO5hn9}@$kU`&yUrappUV;;QkmsP#qQM@T?P^J_$UJ$uA#P&?ib~ z`ZhBJTpGd0)O-O8)#=;7bAfRBQQ)@;r@w>FUkz~jIYR|}4CMs-3WzWG$r8?c{C-=w z>3qF#KDeOoCOs`I7S3B(FG?T!Z0Nk3;x0DFf3pzdc~v<5PUP$mv(HaOM^8Tf2osy5 zkKI9t{@VpSyjv`rVCRv73BoOn_7;x+5ds$GTYAk@SOY{O+=1djA7s80)L4qp=;o0Fg3j@j@=;dkg^g9ID1pR-ffXG*kf=^{bOW!R;C;woRzX><`XyIaW z^h)9S@9^D(NNtz*7%;IsJS|4wMEYO{WL_qH;0OPUc+e9aCWuG>9euXw^ylH>WPidX zj(uZsTr8de0ng#W$tUnP3O6|~%WXU<1&UqaIapx%oNp5HUQTeP!15R}EI)rJ+~kjt z4wOO47kjCR7x+2C(HT2)nue7@2Dm6A@LVfE{!+nS(vx`25IiIVI{Ex5;phq8CVOHZ zbYXR>%S;jV==KotG2*K zxw8d`=OBT+JA19vuYz`E0DF`7z9Kk4fE?bT1GXU#kUwS$<_f9>2MQVlUlmYph6p+Z zhX~dP<_V|=NaI?;t^)L=4jw6>%^)5?xnN(x0s-~o62U=&Lj^|&5(3hjbgmQ-Z}RdY z!D0dBXq2Fz0R1eiy$fiBy{7;h5Qi}W>_a?wH&MVl+>-;GcWjd9ayWRbH{qcm&U@$z4sM;Ud5}hJvTm*S zlc6(H{D#AOF=rst#_;?}CXp7!=z$kaJbB^yN}_u=uL6%@^k*b=lWudURfu#Mm-OS0 ze74)eP$Hi;d{*&k$max~PvElze3pRM2pHl4Um@Ug6MS=hTkv@Z&erb!0nVowei@co zEij%_0vh}~1^n;~7tZGr_-?}S4}QMDK3i`R&gUk6pNQdq5YFc!bRPWj@XO~GpGOku z^x0Iue1<{e(-OT1mrq$}d|vUM&td%Vd4wEr;>IsP{5z-QHZAR}>g?$&gJLs86|8y- zrv5meCMrm0kNnMvA3Sl-2UMulBw8u8o$I4fo^IF#!eseTE6X5f$a=h%*d} zp)ejs#3p9r`Kw*>Q=LZDx0f2B1_GBX8pN+_8oC= zS@YU+uU+=DgEzk9xNFL)y`|(MysovTF5T3|?4t7@lD)}-+2rnLUCDg*PzYzpK_(>Q zl?%vh*pXlC3ywXpBN=_yzzsf5fIo1)>ycx&w_htn$Uz2aN_rsQ3J5qfqYK?%5RMD% zd&R6@9<}M>c99NH9jn#Gt(k0EGjrKs=8&BdE%|SJUG-V-qxs6{e2YRq#U*)aQUC2t zy4bt5zByQOVw`>k)4RATnae8_jrKZbP_=+n$r)T~;g-6FGc|ed<}T1lQ1!{G;5V8w zV)9S({Bm!n39fd^c=Fx_!iwdl$mKdU%b^J$z>7CVev%W~vn zrY`7dZQ@0tyIAxKd0bST9JfBezjkQ%zTInYDNQFP(;Q+ZkA7<1sn`v9gMKU_Y{EE7 z@+u|;buw4lojVpLL`@T6=GnjI;7X>m<21KX&84N5S>!on#3L*wAZC)t z_ly-y&AK4lUBv9qc!}cVq}a@9o+Hdzy4+rS?2IQCSUxEVFOsf)N>hWD0o&S-Lbn%I zoLW?#uA@k%we&+PA=IhR>V~*8kXDTNF9;(C+CHf`?w3H=8}ACH)$@s#A&jcITdkES zVD%Ha^o_K{Jso4!WIY#pYtCB46{-5^srruT&Dta3oimfQ?TxWB-HKDq0thJd;olWE zgy*;NYqHIqFEyXqy}bOA=w;^9;&O|<*`RFII9_I0C<7;J1R8>y>5GtpKvVVY&AJuA zBBOqOo;%JJWjDtZIz11oj2-Jy|Y-nt7rL~msgc5dWm{1_wlb( zb^G{|b#!T&>glFcT5%M+RD}x3FR2OMMub$Gj)?5=Yot=?j54z$L?-G=36$@`*?lZj z53oqIUKzW#CV5mlh1gwIpXVqR|Dw?dlRm1eLK5r5RHjtpuF`T6wMyZeIc{xL=%lQN z4zoud!Et2ORwq~t5x&w=jY5)-d65@h1naCk3*khj&36^!=-#CGotx;;#dcs}=FD?M z62tc!7U&k*SRq1G9>M$N)-qq4dABWUVhvoz9IWB0Y;M%;BH0x!s^7HHL=7{!GFWEk z7GM=N08w)K46VvR#l4VPlWb8_s*~cP7qmRu1k&zWW8c+{9Tpa?T#0g6cs*axXtC0T z;TpJ8#aE}L;t!=9bx+14+<{VJHA_(x7$*5J~W{- zw@g17e421R7Qtu7c$Nugo*Vkl^(9STdlSifQMmg+7Jh~)_QDAVe7JBvg28_#KI9{l`BwOmbEtm! zrU0KRe)NH#wKmKd!~e1HK>-I}jA?OUvyr0a_?Jk3bVL6Z z;qZeG7r*7<8X2TSG}1I15AYX+k5;CI&YGJcDx~1=3jP@28_PaJlqk@*7QUy_ z7krrTGXi{9;S&{KOQU^-Ti#wE-12a}aLdE*$^LRW`=1fxKUwKzdG8|86@*LE8-!ch zT^QrJQ*`nS`Rad!TYi2|xaqKw6gC~U6K*;@C^^u{8_x+R--54|ZsY~(f_=qr<+@rp zG{QPkczJ;9hw3667dYstt+#vRqF*DT&uQWtrCGIY~0ZzJ| z5#acJJw|^jM!!!uwu0v<;pjjeaj*muM|7(dZh7t+;S9Dye@wXLmFI+8Uin10L^+T2`RMs^OwQ&anr>5sTiWd-+-$Ny zxY^`n;rj37oF&BK_(S2Q+g-v#%vYHfbb^1e+;R>44=n3J3Mf>|c`%w_}B)KXLqe48K^o$-hCk)yarc%u6ma)Pu-KPt; zG+iv*^5^3UOUdWLO^I&lc!F?~dAe|PL;efmw{*NHM!!zD$-h^)<$>pfn?7#~H#>Y? z`dgYxtjkyYz9sqCjePPC@l&n|cYuTwF8I#EEsbUix4O4lxaoYTaQ%1uZ9;Ym@NWyZ zxLhUNbh}45c0m481%z(o^ABTb!TU^mkBNxTrapmaHHTR!OenO1V0k| zSa6%*F2UV`dj$6i?i1WE__^R$f?o@s6+9<+Uhsn8MZrsgmj%BOydwC$;8nqEfi%T5zCX zp`b>vNU&J2M6gt_OmL9kV8J1R<$^B=wiUc3pgip$C>M+q{8jKb!3ToB3qBP5L%^ML zo9lO?;B>+Hf=3093!W7GQt*jjJHgI^2EjvuhXs!bo)G+x;1>egC&JN>yBGdj`rSo9 zILPY>TYOvLjun&$$^-)iTL`uid|5D5Fh(#%Kv~>Vu&>~70cDP|c9b9^uyXZ1;g<<+ z5Zo;IvEXjOeS%*LCkfI8y{!3x1jL0XU%TqO9e;Bvu@f?EW)3GNZxFQBYaMqd`ZE1-N)t|&j08S>B- z0`kuPCfxsRm=@j-6wXEh)BhX7rH0Fk=f&`=h4&MjDfp(~D!~s0_%(MzIDRh>zy}WB zIReTTuBMC;dgSf7&h{m$1)kzn4)Pa|~QR{NQ2Xc+eI_Pmj;V@75IU=z9f3n=JRh-6Ce;{{Zh zTMDT3!J!Wp;0Jt^fQAE{ij{&0f13a~RI)UDgb6(-AS|Al0{lQ&^nwN-;qwkU@i3f<1)TVF&dzO7+BvARr%w*@ zM=!)qn7n()Ml(iV_{!_Q-1EW*fB*PXJH0S+O;y<>pM8RC!3@8$76)5!>R2X_;g*GP z(5=r^SkxYJ!B9D{3|69=v=qhSqzaZBE5K?7#v_uW@oQG+7x>j?xy{QuchCK>r%#g9 z{G%OPSqG=2K=iHy7wMFHyImsWqvYPOYS>ubveI5JOCYu4xQkdey3D`QHL^rh3-A zL}OE(ev&P!+uUjqTPILGD{uLUEx^&dD|K2RDR3328c=PWnc=cTxVogOesxxdRDAFtb!^65L{R^a&}!G8bt=nbCnR;d&2P@)m}rQrQ9{AUR6 zo4QE#mQL}J!+QtwB@4`-!6Y^vtlG+nKJM27@-8e%jayK&7B~Yx`PHil>bml^z;|Aj zqDXA$eZf2Q3#;gYcW&v9r@3Y}w%)NgH6D#ZAKk~sajFElwR0+*N`qocld`IhYTL6~ zr`2`YlD+eRd^Sh1oMm^9+ixH%Rp(l-4X7V*kP1;wQT3@~%e*hY#iowq&a{-zxuU{S z;Eef*c)Aa~upP9+$9%I$Uf|%js7;LUAfVXW?n9Z~lx)@lR$HA};Pn2A5{ucnaHW3S zt-di|M)L&WxWLUjuAI7k>w|54%51L@qtb&*?kE}5=a2o4-e}MkOUka@{I<=9Z+6C} z>o?tZ;CBYRxzWRYPa3dbCSZjY)wb3(wfPHY`rMNnQqs9!Pb+73%Ud8@vA<49<-@Aa4Y_e8orm|d zlA#6T*VI-ln=*d)8C*>7R+=W=2X>$9awAJRYkK;UmEu+n&ehXL1hzdPw{1!1xX+8G z{&YL^+AOzANoVEfMK8AnC)H--ASk#)u0nb8^QvHQWtrsw>3cw~Tn6pwGQ{zj6>4Vl z59{}Z=E~gQlFnH@t)ZDLzbfKVIvKIg6T=2OuWS*vBu2fb$F{cYv zXMH~PoRMjxw9Nh-CwjPR$R+w=pNl&IqwLw7Xlikar9KzetXj*fG_C(!)H9|~epf*1 zE%;nyx#H^O*E0!y#LwqL-p(C-dGE%xQwMx$1(R`QS{*j<`O;1MeX`L>eZS$BioyDS ze>%tJw$=TGox?v@^X&PS@fU|wtgG36Z2I`8uUdOt)7jVU*0#xJPd{5WsM`teU~+u{ z)0Xxy<++O-Om{L#%wrSNOaL>9%#%d;v6mN$$!bL^`%M~vNT?UN@Y`(0hOm(At+`y(>iSLreD zJKq)CxmkR+e2ff17QryAaRA6hy9uBfkY&JGKY>9lt3l(jH3t|PAbT0jvKq7K;GF|= zUr_nX)%LLA^R6eT$nOOE1XwrY)B*jkyJe?uO)ee!=le1bUw`2J9d^eNJ^MTfW)j7) z4|$J4OzOG9yobr)HToI*=eE|epzo~eVRP`2xy%OAqfEH%#fc zO()o#{026ETSU9uOADmmz_ zf^7r*B>lnz{Y(K1y}-XOU~v`rN2{u^aljQ z5nXNt3V;o^@K(C7_LTt*4T z3C0V^N0S7T1uPguN74?RSjtu|U}ZP&Woox8V}gEn7bqCF;{-S1jTG!E7$cxDhX*(Q zMhnIYwinmF{+V%1JX zaOaH{mefb>+OO7av-w+JSor1_=2kz`{=$$k-z{BxMA^gPxsx`5pNV}yF8r<%Y%aiE9pLaBCO|&;NdkDm**}1O zy!*C*QVgBFFw_9hM+m@0aD#n96_^<==;<5-6{m{*Hurx3?zvzwK zkq?eP!URWWJq!3_;{tnqb>~TQ_W$L#@mo^zQlCwKv&q*>e9s(w1$r&;|APf` z?YS?NcJ7tivxmDzu?+;#H+j@C`flInx0ti-E6;3n%W-F2aQC|7&b(r$@0V?9qfWN> zfL6gCT6kIuYZ;*9w&&!DxgB(K^VfR%NODdCt_~*a`~c5(jcZet11E2K^G<(wc>Nyh z2R`(N-@abI5@wSPE* z!3WTV$+qSWdTYqj33;tqH}e^~x;gs1%lY5I1*Tos-1}Z9eF=L=wX@`)??7svDxkdv zKUP5dO`qmy0sR2*p9uJ>0pC$Tn~t9!3ZMa`JTky}N0{(EE#MvWAp&IbeqRB74siNb z$Om5{pg#a!C!kLP-WvRZ^H@&f7n$@iz^(seeIDr6Hvy+_MBfFRxLWR|uSI|5s{L}? zm*!6V`OaO6t3CpaVq+NY9PUZ)`= zopPv?6q9X%5o()tc6}Xp)(dG7r>*w$Em@4Yf&c+l4{N z=Wmxgp-sWXc?*5linm^}_}ieZ`e}tr7mE!2i`5 z?VH6>=d`XbkXAfywFxUm>|_&DI#$EQu!#Bz<= zj+}Ko#2Bu$ltxreNzfRg0rfOF^ zHAoNaccenfC?|>#$byoQz;q*#6+nILlqIr9fn@EF3_ZJPYVzc6fC67`#Nf#1v ziL78e%qWDEBwNZf1)*W1h(;O^0vZxmN)TnLUG~cAFX1$aX7&JY zm0UFPv9dRm6+P8!cgk(2o6t||Iyh2TrD*uJQ75gJv(+NAygrpxO|d*vzjFEfb`7x4 z4leNaSNbk*X{t-7GO31ag}CZc>10KstxdJe_=@q%)5!*E8K@$Pw%oVm71{+%>yp-b zDGg+V)lFvb@*CDad}*%v_~RC>ees6@IM z#b{_iVs{kvVKJcH;ITHwaM}+ZzO`v5X;XM`j}p)h@!;M~K)XeoiF*$LZ4nQ@vjoWJ z!Cft&Z3A#G6wuyTo3<=)>&Jz|SckQdgj+8#`M7CMO+Vbn3oKr^0c$7GlW@@oeUSr= zwiw;vrCqgg2k7{PA05E)18#i>-a!xAbD|fH3;gw4Ymc9Q%K3kX)~3`;1XV*u#g9tF zQ#Mr1STnW4@lwIB2n(!#N5w*8L3417%OeS;dTkz7tm?+M=d)^=d`r$io|ivi?jeY^wEBAZcd5mP!0@cCu~4JofQ zNBFnqrd7PeDPH*+%~y&v_wfqPyV~TB?f^caSj7y*n&LvK#KXsdlIojonvJML({YH~ ztZNJj7wgjO5muxJ`ZOx;zGlhlZS<}_hSR8CxEFZ;X`84s} zkVdCBq0$MUd7@Dw?T^+kb)0ofj0YQG>A2mZ^o{Eu$BXG4e{Xum(=(1!GFqKJz82*# zT~oTEXzTM6K714J-= zfZRrD^A_^$g)gaaptH{}Q3tMA=M`GKCa}81w;gm%=;X9Z+Dbu6DaGGnWf`7$$`?z8 zLY~6hv7t_VRF`xuIaWfudt>cAxuCmlnRPaaUp5w#D5av<(FXlro+AU#jF;2q@PP9j z$pfuIVBd(iX=iD(Xm@Z=6W|9P#-wRSnFpX9+gXqlF!oQ|G)&MTz#r}GD8X6*Z67j6 z3r-VQc!Yhn09o+hzCb`*2hT*o6$08pYxA!Wj(p@z7u+tuFX7J;+$DgQ@b?!yAfPSA zeSqL00rGIq6+A95{pJb(xq$fa(8#VAAe#sG>jH}(?!OAql`swzFh@c7JT-z+1%#XT zxH&UyfPQ%v3phK>^u^6AE&A~AZO=T7$-~W=QH%}n;ND$s(uxN+Gqu()!M&h>{|LFU zFAwim%FWmV5ANgTj>|h)?rq&$|Ng?jKlX?J2Xb3{4w9Su?#*7fndLkW<7C!F37x4F$VB#;bleekd z#?PvUt>m_T9`16vEx+Psm4w*`_XN3Z9uM~cax+%MgS%F4vmfr&a__)PJ-ELmx7iOj zXI#hSUnaMuKku)WJFd?ya#J38c>l26^egq_+)oKHdnZJDR&L($;C@~X;)^|S|50uW zzgF&d*Ki=o$Mjzbuf>Y!+`ANCIEw|Yl_xEG`xUY=8Z;<;Yxh+57zE^Hb zU);Zz+v)?{zn8mAzdVhCH{`bRjGHsOEqvU6FL?hCxh+5QelvNt_~PC{?zsOUa&Ig; z5AR3GZTT7ZxPtdn<+k$9`#A;fgXK1R@%~7;t^DHV+*V7UCb`$jP5gOqpDj1-1P|`3 z3f|u;x9QJ&0DF;M*jd@j=}uXueL`o_h3`o0w~qk5rVDsS zU4vby+mXRsJF-U$2y={payeCi?7al!Q|e@NStcM}lnvzf7a$8;z=v)CJm|5jfcWet zK+o9%c;^f7j}6d^xWI?5_$Myl)G5S`_Lr~@74Uwz0RE8z^x9hh|9%4GEfFB|D+1y> zS3rCh2#7Cr1a4&Teux0QDg=Z>9gQ4xhHobU`VJPL^DqH6m>?kBNdo*$77*@C0e-6l z_%~Z&Tl^0a;D3|=JC7F-&v^pEtrZ}57Xk4dDnKrEIr6YI{&p6i|2P41R|t^XB!F+J zfOM@Cz&A1YC2g?72myTi3J9O^1pMzQK>iE?;g$=C&+fr*qkf6+fdax^D8L_W6*jFF z;BS!tzOe$rpCur@4i*sZ6an$vUqJW=2%y&s2!D;7;ln`3(X+ zs1=S2jQP_2ch_$A%`4#FsNW-fHhxrpdY@hk^jhG*(E_I&pZl`5Vw|z0%T${kF~c<5 zzkf`8(F%={*K0bq!eh~-_||vdx9yeZl$>7w;QUz^JTdgJ*3(|zy6kKH{8)PEtx^+w zS=NU$N3504et11uFK6A#@IWZmA$l*Or?VdQe=BQs?n^jF>}jDhTmxN<9?U%ZSMI=o zbbA}OWZUU7{*87aagkVucg4bYXaTcm*<{F>)oFosNw;3!9e>7p_!_O^Pu4W2veDA; z&s;O;&RpV7S(M}WK}|o*kWRX9uz7YWPJ0KPGqjOGxIFOlaNfV^I#X`w_@(XS7odM&GFJ&FuF&B%J-;QKeiig<1cV8G zhk!O1{K4QC{8@p~*T?ASOWRNXf;O68+F)!XRb3y2{tkS&d5;dfM;`qN>xb~3eh=}( zw%Ch4BymAk^oIwVesgke$I{MSE?Kt03Sh(Y>=}2cVnq|z*y@(+ZJnu3C;6$=J%Tbq5FTFQWz2PgR272zU>?DxjVN|BJxpksRI1cwj3Md=@f1{EYdsb zVeC;K!(WiX$j8oQN+65l>GEsguGTx^3(xs6nT(}T&qKdUVESJw9!m?xPYu6XI69(p zRsfx}cvoP0-Xk8%C-)0CJ3JDja}TA_=gKd-5jGx?jm%#P%(g!lzvZjn3O7Cf5Tjo% zexq-$c$wdAgj-lU2sfT`;TEroN-%=7r%@jh!loDOt?h4@tncIyP^8sRiI}f ze{3H?$t4xTe%)uuZP>nF-(CA`lHMqzpWdfC3+R0KT}nHvIu~xR*WN$i$(=tPx$)2g%SQXoSR`PU{Lk!YO=wk= zKjPQ_WeqP`)E=5Cs&BFi*^OdAF#-k&D9To>z{$EiCW9O=(O<2jCa1ga>vbPee|Q-Z1M}{*_F31d%i>+_4Gr$R-nx~hnWI-` zq7I4SNjkkN)m3TFwzX#~S0$R7>94rXNOdZsE>~Sr-F)W`@EX_URfl&GoiX=1FPLD- zwb77YK$@ooaq1WcXW9l44TyXYw`anyR+Hi)5Qwp!Q?YkddBiG}s7Y+?LM?iIetXD+`A0)Uyfd0_07oZ#X-2z%w@S6o@ zPy9j0??VD)!^6Wnp5X$jpdkW_AN;ho7O#hd)7!-VIsr0(KZyMHdWh`w zBn;Ds_oN%|w-*c*3=@nL5Dw{8%pY+lovRn`pd0Zc?-@=n3LJZ57i%`?9i2HKw^M27ju&mxQ`LWLD?wD% z&l>dDj@5q}_jJo6H$VO0$M>vGfo&{{92$=6wM{I5t7I8-$z9v(gPZx*?CS zMhk8hkJ*INawt2r#COO1{!Tdj#PPL&4jw!;{Mxucder2))sq(d4>s9IYjFF%r$7I> zr*m~~P-*AVH6u6JIrx{RH_{r6R|Q#77kr>)f||dgy)~0)NG_jTF-4Od!LFZ7u(vR_ z?I&nm+}@w~2VTWu=RfK?{O&I=KRV;rUs(3>8=v&M^x!Fv9{SFXPnPW+_8j7K9Kjd3 z*Ni4MF4)WU{RFa`JygdeIa!44Fjzn`lcYSn;~~qCy#S`Z$QIyad472&3c!^MTnCM8 zs+{F`FY2EwFYO$CYuDq|{_}gT)JdqI?+{qI@1(|S&KPsn{M&}zRk7&0?caL)ou{7~ zbNu_VM#8OyXZ1L{kl5JC%51+^#MYFvHa=R@U90uUtYl~R0xQ-#F8Mx*jo%GW zTvxxAKdCi>-bV07TPV@ptjN9vb_Vd?uglN3A$)$#KRaXCWnp^S=14aEv4h2LEG1+% zoyP6Vt_8ojl~jv|!|n{W)wYGdaVy)qe41?pMbC(X9S45vr|B0@jW}PF{@qa{JH++- zENYbRilx1U#cmt+GWl)B`Ds#|hy53;WKXsTM=?eYn=0A2Vg3qtA{3@ralYc|kuR%I zYoBKD`26cPSa&Ze&Xq5V9MSA@3-BhbjB;qSE2Y@xRl=pjQ6l`7;kdq0 z>UHI_T^#K4@O$Er(7o>{ec2nzHff*cekVfsG>Pw{%1^EM8?*nvlFRbSeleWCz99^B^%w!)zY_mu+V(qY1VrvTZ6 z_hrF70y<-K-uUi)R6ys8_ag)^3FwsZj1v4_fE#(Z|0F;j4}JT$1oZiNaDON;eQ*zu zNA%&ry|df{oy)uV_T!rh`Ml?Q-QJIpn^9kE$b*};TJZDWJ}PkQ$GO)CF@5+BIYVv> zANThIe&UP!mcT94t?_2mm2VTC@d8fYjJp|qHTk^%tK6n9ZhEb8_rSm{HYaaexy}Cs z(aPmE{ctnaOuF#ku916t=kjjmkjYOxyl0L${{C#akw^S^f2G`m^~*C^@R;1ZLm%8v z$ZZ|(DRQ$9$Lx#y_j2?72S4tQCEWxlKRZUza;B?+Uqx!mNk)kI79rLm%Aid$IWJE;m4W@}6{1bliKf zh2?_yQbvdeJd_X8lz8HID*+?zjByY)A3Y-ll*>^9c*$GDbDRKuC^NVL${soquZaT6 z*CYYyjt$}A!wDVWL5Cp%!iE>U&;>n)3n=H*D}-AiAS}Wp9>WC47%d=NbVfdYkpT}h zbVv5~0{GE|aLWaRH$s5U#1%I-K?Z4o+(81<4IXqN4x}Y|QHK%U&I0rsEFgZAVfe{Q z$RW+}M_%Locmezq1jK2w0R2cuJ&X8b;{w;LIBoqVm%RPFvtP;SeYPmsZ2iFZOCJ~7 z`}A6%*8;s3_)lA)bI;uH(#{<^TQ@jX`0rnlqgj?{Fz|<`&idlO3tro8-KqP}nz=Un z;yw=^eM;F_Kkg^Se`P9$s@fhK`=h$1>b9m0oaV%uGoh~PwqKfDs`g<5cmbME=-@nG zAC?{UOnfwyXKtz?(-L)|I?SZI`6e_9$)rWX=v7} z*_xSTJIRbh8_PoEIa{8y1+ z82vmQcOn!>;6)ez3tICu^FhyOPGwkHd{ld~s=h$28h_|iNc9pUYNSjN!9_?1wx_a* zOm{Eb6lmT{e>ip?$*Ule*ItOH1j(3}ihi2f&p=z&kJF47Aa7ciuWKOkFLRJ6H%;uOM-OaIraRm;enL~=%QE$G zQNaz=Y5yCnZ3^{zTCRMR1AD?S$~l;7U*x% zcYIuUd4P{qC!BsE^gjuwQlLM|T2(3!=;sTk|Lb_<^s`~IBzO` z(^Jl{@_Sr36)1j@M?CQRv;g}+|6>gQr*LFK=Ufi#0KSWGegWn_>0^Vl?%a4-Yi{^` z(gz${vA!I8!GD10gb)3s7@f7t#@`;}A+Fd&tnNJ(KDMT^$0pdCem`kiE`X0XlCDDq z!v%a#5O-t^7LX1K!uiK9>4-n#L}LKXH_5O7AEaOWLC4>kmARp%osB1*@HuHH3f68^ z1T|0W?AfS2KIrBfr|y06(K|l(_|r=ce)ZKaZ$ER|AIlPX^Kb>?7SvR0xeMzAE7Nr= znpnlro=$cRqno9HzPR#PW)DS`WZ_ecWLg^hl11hT_!I;u8Xmg=>}D9n&D}Rec_1+`24xB(nNcu6 zp+PBYW;mgJa;tNLOFIYU4(s9a5G>$|>~sBf9XGXIy!vOGZd-Z%7NbVp@%5)Rf2-_^ z-aY{{3yf&+ERMv73~CvRc#;vZ12*A_+fUBL&}>}bs?*-s_m|&3dM$oRN`KL3V0ysT z{dW=4`}A6%*8;s3=(WIqrv=vTpBtr6m6auNPaH z@xL|GJF?m);~k6DGn_Cr?wT|)?wUGTOO3UzR(pi~2IbI+&q)(Q=gd^QKKnu^Z>LV4 zpU@ZV(MvTL5$G_{hdRmsOfJ&D48A0Tb;%5L@QGm$&G-~KXo~qnnl7NL1701&4~yZa z38&8qPjd`EHin-c!)e#)Ptx!Foq%o>IN{LWq-^;oA8MKYA1O9fy5?acN6S`hywoRv!6{ zZQgt0sy|&jt!#_nLn*j8H$(5x9_uxdEPP7vSaN}PF3*iD?VPga^KgW_ie9vfB8YR} zNqddD;&-pU@%&z&ZawISKVN%Lvd=5)<_(eNel-Sb_&5ofRS~wjgmnvk^$ROy{PFvo z+RQ2>za}O+KizuR6i2g9yk`xK>_!&j!M1#nn+9}oZB((>t#E$|XtP!&npMqnTt#DYwfp1P*fx=Bj}8xVZ-Rk4&)VLq z`)Xt8Y;CVdr8|7}8-3X^dp@;VhC`0WC68sEC?03`Q0iTPi31LI#{^j z7?^4fXj*^LrXj$Nz)LZzrrQd*Lczu8b~S2TutXI1V=n?v(FbKFcFIJcRP-`X*2k&~ z*&kNa&C5`Y4ZRPvi6znj$&O@w6jF4AQAD#Z;Al;gJVmeFcxdD_?qZUMu=hg( z93Av5<&TXE{B6SezutGu_er`wSxwEICprQ3p{y??ef_C zk+*pyU*hseRtM)1sa}$4#Ct3+#D&SD+MCkJ`aB=DgfBP-CO7~b3HHXzi(Iz$5T0lq zsk!{BO6N+gOtylk3T&#Ed~U%u^&&Qpg^KE&o?3S-omLMtI@bu^bTiUA!dLTVM%C%b87-Df>Wm(pi>uSqGWI5<=q%y3i0Dn{7naV- z)Fs-I_KxMJ^Ajzaf6GV{opY=;Scz=mTXVbUx`Wq$MrH~g>d%i=NXXaY1tlt6jA4P# z7fyKtUm}3#CxYcFjFcVn@J*@=OZ0oV;8x*`*HJ!Kiih{WeWFu8Lw`Jm@1ep*U3ZgU zq441WK3j}pbKw#uGA|MwD?rW_f~0^lhCZ)IfAl#|Fj#>8HwgAt0i$ff^Na*if1>9? z>4qHeuL?&8^!&DP{DNO8oVpAAb@>H{|0Chl6X17ky?QIQD5) z94SZSjn@S-my`K}07uT>1*GF`0_GD)3-n|?FKGcjGG?D?!pU#MaXY0Q_!k9JBplmL z5X=`3I>0kG&=WZai*EU$QF`jXPe;kIJk}D^zeBjC^%~*Wgm`^JIAMXGD_qfZ_$9&# z2l`FI$&=uNlosIM6Lg5#^2Q43gFVsnbkVT`wz^FCwgKKD9^wbj`dGZ~5D)sm|AcU} z^K&u3ZwbeS@RTVchQB2_$VXYj4ZfSR<{6Z((tmvlmiK6Sjqn{d+e^HEo zrsTtOqhP*p^aoGG@T_q3fxcEac?0|=d9=7cE*v^KJSW`J<+NB_-iq;j62k{7fs_Q! z?>54%o*XG$Y>qxrxY_nsvYY-po4hE5u(0R5!mUhwDjdJiH&G@u`ZmJN@5y>cyKseI zwv3DofiHaSBkHq;B=T3)8Qf!NjuVXl=!g^{Cf)DHo%vO-}0(RE{^=RiEimN zR^<*k)IZlrrj@(xR2I;m=VbB2gKYuyhyTu)4(Ex7aCzS*kkiHC3GomY^t@I?ORoum zea4G^xpY8(?EA2IOt%;1m-3F^4}?=Lzz>nF&=bBF#83VtTzD0Ir`s^u4LzY(C@xlB zCdv&?`@4^TFmD!oBUXMd6ONvQwYlV2xPOt`;?<-;@rw@YMYKGFn{as^RHj0=2Ehm7 zp&ySvUsPtmCgA5tKIQaA!Es{7KQK%>Tb|rgJjj_KxK23X!hf%DYz|(jK;?Ap@*cv` zVZ7kSvMq8*um8v1d%)RMRek>{GeZcWSrCwzNk{@AVbW-cK$uJllTIcilu)MJncQR= zb7x2f1i1r*F1;#EKm`|f?#Is2BGg!ljVN#4&h zJNeCBYwxw&+U4we&czC32mQM6l?JQZHwO0TXAgn71$iQE=mNf6zRHuj0{Z6MyF% zx<#lIRQxUvq#Zl-@G0SR;e6rK0(r##Ea6cb7D9W{jT>PN7S0wf7ASx6j@>o_ z_49rKU6B@55%(PmXzacsK#vfX1aysP(u;o4=Ux#%PQTw04v+Y~^^1-h1awv_tPz@p zcA-n4Tu2WxCkShW>jdiaeZp6Ti9&^Nlkm83sX)3;5|D>pFYF)Dcj&iDAdEwW<-(D| zQNqyz`hiDhxEzfzbdkT>%)T{P)4-uxp&7?%jk1kwP1KtL}D=nWA~8b}lVp-Ib} zfG4~|1i~Y(g#kSypce)7Z4rHpe({grV})rEO&l`=dUixpx93JQ{tgW2g9G~GqS3)& z!V2M0K?b$O>jLAN&l;P0Vf!7omEFM7wFC6O-}GysUjzLb=-0r1UIX`?lATbRJ>_@9 z`rOv*`@O5JskNQDsomDtS+QD+l`AJtu9#FYWo2`^Ze{Swb>6VLD3N4YGugnK@$aoa z{m7rH{;==63zy$L>X&cr^!)Ne%I@0vgTG7F7Fpd=We%fD|615(^Ce!rjTScJvzYq8 z#%kUAbeoIG#!=o5mhB@28$j;pX5v9#{c>;R)|8@O)MJLsWT6DNR zsHb;0q%t|hU8VKpW_`7fg=OVc%g(y^(bOGVTaH1>Za5&HJfnot_Wr5wea?yFKN&0Fy)1PJ^*R;`$ofYON0qx%e=1&jqW-yn5~JVS*)sUZm!ceTXQU3e#|9jdxk9!wZ3(osa9U= zz=pcs>>w+Pi3p&RwiBi$sx6^al0(&q(19-!guJzKU&O?ryRiBKlD>-*idlv50@2=n z+%;h9w=T?&{~SV~(%fnh$C~Nv=;9Q4^a;hdFjZuH{!q$@t*m?#r<_u%Y1J1E3#+t$ zxqqzMOm#-S(hcs9>by(2zR1v0n^18-l32yBxk#+6E+sZJ>ciEIHu7m&A8&Po?aM?F zDnoIN&a-lo?vq6)5GG$BPy^@nEfz+Si%NEsq_#{zH0WEAjnP*nYg;=r0a@AV9HT;1 zXP~INqQ6!8N@Rn!s46q_g5Ecv=efE+PbF)G1??+;DCWy_UR+a*NV>jxOKaDXwFUa1 zQ@G2wFs08D#TLulzMlK*zI7QqALcpRXqV5?=-k^zJAN)_s^lpSqnP4c1TGsnHU)cm z$`=>c^i2r$33@=q{7j|V=dW7FH6kJZ7_gnc*qYX>%;fOP=%hoN6t@y$i<#<)^$Aox zO4J*xRyMd#YR1m9bvM1UTTfcQ6`9z(&!6f`oIICfTYZ>BNyv?0UhRpsHSS4O;G|%k z&X&}s>C1fn-7Sxp^G%!D5nCyN>k5KeF2$*W$3l9^z#@IwCFap$s7YvFm{7g|C2ZBq z%8Gb$H$Ab@=dd&J9;qeeC_P7GZ~igmGG}&kn%inSbHj30Ie|rwSUnf3U7cCd*4A9@ z>TOi5pq)$HH(?W`Jm20omVDdjj-&yz;BocZoh z)&&L)oI0TN0R8DVo1%fU2WBfuduCj)xxZMLjBhg)syfkUk&;3Gh^SZ{OcqNPTxP7u_uNuCF4 zAL@eCw)JIo_XYP1U!QB}s(0fbK6|Xb!!B*PZ~oHZ1-=5Z$P|H2An)Q=5?nZ8Fu^1T zy-XPrfvDS7_uAf;AywpRm!PI_HiEUd4+*TtvA)SV?#{xF0_(f1EAB1O-jHGa@*@$= znjve@*t1q>^h_-nvKC4>tj+EwAoDF@D}gY%^F>_HzZIZ~Z){-y*T8=N$eu9S*EhdU z2QsWn+uGs_qCYGU=D!1)yISOvaBdPTFJBW)n4}Yf3 z=8kSj2Y!mV58H@ebc#P<<%Di6ez!geBFhPBg}!)7Gr1^Gba#w4=>U^CeZ^)}gP* zx3{mVl3uNs>6}$l8CWJm%&NBbZoV6?>A;DS)-XYN zmT&>DOZ@42InS<|m8sqIpqzM4VBW@pTdc3o&uOl0$}BOPr5_}v63z)6-U4!;dt1=v zKTYNs=D9UpZX8wF%qtMILUN)zbv3g~!{bzk^f<|Xq`s*uomrJ?z(-L_muA$iL0!6D zJ*tK?nkaVav!BuQF0V}T*eUsZ(i7&pME$eo0eLRHddc&#N(pmbA!awHm~7T zMFLyWrn=A_2jRbWn#aZpl5V7tPKNM^%x+y(t7%Pxs?yrASiY`u8(fG|WmZJPE)TOBtqsoLc!6r5=mtj+*PZ;XsuN|p) zD(P$$w|DlHPtjEC%@;J$U_HP|77;kKHnXa-xv8x~&9ns}4ZwZl)|1+$v@+8=yR}|P za4%={k3zH)tdMQ={&ck_a5>*zjQYJq`5Ai%D>sQPlbZ1KcT_5R0=pqO%8OSpbqitY zlp1}1$_>=DSS6ASX~iw=&s3%o*P~J$ZHqe=rdzu*i#5;7RJWeUl%9P-Gd$CG(F0;T zS?~YYEn&&6!WSoFKd3hzEe z^nY;>4qw|vhsZoE8r?#FH<15rKo8VFjIkjyyGHaRXaT?EXR7Qi%?FCMFc*lnG;puL z=+i`78aO9v^mU>cs}L98t26s=iZ(s`RJ7@e_mnb*L4J@1Xh!cMnmUR77}3-v=>0@f z7SPqAO;^VTGHs&G@5!P+6vWKcMD)nW{%4}cM0APD$l@YT=#y}j zeCL-o#rTwZjh_j^L}9A1kFc+>pRm7hkZ`atS2$FdEKu(V7ya%oj239$(}d{)`}v0m zl|q#;OPDRp5#|Z=1r@nV&p7?kj)9WxzXzh*f^4OqhG>;2GDy8 z)EVds0o@Tcc_d%thkOt&GRT^K$UAvPf9T8jJwzjWfG{GW%k?XB6o2duqA0=eOq>NY0p9DP1?-MFx87ISmW`_ zC>1Msbylh)S#{aw^{>tyzM*C1RlnHf-Ye#8+w#>rPuZvJtI<+y_2RsJYId;Q9-p7f zbR;3iJAZjr1%gou^g=|IBARD*HEIKUu{H-9o7>jL+mrrqg2H0MYH6xfGt!1Qija@O zUs0Q8?;|?Jp#96P=FTW4Z^x7@6NgZ6H8=OfM9fv!bhWp)b#x|QdhmLT)5*jyp7Jpo zGQ%wGJu!?Z8ST6wFvDU5yQhXbjGCYsbz{%S5C7Of|46_uJR>AVW7snaL=Jk1VDh!1 z89iao?1DIP+e&fS2<&H(9rmXQjHHmiK-eLouhp-`B{H6=aKng^DSju2wzSSk#p`VTOT#H#223I zMr5=`m(SK~kDS9Rwx1Y@Q5}suQEM#`Jtv)NZiwh;i-Pu`jSICawXn!Zmqk~#nVc4P zx|&mwi|uzuES@9M5*DO|-Dwvigb&kEENuNhj;Lt>~Ulq{gMsZqNN z)B&s-Q_XX@o|9*0Rv=nM1M@OMB*?b;RawSz+kE9+Rwl zQg&u&Kde)+jzArtos5d;oAgVWQ!l7nlr!`z0(FOaz{H!i4g6*Tn(&Z8{(OOYh0Kcr zb=T^?_4e?9`i8Ok{e)_4?5Fx0*M!Ve1FC9zNuB{PmlD4fJcEUjzLb=+{8M z28wAQJF28-_Mpu@)U!9xS8y7+tD`=(u(nlu*>3G(zysM2m-Oth`O|18xfy;AxG%eN zNzdfXo~USy9Bntdl%1XZcuCLxTT05}!wl|~@dM7y?pe}PGjMa)w@7WQ{b;?cL*sn+ zJ;;jX=}cE`a}|0#F}q7i&(zJX#<*qp*@G+L%eJtj`N@z=+HKj9>Q6R%`Np>{DwtK} z*1@f_!%KP&+Jcg(^IiU;ifbZ!WOpm+nYQ`sUEJH*YsFmoekS_~DQ^o(U2fS9xMs`f zmXrEti-H60&Whtps6g6OoF)xwR|XK>EM4S(mDJ=PDB~HTBx7=}5OlPftz~Ca31|*#hT_I-jl_1YX9($$?YpAWm2xG2@6m-_0!ulJv% zdO_;Mls<0VqKpUrwXfsey{PLicI7eC?7img0{KO_Vrz>zcNJOhPPCzIt^At-?pWbs zA4S0y6}vlTSl@e43~Okt!LdFDSVKQmz>ama9xa%$_BLGju0SKf?Nr&bj)(nj0&Bd; zR|tf``WBN6pU@aX# zGi1;DBH`R38b7QZVxTdH%AW8D2U*rqWfiYcLSv6Up^4Mh)S(H7G?PEdh_y`e#F{_y z=oP&~1Ja3pSyv^U*uhh#>_43Ok?g*uJrmC!vITTDD^hheZS`wXoxum6c6|Ef-GA}? zPk&x=!n;>hw0(cbs-xbUT=ukmm@n0t_=%~Q&;{{~TBHsTXA(P(Pp?b7xozm!HSQl` zn}ym9)7+4OU2L~BRiDy9_h>KJ6760e>f38@P}sN3@Xg@v)NULRN)zN9CNSHKQ@Bl@Lo;YOV#eY6SuPzT|0$Bz1k9QB#-sGGD2tMlYDyE?m1Y0nid(RmGERj{ExCL;khqL}gP`N2*DqfXe3P%GU16OyHD>f~d@xze>Ga zLU)NYN~&$H%pBg@)}b3SdJnV?tf<4$oqR4QYXHUOq0aMbPhRT?(VHQv8)vt)cXs=` zHT9j*C6vm9Slkgw`i^E!x+Bx+{=^R23RE)P_wQzQyPtV&=~j1mCZoX(%mSqW#C{gE zaZggoSXjGGHwhLux;=K%J+s^8Z)SINe_j_Vb(=#cY;;4Nv6BC*b+&Gw>H3trrS3m< z>i@>E)T~LjgB7}Culq$U%k+u@;P_=4SI+GAf0MYDwYi(c%i59~jLX`17m5D1wXNxD zcUQw#=zLO&+gVjynQ3lzJD>2gQYyIA;zlc)bfyLC+3QmET?|*bj)H}|5g%RUJSyF8 z;yH3=8OoZSt2fEMYA|B6yCAyfQFzmHE=?#h^d$7*^s9RboZqIUK_3{36a366mL)KPAvtLm#iM3z_|e(*#;M_Ui@ua_G+p^#9P83Opa6 zZxl@CHqn+I##lUekXfnliHq=`5G?#>L|d5uCECJ#C6GB$en~Uw`=wy%|AT0YYfY4X zWKM}_#-x7>WZo5R`Q?FSbctx5W2BRGSvq%=y@kK4Xe*210li#t;fH*c%ii+EeN{`R zy$hA_hYCD@M+%G&(GPUF!eI;t%{LEBrdl* zN;J=5WVjn*c|TdSzxQ-_JzT z-CWD0<1l-@Gp048*WIYIDq`gZ!Ud5AeiDJaMCfi@odpP;A9JT($gv=;sdEhPb z6PMs@3|I18fy9JUiFq+se>60fIkZjRP&GH0Ky7ZwA3Nq0SaAQ|B5<)q@5zeoxZbMg zr+Zmfl=f(Gq(iF+?(J13i&BiPZq>6a-N|#ztQMwPyLk0YEw8QdTF_wBe@7v)@Ecw+ z-_{ltm|i0muWFcU^cxL8B(Y3SNmGS;_m`OHOEw$TyvU}3w;se5a-rUvvPx%){aat+Q@oW8y!1@(4vQOCu1(aMDqHH( zs=V$vZyaPn9A*)n4328bEPWirwd;tdrVxK~YF%Wb9P!mCy`U%#J5Hd~r)Hspn6b_5 zhP1nI8cj*_wm@Tb$3#xSR_XAwZsT%rEDo6iZhlM?N1s@^)0#!>{o&1C9ekNJ)+)N( zOm-(;qQ;zO!5f0Kuf{9gVi%v~gmo_fqIi9>rMm<3(MoRA z)#vv35f?9MM7#$3Y^q0`HM=}E&Ol`E?yxi57O$FT&z8h@##M-%w&_~Ls@m43;2?j# zT~s=OHR^+{(II>*MRgBFtdeJ5>}YM$PcCw+XxI)H)@IhE8u%WMsaId1^(prXG%dMTa+KSDu0CuL@q;0*`&wd-YgQa^ zO}Fakx~f&F`ZaW@b#3dYFR^oA=X;6XUC{Q5+KyKBmT^6CQ?@t(vEM}9v6U$=wqQAX zQ5WANiv7=20#migYqVx|Yso$C{oI7l)$ph$sM05XlPG;#@E@(qw~hPwq7D{r{6e23 z@**$3R4n1iFDZAeR}d z_tDjxgiUgoHyDX4WgN-eu5|KpH?M@`K269+3aT#p9?-mKI^0+5Yuw=+b)l2@i_XeY%Z=Zm3uQaI4bhp;8>S$|i>ta06sU3OS5Ax3y8?(qGBi7_Crv6QFi5lEaNweNx zri~NT+&Cg$fkzh=PNV8Bb|N z!bg;;T`7yB4yFLgvwxRdH4oXtJJLCMjMZJRFBXSYu&U4I8>7>xB;6~36BQPJ=dTiE zIu2HQTtyEi3yBbYoQ=-3qnC41t>9^%w{4ib8#mfIlq&W951T%?x9V_5E^ZmF7NC}a zOl~8?TGNx7{4%FzJ?Ul9>@Pv{eJ|D}#tF}gW?cgM=K(!g0?fhxAiSjsKI=BfTq#S| z6R^~-&@S&Fr$p1u`9LW4#;S(k@Wm+6yy#o59qM74Ej}grp5A-bgHTz|v z_21doim>!&0{gd=N5UtMKM^rhzZ-;YBusjk|DPs#_CyH(3eoIWLf<7CcNvz};&p*N z@0~c{?(M$&E$oncR&ti-Clv>2MHinJh~qF}D=kuNtzXhHN%!p=XP>aym{ldyUv1rf@9J^`cF8pOOsr$k?}NpkEV64{77OG^~|j{|(XX9YS{~ z9PCNYFx4I6VqNZB*;_g<6>a(&CmGgykhx9vtYP8zr_zbh56j;4^PFf4pKr~Xt_Lb` zlmDyyN-Zv&!Adaol`wY|ZDs#a$&ZNa_maKU*BPQM{C$-+)_+LbAqvpK|EGA?qzH2# zg=2C3DA3#QL}QOm{wW&2&_^juMd896r3EMAnj>s0nlvE8x*Pf=-s!R@@7OOCJu;$O zMURf?OGKkXWUdp9ZlUiJP597!`)E`|&sLhPU9C`JtlU2kj}7Gis5D#MdsbnJb>TEhUaU)h zTj2K$(U$&8MUzhQc!TKS5q-Mq4|<^fTp^mgL$k(8-GF{r@>WkClRbX1e?>HF%+P$3 z*6b-D%lq^4OL-CR7b2aYpEm;i{8}=m^M3~PKqX#cE|1%)5n25lBiiaP-{Z16&$sCa z2i?9Sj|$4^|3eCg^k6?Lkl$JTwdMCu@@r-KZ_y?{M1^Hx?k3t~CWuBSggG;yCn!wv zi%y0sUMr*V0X;3C>m)38z)Qkh5hL|Wm`5l~>JD_LXzQ0&DE;UJeXbHsdZ5>dw(>nQ zkhvnD?~zC3|A5~}KZIW)nlwY7r?@Cn=v#v@S1E0l-}_{5&x_|oTU|X>GV<>H{#y1{ zXKs@veFb6OE!uSQh-lO2_X7KuMWYksUlVP8>|hm&$$wb1rDvRIYZnKLw(?pk+Vqwd zZDFnxZEgQN(bQYw`l4ub3;lrT@`(Pt5^v$WBzx1Q4ghR=)d)=2?LKa)qhlcH!KlFsQ@Jr!W!erqn;WQM2OrctMUihX!nwJS08n|z{ zeOSNfzE=2wpz7w@%V_=XDU27Ygn7cxg%^Z!fw=xCd|tp0^i9IS0&cGh)a{YNs{(a{ zvK%2y74{MK6{ZV^2#bZK!iB=c!d=3>!UMv$g=dBD2|pIz5dI$evS9nu+ zOQ;tP66Ojo3Qr2?FCao6; zr1NosI68!Dg_{N9A)Ffobb|lS2;}J&p-Z@4KyIzDPB>XOT-aXNF8bY1zZVI23ttt! zE<7ZBNBFC-vrs2A2rmoo3p)v|u+Kv#O7ETp#L+{5%^hfo3QbfLKp%R>$}yjCI0$5&ejMWsc*I-6J^iD|5cM>vrEeb6eS!>g%N2)R#RrxMNVK`%o!@ z|6}I#*6b%sd*+{6zM0SG1)n#nNNB$foE+DC>)kWbPtN+zv3K3_kq7TR@1f-M z`hDsPtg;XL!p`wb?#)mlXo8X;*BH|n^!j<(X{9~0&pmcC=iZieGsUhV z`@_b2P22Xqn_fNVrPqHo^RC5B<(-!dIO}(1Uy9%Cq!EU+lmrT5q99!nJ40&TW-X>&JTAUBt2 z&(~NTr-%b(5uSJ8=oAs3yNSIX-mJ4iirM_w2LkL(^T~pE{K9PQyaY|tFV5#JfXBhJ z>BU&j3^ikf8U<~W_V;^%wg+u*PlM(eZ}yC>ps7iW8vr$n=Vp0C^XwQI(JcWzRB=)B z2$Sci`Td0G?F7QX-O|G|g}AW)qF`Z)jB7COyCxjMd|D_Mkf*)VzO5hNxk?=L5&3rX zBiJEBe8`aw1s#vk$uD8jcVG`sI*A*<*wMG0Ga`F{UPyS+4x70(CH=VjIE<@qK~FMy z#M^K0^zMwE&i=@l`4|7?;f#*7zB$GxC3K)54zjYYt|N7#Zj$==dwu{a-ezaf14YDElZys9;UET=wOW{UM@Fo-1#=NA@R)wzxhgnluv5egbL!i0}>B z6E61S1)4o_H3E4dzx9H3BdbM|2JHVWzjPzWzbV@Ezz`Q28IIqgH)MV+8XXZ=RzN?< z;7<6+VBj%?&6I#HhAs(Nx){=Eeh7oO2$ytO7r3Kn^oHKitD<(pq@5$0FrMBvyMI~F z{OpA*H*+5q?_zVvsoA|SKn=*B(MtwBcOO3QsDU>O`TqD@9@}BjH;#O`blhpTmYp}o zcUA1`cVuQa*S2SZmK*ZXVF4%TrHk#57r6kd2Xk~1V-qgx=Io-+>Zo1ojz~1SFOm8T zEzu+t8ehRRNkE=LB^k&`Q3o!=G+hn)3HvGON<@hs;yCys)=>=Z{8?L9a&%Ee-=f1S)wAL{5FTOFBT|pj z=y+@BV8P|MaUjhdrYi7dF8SUH#hp#Qn17XUp>SZ27xhiY2*(TYy1<0F-<SMNIpz zSFI>h(Wrq@dvpXpQ&C%&aRV@%^nJ3)6_bm7j6D7{PlfA7eL$RJwPu{Ds0;#%I{blC zUwic7Z(dS=?TZ&)eAF(#y5y94Rx4AYGg=8m5<0C=z$&eJw>tYy$*ytk$fqUaV`>xC?P70@V(N5p z5mJ}lT}x=SS`#J4wALGa+-bQsD#XMlKQ%3KtC!z4h1Mq7PWfolUwn0mZrFrW|nTpfwq+! z>{yL-ty{nF4BZ$OVHp05i+&l(!0#(Cl!C|KT!Ap*844{G2nU{F(a{2O7>0JM1l%$3 zCkPCcF!1L_zs6r9f^aan-xmEE|9}V^y5at)VEKc8I?o+DlA%PWGdtzfnlKQcz$K=PV}TJ4%u* zII$WmqgiB$6-P~(2}izET;bu?(P}(qm>=(?mPdozT^K9SP-&b82sA!uKJi7PMW$Ln z9(y_}=4#M1b{aG?DSLx+H0 zmdxlNpt+`N^yDC&qh-&W5g9(Q#(WaGNiu{(m`BK-xheL?h_<{FztL^7xAcsVU+nSA zF)hm%b9Cn7gi|XSbb-tRvL6}Q|F>w<=UmCKen8$>hcJ7tx$YXt>&Jz|FP)y8T*oJ` zuA{|{a-dx380jFoL!Qxr(d3D=U?0xI%f%yOWlP-XdZa*p zaYLR5AT)V8_oLYZOM9kWGGH@z%;ECkGOgWd0+7te54>#XkTn~gtiNDHMP|;g-hbn) zU4JmC>@U%4uL7TuN8iCj`$*9n19CeZ$1y!=O*MPk&uR*2<};C{R>AavOQtKcbjvJm z_|7Kxrd?vCML#XCC;T#f9M*AuF)cTc=pL>YaM#V8sBM%v#q*_d)qOnlvXmpu&xnofmAMgxB`ke?vlI>70oX_Uy! z3FxJwX)M?`1@;-y*0G!^nud(bRf2U^UleWO-!IzI@Qi30Kk_dMG*IYQ1+#x$w8;-r znyoWuk<#d$MVky?ZlMDqoVkJh(V{J#Eut-*r-?>y$e$C?mx#9f{w%UbhcAdW-QFsi z4iLZJ6OG=H!9ZiIgB&FKcR@IGxPt|BP5HpnF_Ld|h3@cc9U~o}b&Lweg>U6d7<6WI zV&wvzAz_m*7HR45Mhe)WWAs4Y=v+yc@pQO^O+6VM(R9c%wfwR30w245!z0IEJLnYB zS~jR^z;>;}9^U2`TVFYNt(bn(uYpb1K+mM?tkRx^J);Vqx%n$68iM|ZKj*IRh%pb* z4jAht;Wx$n8@C2deemu1#|-=U6ZgDV`NHK-Y;)T3?9HWJG*FgDTHKO{pPKu{5dMbK zbebQA?t^BB32E$HlX5Oz20NND&61`I|D}&)t4gyiKbp5uo%Oxi)YQ>lU%^-HS85fB z&)PSq>-f+;>$SYgU~a{qMmJ3oWWw7W|>y|lK6e1j!Pd=zT zWkHC<-X-6*T$O~=Ap3TO%<|Qy#Jg$o8;_R-vktd>!*bZh^Sf#Cn-XslSFt6#L^CXX z)hdlFx#erW(5?5FefgWakF)PuQC!w9inTkvbt+YLqNq8mR7*(b8duX;^kWIIO)hI( zxi`r^KPMJLe!ZxZEFt)1O3OEkgDGd{>k`_?#9ASY6J2~s{lb5zQbkyWk}Pi04!l;) zzqc(`CMMbD+Knx)nl0h`#ZwkklO;yuil;sFQ9RC2B8)jVw$LR%CDdzl!t!m>y6a>| zZ4T|wL1FJ;rR38W$``hnuzj!;OrO)HG9!$_#cFH|`)GOr7F5xpU)07ge4F|pmaHi? z-=p|6S)HtvYf}38I@!37WXYTGt;8A?Cd>ANq==;<(^?u@zFnWa5PukZUv zUEj}!qB{}w_6i5K_bOKFyI&u02SU55{v8l50KO5HOl;q)D<6H!ntA{H_$wDpd}H?e zk1hMu?5~&IKQP|ONH#KZLLm^4W2v!%dt*_7gP*h&SSMlYy(+k}RRW5JTHp{(1-o^M zGg`XhF>Z$0S(_Lh^^EcvFyL+@bRO&AB!SU3kN8UkM()t%0y6~YWdgGRXh!JBGYdFK zK;C8@3>h$Y3)nG3xILovS!KJu ztt%dj%=_$jHhkfZL-(%z`|bN~KkdOETy)so8^~@r>LM!`Q;p}e3buFlkkX#1XKe1b zn@1PpD;Dwg&UAfnPOS3&X~TL>{o*5+?30=F=A)ne){1vtxuQ(#>{K(8o|$gqO1<81 z!_ZalVu}|C+@iGJ6Ure)-f`&`qpSTYjH9iNpb+XPvrg(Ein8TL=sg9iyHiCYL!F_{ zQLmtpqwYXsOxesZiO1>~GSpoPg;Vs8mkf2oN3$R7Gr&xCaM$Tk=cfmLn8O~dp9=V4 zhfNo9_m7(-(=MO(OL*)yv!~mt2fdHUTzP0S{J@R&o?}=xWUnZ2ves^wqZ5NzDTt;_5EbiQ)3B%L0 z+|fWd$YFmu8A25f&I)ZPrQ)_|)dqJA!+nfNjp!}+42PL|AW8bz8)q1V2HW*Z=~|kJ zp()~$L7aC@c)z>uOTc^*x}QE|+#uQy6^q+tBCXV_){qXSr-_zAn&}A>m6mAu=2K2i zsUxJw4;Ouz5oeg5aJN4!FALQVI(=?@&VB7?NSfPv!a;FJ+i)^>FqUw7`ghXBy8-8|5&HUM1j;DHqNcaL1GjHw&TrQ{q`eC%kgu6@lj~Bbrgd zYXWQb@MDBhJv;MvQ-o%jzC?iFt{fhzG|6OXKZ-2K@{M6hoF zKU?5k$m~~O<_NEfC;hm?zb*p(VCD*J7?WQN{17RUaSHLne@MLPf1dcg#54239e%cW z%g;jbyc>Z%6XJtEUOe$*76~olDQDc_*NdkfU=|D4iZ9VG;ltl3p8R2!3cLq^`0)?_ zJ@KZW8u8CZ{&8oP_M&*kTJVPpKNoNLT`vBQ;?XAt{%?_g4?Z36M~d$Z_@l&sTD-+~wD=3fTmDyyzf3&& zQL^1Z($7Xb;U6b_Uc8N2j~9Q3cq>2n`^B4n;J+n)h<-803(ttR^uxa*-tr6oXYm$4 z{9EG9f1UXE#M38W;6J3oroLg|cN1^vf!{-X=zpSk#>p7m_s#P^L%fv_?n@$f@(+Jh z;J;q{@qvH%)#6P*@EP%@5BN_<{s|BMOz{?9gZL}*_*=zW{&2rXyyYMMN%2k-r>yuz2UaG;x2Hh5CkVu|zd*hZ5r}_@KzjBN2zM`mcxwgX zs}P94TELz@mEVN|?qdYmPSY>p&53^J>6dsb1?1}m z{PS#}?jIKM4f>VAIbIj|;axv{XqSnzE=J#j^dQ^1m8V(1>DNHN2KqJ7uYvzX8u-F- z**T@zlb>C>(G8`(_a`%M7o?&^Uo`FLUb#=jzPbn1k!lQ&uW+Kpue?|2exbzTZKK00 zcKh-1KYL~A@G-5Q8v2h9?bP_a8)t8&ha2k_tc0|drRY)y!?u*$;iAJ%cPXIqsprIwCwPO-Yh0^ z$N?pM`4UDq{;(0NUtt`@ZGFsPibJ|s35M?ephbf#q0pXnY0~Kr9^|{Q@`lgmoLb7N zEGvECoi_C-4Hs;eon6{feP!K7o7#VV?>0D?Uct%ql;1LsTjcBSTzc6*NBr%!4NLF4 z;l;Ku+_2RP`@EDHNQ>;$KWY&zgwm>ua!X61_WGJii=rMEu0Uhk;o1h}Xlu>6dZs=l z2QP@P*0mK|J*5@UhN#Ju4LAQ-f2D>|+pKM{I!ep3)zWbH0olUz_1-!x%&W^b>^DgFE{4zgeo{C|f$9$6cEAsGj1(RpK%lr|)06FG=$YGchrv&8j z58oc~`f=+WCr3OJH|Fl^1?Gbo)(*}SEIsho3d|=75B?^Bc`b&y{ar%HeFMQe)7P4p1fK8U|vpG*r9XQ zFFr019`ywO$PgZG$dXp%DGSyUkR?3A2GGdihj>|!L7qI526T-*bpu(-0G_(VFL7c| z-5?zDhd+ypH3yjn{@6W&ykB(<$uyE$pz@qCL^;CcSpJN5%E@e@0B<^EBU$ew+~ry#W2>#@vx_av{g?Ztr%G0JpdPh6{ z3_^ZM(Cg-oaPuX?k!Wry<~}L&{pHsg8|(XehRzvPH@GLOKOf)^s$&afqvYIuT0iz< zjEo%h*N?5)?_aAN+s>?U)C_i78Ramhq11W)wnz0pmn$aiXC2f+uR&67oX-n!V$+?I z7jNU|4(P`7n^tFgm+h@q6!%fQ{`M~W!9p)ymy3tqSB>^Ql6g(oQVUyOU($W2zc7Zr z^iy2=gT~O8jtXPwOG}K<8@1!$PjJ!psCCqMb4ltNGg4+U;pu`TwuI_i)5Ya_(?Fqg zaqSkD+w@S2YqT)bzI4em@q?OUA`d*zdG2Ct?7(;eJD$@#*BN*4Oy;=`k74Yy6l0`829CJ5&Uqz(6p!UY235BSN#m4fAuG4ZtmV;J1`5pEY4pTLusuL}6b93VU@ zSo-0g704?F{s%%R&p4DZ6XD_hnm~R@<8BsHiF)lTIA0oR}@#F_HQ#eID`p3YZ zDW353+aIJVtFZ`Y28G9lR|AYwA4?j!b+z4Y-_}RiQMNsc3?>WLh1NUn2 z!=z~3k)J1w5|4k(e1Y$gIVjXr#yayc&iV%bMD0S4S$e$<^ZG*etF~$ zf0)o5xHBg`Gw@#{o^vDk$H3nwp8BI7$3H8Aeu(gv3%`!s;a3Rn2JT0Q-$|LpKjuhb zZ}IrYz|R$L?FW9DcqnZW5Q=1O8C?je&-0tlNQ3E z&&HlK68|Ux|6>L0dA^a?nGrurzqlVB@l*9noO=oQr_K^SIz|rNk?!FFaqb)O%-2ct z2!V7?7x2GKAiQz`evCkwA1Dwm&j{pa3+QNtKseI`%4YBAw?e=8pDQ3=E#N*e`kka- z@^^@U9`+N^JKSii(WTO%IoIP$c8erfak($@K&w4M1s(LEcplT!|j*C#jM;Vj$AH` zsdpEa6}i>M*a-dIrn;zeY$_^Kmct(;=_nDBO={#e+3k>pqk6!aiJ0?_H-z`ZXZm6|oyn$>*1w*_&)W zPZ#Dx;+?aUAUm<-uOSN2eEM}7IzQHzipQ4dKB4fD%jL$I>sG9G^!*4RC6q+(b+>q0 z{i<}L``i~+ct4i++!Xia)_d9Jh7rp3)q;EXMGfe!P3QXRy-a(T+w?Srp>KMc^0lAT z0>a>aY0|cG^_}mNGV;A+;=}h;^lG$Ac1hS%;AJH2ceD49+q;E5gx%9BwvL(`M)7*3 zC(uR=a|8?zGagtNXdd)D5V2!^WeuG^_F(ZXn1mY(? z_}>cTi|}?A{w|OX;vXxpZ_L9Ueh=Y8B1kX%p28;r_i^I6*JT5$y~OivZ__1wm3Y#R zfoHvr0Rjg8DDey|^yBzi5$1oq?0Cti=@Kh#%1JcP}_bd*58sAJUYF#`Fb&L{~E_#v&tk6*%K9RYh}iH|ym zJu<|JuAy0Xz<#7a+AJ-^jeqJEVG;&mktfnlT|}NV;h%LB!rMc@owCDyZ-Km%2jXQN zgE-0s!Wb^3)09A1e^&cme+t1(`F88gm9`Lj|iIkQf{DoTY$OhCqjc;Th1sYRo>2^=8VvkC z0;4NN#qbA3zxr`^b&uEjl8R9VdA}oH9KYL(yereB|3&s{K zAL_%1wfZPy?f)+y9BNR$QI-Vc_I z={fz?AKrD(;LE0!y)Y==JV;*2$3kQr5-&UJXsvCw0B7lgmG%0XSGV5Orx&evX3W6^ z_2%^EF5c&>VB|G+k3CkmHny23qRQtpD{4FISEV}i>aAu~aYX#byxhCGBHI<|=7uW0 zGBmOIqK4PGzct5dCUw!Mov;&u3)j@)hZHeKl{DPq|mW zK{4bu!;9Xgs+Liy7|JgZP33|W=9zudgn&|m#<&B15Cdeb#e&Rg{1gQ~uRepjgzW*OfWvN-VE zt!3Wi5=+>bb9A=Om4m!GeW3>ox}!dzGwkS?;W6kCUGt0K7f`0i;};%z{GL8CTV2|- z`xzCRQ=cpJwOf5ViLc?rO6+-Z(0|=|ROXF`n{L0U>4*cyzxDK_#wkiLE2D+Cp4cD^ z70Hc8c3u2>I8QlN&;2uzbxQV2IDO1&?@8iVcT8^Pm@-XSiZ(6)tEg0T+%Ys3DyTJB z_>ltc$ip-Lw{U5U0D0W4l3T;0p-@P;BPY|uA6pmbzN5Nor&qqeKvt`gJATD9W4Ex_ z!es};@Ah~-^ySujSavc!jF)$KvHR5GDm29V5DE=<0^Lbu}SxA<+0lpDKWnH#bbm(si;G6vT z^qPE&lkoQ!%#OR5euvK9BZiBmrcfJ+TVc+8%Gl%b_W>Eh+0G+wb{v2`Hd4rFk2Q7N zC~=cTo9q>0ON+>V(<1iCUDdE{`B&KcLjk11?wBS=1wy^h!l)gr(0eMpA4WOz9YWrH z$Q#!veZLz?*NDc+rQh{J7WcJ*y|2m1y*R%+5*`{r!gh;j@22%)HN@^bCw_|GujNPt zeNd8jf1`mM`qy!@hw977!pc9)fW6}LsCMhZE5jEdxb5c+8dzju_ifP|J4t?)obtSDsAT7#QZ~69b z(4^&heTOxim*-P|xCu_qxsO6y3-2xFrq^y&V!QE~S-woNFGcR?C)vUE?U7!K13UiS zt>06pt+E3~{Uj{j6}T}u-yZxuYIbiaH^0Np-K?;85Br5&IlHy*djPM&!n&60C+z)l zL-xDuzD7_6{;3^k$fL*HLtM0C>$GDUvGEf3S;$s ziq&pk8op2KO_tW=`w{=7%P&PAVj@M0qwEXi&}CVk1!iQlBDg?OA$LgOjq<&^fnyS zqnG!beKf?Hw@O@3)6x~_7OM0fl8tuchK7_I`8=haj=6V}= z>Z$Mhxuu!keofBTn2oucuC0fsZc>KfQ@^my(8u&8m)k=o(v%`?+xlj5N^He?;Sc6( zV=*Q*#*Y>K_%VqCiXMYL!pmBJQK;YWIZoPF%OBFzVfqmpkD^;XI)tv)ITvD}FDwi* znfHWqph8K?KCK$a4K}oxKgLP=J5oX~ACB}wSIax|hNNzqp6DfMtA2E0wVgJ_sJbv+ zzW(^X*4ta}=xvjmXlBoBs<`=fWX%E!3o96C=3>m_uw$Wv#S-Re{Ein`&1C+@M1Q)# z+z)=VFk8T#`Co;wOu!xNBOE8-hCJudQ-aMUt3|g8#7q3}pNe?qjthlz1;WRDk#My@ zShz10ZW35f!PE#}6Ig^{jtT#afM3jV;d=sU!w&u>f$)$&O8BLK4w#!BBfKlH=*B#@ zPO$G2;+_`xMj?w7q=&p5B!a~(_%`7P5zMDqkZ2cD;#mm7e}`~_covaJ&su?Z`w|!C zWZ^TBf8#$Z9(@rW?zct$;ZG4B6;JvpzfTK47H_NDXNmv4c;d&v|6M%c>BsSd6%hKt zoGol8-qHjAQSp=q^6;a@TYk?GKSTW1`bD3V-J#-b(dGj2$BCyNVJ;H7#Zz7w`18e6 zCuLUg$JPb@()!D)+va}fdF(LAel7}2KaRg&1Zx$TO9bBQOWH8-zZXy1k%#|>h#~sL zT*eV6xL+^+&A|Nz@l--9 z`y0h>Bi`}{KUzGCqL|MM(*k+;S$Xb9inq3bJMYEaL%*1tgp0*n+kn4LJbi_J2HYat zEMkOyN&juamKpfh^H^Yz~3z1 z$^-r`@w8P8{KMj{zQg}8k|%%gKNoN5zgPU<#asP?A1Gy8c<|fj@x#Si__*&Y-qHhq zNFF~wPrhEf-zlwPD1^;L9Qju%F59s&JK>i`|?~Awk2LDlYjMl%vPZDo^8~i-+#E*eL zQoPj%__{p#Pv!Afh&O#9f0KChMSkG#5&t3mVjdA57th%&4E(EsfB4tM(-)Ip_)>LN zRz8o4-(I}wAAW>*%P;)CdGa&FTYbQNo_I?S{7Uf_AACkU?FaLia8~4Q{B@B#>BIeA z@#qu&o5FX*+q2?Z;(sQ7NBv^p-wKUBPxKYWdNiw}OK zc>Q+ucBVOcy4Z>&g_$$O)e~0@WdHiGIEq%B@oyY$` zyp<>JzY%Zk0sbxVqz?oCp7=7ydA>x-2>tIY-pU*KiQ=ulfS)Jc+AI7j@m9X@UE;03 zhR=!*^LK@KtDm@kNqiXpW8%wXkHLL|c>uB-xMFl4-@KdYw`AcAiR;{ z2kRFDKU%zka0Y&&c>Rxg>~N<(T0c$yMi|JI2`jdP&!tFApV1d zLBf#&@f|PVr#t$kPepE`Kt3l6$So8I_c(#{T__Mfvc!!n;ZUcsqwJBd5OA9(5YEX0 zWp=tiIG+*7!{q|$r|&@?zsMm2y_-O|BL(6eCEzwrpf2ny;J-&8yz2z=eTRVj5dz^{ zCJ@d|0_o-1!S4tGcXUjC$_3;O5pbU?5bgy6>02%!+b)ofFAAi0cLBM>1?ujx0^!j| z@jG20opl1?w+Yn8F#_T3El_tW1?tbm0=m3Pz<#QLT!VnFI|b_aT7i1JPC)*10^!~- z5HB?TmI{QsUZ8$`RiIoLGvGc;AfAkX{^*lP=jR2|{YioR%@ELQlR&=H0&=$q=wrA* zczXzhf1p6PX9@V9Bp}DLpLFam;Qm>GaQ77OKS3b9(*)!W7LcnI$kV9;`9E7gA6E#Z z;}n5%drZLoOo8;*3&el5fLxZf?1?pA^PJ}BV7Q6OD+3h3hr0l7s2@t+X! ztMp6y&J#+6dj-nnVS#$_DS><~5wO2UK+nwr_QweLPYL*6A>e+kKzv`1ep~drtjm6z5b(D_Am3*Q#CxkyDttx2|Ca^)-zAWatU&(HkAA6J$ zkiMIRLBeg(@9p}PN%P0n1xD6vxBs}W9rX<98CWuSfd2QJehu_%;D4V6UTn!OEbEz^ zy>qj^G9x-bH%n)BEA$=TmiW8a1E-!+zx{O=UH{!*9hy3Mx9K~MeWK#tuOEDIb2j@_e&5ya`f$shQ&8cKso%?D?~c!(^EW)%;P*rc zJvldnZ*~va@nb(C|CB+ltL|i;cg}V^3N98-b(R3 z8t=pJIQjSCn{IM*Sxl~Q=f%#_*l+GhCbK0h(|s|!zW4h!-AC>|TycMe=L3q#<({P2 zxP;GPt_ICl?^>f4hbMN-N4|Yuq5FNd#3#FM;rWbQm)x85xo(?Q3O>H#vc>gpK6=-@ z?G@U-Zf?4AcLVd?IE%Jct&rC5&$)2|rI2H<*YD&fuIziVpGb>lr#pGkOkrPQzKF%2 z4JowY&cAtdHV!66vB$a-Rapxh2v; zKjqK9_;x}ou<;cqNBH^(GR11*ruLVd_wZvDQc8(>eHDh8l(wA(@ji-4=Jz~S3+=^U zg?^HAQg*hyuy^iDCb!S>C)zkK%U4nC`|X8iVL0t)BdfwuCvQ>lZ#?JRTK))<7_iZgl^IYQjW#0oSHa@avcQ}G9CTA-ye$?gX27YAZPl)=n;mIf>IR$I)_~UuW zIEv8i{u<%%l;+vUSh?PDoxyojKXwhjlx9z6KR*bct~M*gu5hO7ZNr%Tc(C`A^Q=N~ zGT!d!BTp!H`rqfdxNR{_c*$b-yuuN9-#587rp@Grm%pdMh@7zpUm_~56`N<6RPj9K zOC_V9Lj73|d@f&w({JpedcAP%;BW5oX-ca!;p*amr3R$u9YZbY7 zIehJ+G`VTY$kx|d=0V)X;uLqWe24Cq!qCp=(69D!ztyklb-6mie3BT$`cC@&I5j-w z&3u9Hev$?oefxP^zQz()n~`i09b|tZHbDauA{q8$*_*^bv!6Opz-~8zeM+_lnGftC zAOp|7v#YR1z#aea9RlI8H#%Hk zpO*Asb{EbP*eAunUnH;}je-B75X!T!%Dyt`!Tl-0+{cK1K9B!t9{+psmR{ulC9q#h ze&F91&;w?yzOi zH{p#C@HZyn$LUvQ4S#H1pybNG-+9ibyAL4UgLMLAt7pm{bO%8Y+Ct6wL$imK_8fHi z#$PV}pMO78`1Rjesk*M@P2!h7**tDw^)5$VQhEB#vxk4=6O-P2>9qzG7b`w~G{dO5 za3_;h9NZa;u%g=(P>f<(Wi=Pi*U8S`!LqSwVYnOjlk6tu%Q9wRJjo6gBZ&Mo=gaf; zY5!JqRsuIB&A5w^sn-eP7{c4QKhn$Xe}5Z}Zzua(V}886>HhtjwD8^J?vQURy*4KD ztF-GjNh7S%aqHg3hLmEl6!!HEX4aD#ce6i?w$QS_CCA;raI{LwaN|3U$&EjMr!Vo5 z+>}cw-p!D3ew6HYgP2vZnoPK?i8jV3cj>|GX$4KsMX!V%Jup2Hy(~06C_FtmJsCYC zJst)(dPaIp4E!erdOHmKVSe!;Xfyo3mAI;hXmX)@IMxa4|({% z3iP@d;@wsb^r#qkZoAo&7@pTA!Q&skTm<>UkS<0B=mdB8@ewc5Uku;D# z!bX2QmBWpk zlBS+v*(Iet`(`_~fOQi-CsEs+KB=}-Z)J;DP8Qy}%e9j(e>#2TPf|ZQdCKacV|PB{ zZgOJZL9kwd9>HdeNxP-(V9*8ShJhyk80-LL!S6*=vWrW57G78Q?!5o`*JjnE>bpA9 zo!u2x9o_AnZA~4u?W@FOk`L$n@kd*wZmW5F!`6d#{>@FldG$AU{eIx5hA7Lm>Sfs3 zvOOqv#^~kzQ-c1~pAh27m+ZN*yKj>0yzrKcRkGpZH|;rlI6QlOU*`Ktc6+>3;f^1x zQuxo`ze_%y!xM{eSQSX#Pk?QB?!Z#kcOH0m0JC(zub1SfZ(p_&gkDH1qYStgcbfI{6+Hav@1r3>Rv z*6C;sq?Pv?O^N<)dWzU3Y?9AS)gQOe8996~t)mscr|(xC{Rf#QD-_lbCx3wWy^kr< zJ@1OZx2HEf2j16I-Fo0{5`^IC4;sS0N;mJPAOuf;kPwo7%b(C=)ab{ue$|SzH;K)r zhdf$68-}L_PZf=n}iY+ayo{RLI4AN%r;$lKt7PY)P6yQEw{{pSBw4V+Pv zT~^vNfBot$V3-`dRJ%5_Mz2t=?Wk>TPBq6P=G)I7_LV7TWxspjzUe97`Sc-IywZKj z*N&0q^T!!}?}O)wfBR?1vyQ?EYIbbw3t=|4^E)2=^)kuYN4`XO2HU@B$FDo^{!7L= zem5rnUEGB`D6~fm?bP~AX!;M@to1$g2ef(I$_4rm4E@Jsfj$NUe~5q_^6+y6+Bt@B z=L;4u{IWbAJAi+}B^|VP(n7d|MYzCZv7^u67n$=%W@}1&nl9fGs@2l2*3NWGs=~b= zyRE$@)p26FK9#A6-Z^W|4b9EBZ(TNUYRL;9d-3CMEuZk$yYK$;@uMb`p8wQ7Ke}AH z@LOcb(J=->3{|OSRIp+TL@dtO>+x84LDC-pEVh)DgiYn-Wwm~AluQ5_`m&|TVv8Mw z+qf)M(r=44x@yl$5pCGTaG1e0GJbQEN@^3%+{212Lv36pKc5`B_Jccn0T%;5CRu*7 z)L!#cs6oG2h0bVhxl;|cGLyF^GYMoXm5HDqV3M!gT%xCNLz-bdy)p>ttCLnp?7hE9h;(p-Uo3x>|F zPOz}xTLcC=$irs^I!VIg_flc3fI;p7!8$Yervy4G4Do(Xz#j(w=h3fz9RF4xKTHva z@_Yo%2F3Vi$&L;Z1J4Vuh#v#LKztbgQt{R)#?E9JfLfFU}LhqOV}yoFrDPKw-8Odf#Up?&ztMH_Nynetp|MKS zD4nrC*61j|a)VviZ8Ku?lA$ecfhQiHLb^@%Q|R#g+mZbvi|&wpEDNExyjU5AF>K6_ zTJBpq)UkgM@cvQjQf%C*R_eMA>w0PGG;5#+;F>=3M!Fk# z?8^n3Jci#%0^I{L@N)#>L7r}a5j^e~x|NJTw}F8_L$IzD{&PYof3JADEW*S68-jJM zbUWV^=GL#i%gU-<(Iz>N( zg)DIZ!m{oif9M7o;wEh3#2vq+i87Pn2^_Brd~x-0lRM9U^mONU(BB4ZpWg1N?RFo0 z<+kgGy*6yYHur9`)6f&P{?XP`huk=1=vMV*4-EQS*~dydOTJrDK`8yEUjzToY9KqR zq-XY^Eno<dV(YBnUhdr43Ame6h^?H#Jmf~Go>i&E%sd3M*5o_)6<{Ut>^;OE($ zOL``6DQUC1C#4N|eTx|#P_)sm!IHMLZxaK4y+t*OrKuCTQW>>cH1|&S<0U=&Zz*M( zI}{l3cUtV+EhTX(+O=&RYxn|bM@#&S9q@j3L`lz#Ehdq*Eh$E*&0ThWaKKNtoX4vg z$HLmQ+oT=v2hHMInaSCCf&0e)q-y&22aRM+qGZt20mBBCT~|6vM8E0RK;IfTb4~UL z?GBtXY73ZvB_|UWpP1@sc3T8=wQj@s^ml&o#6!;=_p!Zi`tjd({p2zC-gsqtdkdW_h%sd_NKk{j@^f1 zvf(CUv2TngCmndJ9rvG;n-}3~cHsu4t-SKf>Lcd=uy-B+c2(8-pCmH@LK6r@X*20{ z(i1u+sMEJ*m>qX3@V!$g!%z$FR=Zivj?7|sv;$=pa*-_k>Rb`fx zI0(n=v!@Tav4faZMP9vK@OzbB;=?j!Uui-g7@wK;XJ1Ig9zF6l!GM|B z_Phl9E;c=G;N!FZge9+thrIH5&R>)}s;vF^OS{8af$Y8U$xc+%?7X<(q91N@?`IYr z{Edf>KmOwW>-YQIPIq&Vq-$He`S>xL;K>}nYBJn*8*h`hE%oVZw~G5^*@=rCIDo}& z5o=Q7kCWL^hQe!_vN^IzKisU%P6%5VEN1Vi@x@u1AK%B2+~!`~#dl_~8J=Y|TY~hB z`p95cZ29L6i#7FrVM4qEht&HAH*2Cr$!yuo4|`)+mQ3$Ud4j15PvM?+N(R8tJg&iA8X=bTfG;j3shKn#Xj|=m^-drvVFpE`fB5&6D zJxfFt#emNhQT2%re1(YD0+`>MMEHk4&F`%u=f~^hL6J8B;KxMBk3sHliwKJWe@B#G z?27QK!k%{AUl)1P1OB53{>TIVyU6{sAXq8~_YdwT?EJwT8w=eB2%|>~?hxsbb(CIY ztq`Ga^her#v5s)WjlOs$46ihv(G|}$i|7FzkeB2UVMqgZxWN;d@JpI#I*9|mgn=K= z_(KLTG7_G&fsy;1Q*#T-+6P{+xEu85W;C_LUzz{=8&mH(^>fpHaQf#qUwh;Ir`^%( z)KQP$CxNr>D~a!+vG4b?yMP9ib$iYo**&7(OvFtn_x$lKM)os!bLu-#efwK$v<;7@ zleZ;JPG`GE?9}DS;@R;o5%yw|Q`pESXTu*4rW3+RP# zR9*B$RfY%pAdO&nK-lq18sSA4o{@n#NGtB}#2y`D2M-z4wP9Xhvq!#p#;>QePs6QO z*_TT6zsK}wphp8e8tBnLchtb;^K!?QwNJU}lii^IHoLCz2Nmq5ar!Lmoh;rz^zWnNgFc*{D7U^NgJbTe5APJ@)(m=Z9AcoSXvaS2 z|Jm@FSwi}F#>?*8NZPPtHObQlzx1{|9SphcT(X^@&hitdJ{+LaSEH}nCQ1FNFwXdl zHa$Bu9^Y^rBmZ7Gce>jN?@-3L*K5OBn=7)^k%KiE`Qu+C5A!UvOP|ko2`B-i$$tw| z<$2W!<0L?EL9j%NJ#AB zobdd^)sM{3XSQ3sDI?*t?GL7ZZj%piBOafMsF#byN4W~0UBdX#66e?$C-|>x%JFJV zVAx2AlXMO8mmC)`i9z}2*TXuF!!nW@tz5uTD$s|gZh%r^Vvt?B>L zuf_1}V+!o(uYxi3S-qc29~aC}nSLz&YKFk&BKo%&hPFdR^ndAZgGY++kKt_YWD)&h z;s7HPeQ@~iB03=dte!*MQKFkf#E%&*x?AMw1+%|8#E%Li58-itMnwAIUn%;&2zSg_ z(N9I_6$5@#L_QE6{Eo=uAE#%|r=wpCn4>o#{+KZ12n_DK=G}=OTp{f7PY@m<(T{$jDJ;Kz2Ru>4?K`9&JV`V|58LP$Ltf9%yF2D6kH?QY`@da(;1$BehXM1g zd)Ei}RAEow6yb9N|KJOS$zKfkT4D5~p9tTe2QNQ+$nHzRE)Qeme;0OrfbS9Z^n<@9 z?ELl;epncOn7u_$2s=OU3;FQw{(a$(0c3Fhr7-0U1AaY)-xPLvaEDxe^oASZA@qbD z@k5k5i1GuW7l=BJ4Cs+MNZEkkMOvK~@!%I;JBn}{BqEN%BJ9xx_V~pfo`k0iz;CDs z-k%UDDbchj_7x)hQCA7yUqtxf`QIJ%i#u%sX<#J-e|}7Bq@Ib3@jC9*Rnk}~LKez8 z^7+&rWfS)yB6L9B6K-b_X&5LXKFTz|qebu;BSJ2we9>>Yh;$4Sk*)zE!c#U#*9Z}E zQkMu%9p-nu2>+gclx6%;MhQ<@l4<6T?-$r=a@luo+h^V`q_ejo?eiUC{=a9=o|8Mi ztbPA;yTkcuwm%(KumvSrgZj?$)|&p`Sa8Y#wJ+TL{Ld~rs&T=OMz2+FacL0em+98f z1z4u;4_z%@@xHba`{5HZ$3-ur{`~H5jp1XJ@R-VkVQgY*QVdasGv)9~Q%r zj+7VUfopOvLwwtOe9b|&yo``26@+J`MUKSdu&%{U6B%F5;Fl7hgX}oNG!t{@dy2xw z&c~zVyf@{AC9&(fJ+e}pRgTdVyN4J(6UOFjvQro~!Qpc_dtoIYJAAe+^_%#q8`RSD z=7;Q1)<)P>7alVE(unNvg>|i%zplxH?%2(RHj$_6p?q6IT-LHBA%?j9$o3PSS4N{* zbvfzB+gcmz+Zv(eVOP@-wq&%LS#gGSW8=6N<7hK{)bZ>XWB0ffZ=q_N#cmPZ{f-%v4BDw;&(w#oi0E=)Dnt*8kPCP4QzG~f z-vH6i^1u3t#(Io9yqh&hc3TVkSPnc~n6Z(5qA}q#JI4FiTe z|InMFkMv0yr5w=3ML+1Abdq<3$1idrEAf+uu|gKl}hJRuWtBL}h(p0q*mBtG0o12W^6GEaEY zNc`}`4}Rf6obVYgg2zY^_5($PLr2I*9%4`4z^7b9I;j)HkDig0Iv{g0e|%ox^!;?;A(bv;`8~XFRz5CRCYtDG#j>i8w zzh&#={`B{4XRVkn1^Mfg#VG$kYTkx;2eDNcBDIUcDLlvQDVtA$sQJt{E55)pQ@uP_0PO}20x_DTM3Dp1|7%#^;?Loc;)dshTV7gX+PZRH^1A;?$zFyHPU!=7_Tn=Z(1c~y^Ph^c(pTr zDqJP|?^*YZS4eG~#JUW(=bTSbt3vJxDOSbD)JWvZ;g>Mrke)!>jk7)BerVsas2zU685j`b>AO6RRUJ&7q883QCg!~xr z>mu}t0ly&%@ms?5pD?%+k?SAK_H^gZ%aX60kbVq!J7IK-0q>B)AJ6;OPvpLPfG5e0 zubz+|+$W1h>4AP9n7rnSMAzRQ!Uv@Ap~5Z??nelFet}tMC4Ksd*1GsUn)}~Vc8$W6 zQ4IKWVNX9eC+y{AZ{hQVJwNCyTq^A8rz~hw-znO8LbQ{_PZgN7&PcJLLL6 z4%`S2p?BmWK%Co(a33imZKFkm zr%obIe-V7C6WCK0@kbj4pMfIcnUMdbox^{*2>+EL^g|nm{m1jayXzPJBSgqGPJ}K8 zh~P^ZB)!8$xKoGWH%5dzbqd{5wsEHn6W;TcI*I?iM7UEY2}jvIyMJzBS^L4~G{SD`D*Z*Vo)S0tR_*w0?3%7gyH~nwD?#+99Em0b3^q#cS zvGksp(~NCwjvqVTj9GKMv0oq3c(0e)La1;y(pFiB)ozL8Yp=FK5YDT2ea1ZAO-1>` zP#(xD4A0aV40c{#91qh2`AMGRPPyY55w7>iJHst8t zYh}sid+JY*`Jd6iWm9t}=@VODIIbHs68Yu^9m%P4>%3nMI-_fEC9c`98-H%-b%j`#?ji17-S7XA2J_}`Zg6(AT4fpggOu%! z4VRQS49#Q=i{D+*(#D1>9_z;HER4CUVT;G!)f(VA7RKJyu*GAK7XstfkQ_)ab7#fg z)v(FfSBpFI(eaFPT+S^$ehUC)kqMBj)@)auJ4(-3ubzG2pjE#E*aQ-$e{^ zFp->cKo$)6W5NtVFkm)5Gsq!4c$OX*{9qUiEfz+84ER&R{NkVAEA`+VLIx?<3Gbp` z(nCCame+`l92`Gvn9 z3A;YPe-=g`7%)V>Nz6#Ea*hUm=#>1UQ;HtY0r?JZ27h#->AW)7q8vbUUhzXdlSlZ4 z2OVPU;6q0jdGL$9cZT7Gf86*bkMK*LV~0+`Q2+rs9m>J?Q>Yg-pK)K#}MwKgqj ztE^qqR@>OBTZmgLtD72^)Gb}vVi&6|(I75%TsXdRT;;fh^>vFEHtM>`wyMUOs+OAZ zm17sq*}y8e=ypbe730Cc(N{MnSHAF@x34?7we_-XhVORo=%Hs_T6Y4oPP`}>0rE`) zKEe|3YbowxO*SX{X;^rvuZfyFHmBNtk=BT#zlgH=f3Q&LxWgA-c06pKC1tE!xbKeQ z_7`~J7}hjm`-R%_8*rUt@leUe(>CIIsB~(W%Py85VLGxFDdUq?Hs`%qdC3#s=VEKG z*?P=fl{XnGEpOQQ@#fa6xN1;T-KkO-s`3C4Rhg;>9wqW-mg+f6MAf620iPtIDr4Zg zT13-<0iP|R>SDmxir`0h@ckkmXA|xT5mg?8{mUYn5e)b>kvHSu-->*GfhOc_k;@C_ zHG)43*ynW}V@EoX2R<~L$U(D7`p^UVp!uZfqj^I2GKRz!o@wW2ewcp(5kGSs?8`Ot+T^EU!?f59>z;k`(JRJ%Z`@IzAM}geHl5q& zsk$pr7mZg~q{%J}zo-?%GueT`4)P*%?eJWcF3Y;VZ#Pgv_GMYq>X$a@8uw)l@fUn< z{^8&Ip0~@SndcvL!L04hdHaj+?EPxVBPyWb_oTyJh;|mZ^DiaaL_+d=%6`2Q`z@_q zq&?&<67H+CeUn`e-?gy3o0jTbXFK?KYjr)|!mx#LhL>)It$1k9WP^WU+uohUzJSeb zGxjAN|GpwS&P_9XAshEXsj^d4%y(fL7&zMQbtXTOD4y%BR{ZQE=Uu|rgE+xjuP!{h z+?(~TWnPyznddhCkr#ehsWE$Ij&0AZt=3aMvM&JhtH=D;zP;_p!iR&hl0GRrf4kg!$t3i==WkqhAj_{nkyM7|fJ_^Fae}d>3VLFPKNura4 zJwL$9^H@L88Z-OZamVZ-;?tC*2LomwMd*H+FnxFZMD920f$;!%PZ9edNDFu`(F1yL zetQdlOV~T3;HQPX?Cc}_sxbP-fd4A&`3HVinCTJ>cuOVR(+l2S*vC8ILBe5p-w!XR zC_MY&$uA84nYQw2C2+Ga%g@TUF{hIFGF_(SlZtP&PCp7Be0LI>!X@h4Mp#DyM_9iEf{c#${wrLDoO zTtwUhMdS-@24mTwBK(dM5th0~c*-8KpdA(*D=oma%gxusk_A^ApH$_A^ zbdLKl5%%N-{0HPQWgWSPi_q;z5&njV&?{{M{>O{Z>;59#sr$q~Esv=?*i#4ir7X*| z@yF){9$a+T!}lG1#mn$1>-|K@mY>^f)h0WZ-mk|V)1!fZH4Xf9S#D|H_Pule(H%aL za7;se<&n|nkB;8(5xr;^#-1-#RNOq{SD!lkm!EGuV#E!Dp51c6-9JzbWSD53L_XNd zu%9Uf``UWE-Pxyjv)pVo(l&Q-yqRGjQ{Z$t8CbF#gX`98N*5RQK-eIRVH#aqhWvEM z89*|mx4jX*nLfQgA~|F*-)#5d5;>a?hzGw+zl0Oo;ku=}*_{`3l;cYReAAdsl*jrg zDOq*a@wp|sM&X?9F!^>sOVw&V<(P3d{k-Pp6TaK}=BwL}8CF?w@Wt0YbKUQ&XRC5q z9@-HK2JLo1FgJzx^MGn@`-#dv{@46vE7?)_orhMZ>Eb^ zqiEmJSq=^%$~qh{(f&>BZ5b#DJ%YDAE`()sr402E0fVhQ|*7#D^>tH>wSBB8L|( z!qB_IKhMZaZxtEO9h|Gt(!mAY;S$m8Z=7VbWp6)s;i4P1AHLr+S6(z|%Z0}sbHg3) zz1&w?=-S&W-2F#eMyqG-SJt~P^x+ewtt!TZVZTc{OxL-)PbOp=R8=Udh5X`b(y_1f zRT4IVM7z#Z4}7`mz9SyA?A8u54eep5P@xVAm#4F~SjQ7oOek~Bi(mAbUdmk|?zTVD zD{Y|;KFIcLDg=g#>+cet83JOk8z%B$J9xUtrzyZki>QE9F!1s`)=yONPS-Cyai=1# z6Zy0U74CB)hEf>t*F+va_(vid4Gj2qA}S>Y{8s+gF%fwKfIGxHkNBzZGyup!1Hik3 zijI7QVHgQ-hKe)g)X?12s86BJ zX{xD>Z;D#<^dqNUy3;E!^?UEK^Y5;>;o<*k+VQWg5}*4@lATZrv~P@~fOFGtyp`Bz ziM`7j`lbVDT~pgpVT}iOveNmX)5O~@?lOg^47jJ)&r(uB>>NVJ{L*hKs#3fICVWGY zaTqd;jKlCuMWBFS$NT}Aj-gNt5#a{|X1)Q8fA9e!FVGZ}6GRjw47fprKMWY65P5hC zq`xJpNM4`_gFOY6!bUimmHhE}f#a8)_4sD9@7S+jpTDb8zFX4ggsq+_yRPqEx@=;H ztwwG6xh=QY;`Ghm>vh@Y>-zq9lh5_OyWcnaeQdMFO<&t|30yYDs8v`r*pYF-k!F!scESa+T7CA z*0gx#l7$m0Clzi!8>ihBv&^Hqw~@z4gg0`#l(z5LxdQ8sE&1y;KUAYJEnpNi#Q!fhv-Hf(J6H0DZR#pN z(yhuRKRvxPcj|{tMeEwuw%UfuhT4XvmbD8fM(?xyX2EbXb$+*??GTKV_;_y9()R5- zue2R2QE^nSs9jUNtg3NoZDmVsOtskbEBf1*GJfnhY{?Mw@T*HS|`qGx>Y8^mmsa3HY$G+Lr zNdwB|Ed2P_0874kMrrPh4;yWDQ-e0;*3{QE);3qQa8hEtYDK|02V&R260f?SDf)&@ z$(6Y+OWSwtygGb@uaJgTX-tZuByF18rnG%v=lb{v#mRSsrdPF^hMvl8UfTZgf2xM^ z?Wy!LnC|Sp-9ecAsKCG0T-!qS_3u{Vxomb4Na8UF|F@CdMSFfn+Od*q6{C5d7kKC1 z6%Rdf>aL9PS*v2&ruep5Uo&Ky#xI8U8C9QeWsbBizjf9=dd-X^+vAwj;X_bN+t>tB zc+qQ}jvqB>y~|c8-8ah{&c$Y2G zM{JmvW>SbbR!`*`#Z)g>pTD)EM@uxvLP~so7A{%-mS$ZAVY)(ofQx77MlJDGsO1!so(y?RYMn7_Fogo?q|SSDYqW zh_XvaY;N5+`mDEoe2J9B^WkT7Ab^%CTh%N~yOafQ6C{aBfBHeP44afTnd8PcX;&Lr^_D8ONA~7?ICqWfDesEHT;%9U zx>P6m#~hLi&&7P%-WrzDlRn}W)$Nn1F%&K|P+rqD#C4GLSJ>hu<0$4kZo8-n$uMZ1 zoi|C_bbWStyzMXKlPuNvx3@!>`y9e$zY2dTA@;SInta@Lpu%cv@=a;7v06#ZuzO=D zDd6xO9{Z!l;pV%UXtQm9(aHi{^C>}l7uaDYN}9btjbCA!LmT9!WZ7H6%X7A5EEu_7 zvfAjd?_qI=Hpp0?*HzNKF{(5EHgwx+LyN_h4#g2P|_zmy{xa+lqqX=Ell!A z`-v}q&C*J7-{iuQ3@NB5^y(-hg&d2&?LsNDd}Z}!v-z{g$t^8$`me}3j+F5lWsg!By&F4+27yd>F zW4Cf=mp>P4L%eLYM6GC69(5Fh?;kCc*7{a)X=7=hMSkvD?}%eZZAa|pyJ!pJjr|mB zP3#JcxaVbM(B3vShRo8X^_6(fX1g*ntk;`~GEyj&wXnQ}sWaK_SfQV;7I3%ChI%WhLPJ@HOA&=Y_@`#q~fhydRJUm`aP6zYAQWQD-+B{g%a|9w~tmAtFP7r zDAWO^-QWAk_uIz!MJJuT^NYts`m9Am!~U-5IR4^q(l8$PwJ|C4Fv+n?Qrof4-1mn` zLwrGeVVaqXp=@%RqHFIYm#C1J#bf0p%at-xXrDdrl|7CRwUiZ(Pi`@X;Uk&i{r;*Tcs zrq4=)OK0zN{#yUe?P-DHH#K#U8fmVMinTTFPMVo}B}K`Q@qA?L!sjt)XYG^+GcId2 ze()0Hh?*DoGSDm6Ib@BjlC~`q*ne1UBwxd=$Hqx6DV!Hd!SCU6_WPE53X_pPEieVmH&A@ebc(X&{SQ1E$*L@3Yw<1 z;G!7bYj$C{<+!~O(YhG(|Dvi%i1h<(=> zw&o5HvAx!}>iY3oSw(L9>(|5McaDgC+7Nr$j}Q?DTY*Q3juWwWn{Bq7ZK@Fwj%~S9 zMC(Mjvt5@Xy%&p+hn2v+L|5lA?$bm!i@uu2`iZs*e?5qV=D;g9?$i`EIlOFt@eB_*HE``4rDhJ9{=@E9<+ zZ{i;V{(>;uo8brkYTjKxs^2;`uLt78tQPTk3ARaNz}(i!{(cPj4Po?y0lz2g=Lf)B zDlL}BL-K13M)_y->&Onzb3ifV+(FAR8XK0I-NFUtGZ zPjtn{)q3#seNuL}3X`80@Poo$KEdD0W88D1=Y_p~fL{{kJO%j$ep}e}u}-*;1abf1 zt%O~l;0j^SU+`FA*VnniT*Ki0!E=PkU-SV!O4#*%p71hZ(t|sAjj)&R^M(0LHU4qG zK*Y5Qlt;{kqMP&n9p5EPdBH#Kj|d|#_#)A_g)8){pQx_BsR!hxJYR;r9^fyvlzc|i zU)bgOtZ=z7bsKYyXsB?1{lXu-xA2bo#at^oQkZih#0RbycKu#2yjs}H2lz~3FYn-s z^Zwy~qv+}&{O5&l687=|zDL;02lz2zmk<1sFy)v0|AOd`f&VWF_mTtoMcLgjFR<|U zcU?XEi?5%9oeZ+zx1aoa+i%*j z5ca&eL%2EbUymhsiB1#tx&*#NnD__}zCqZ_+CA6_d)|Pb7A9|qAN-oImz8^k-x4N% z-0u_h?Q8EC@cp8J!qg?q1ET$f;ZOYFqlC-#i{aeTD&Yb8B|P{_Ve$s^b~-T&;g6}HlGnI{hY5dNznE`|rU`r71wLBX;|DKI z`Tvx#>l61&g*`s-=Y_p30e@B4>mv9eVb|BUgntzH2me~w`GemP_PPk(d{aA*tjCha zMMH$W?1Lu>BR}Z{&lH9q_zBU`LHH+yTZCOc@EO8h7oQSdFYNrmR|$K5fo~V~@&kS{ zkM+nV@{(7Cy}W_{mU7>2GYjwjM+@U0dGUXMuB|mT|V$yVb5Rir78Sn zVV58GhlNA_F9?VHe<4izF!=vR%KyjuCBs(;yZ-P$TA1=hdcZS;IlBjbRk!eRPe6%OV5lW-V+KM9Mx=o5ZB z2&jlf=6U_yO;}ZE10F2w^&9s|!dnLJ(^GhE%Ksu^i4YmWFBkUofY%6n{(;x0+&?QE z#&?sjic};&{_hZW{e4^b5nTP-47tq2~YMflrOg#BC*{^yC{yGTTuPZFUcbc4=li%9oA zBJ_8(2%Yf^x$ck!f3!W=jTd1zRRn+DRmA(42zQ?0GfV`Zi6Zo~T!fCV5n)eRz&|{| zq=Dy=BKYquLQe;Yi2n!?e7`Ls++Y#z6Y}`@{O=U~!tXv2Jkc5YATQxVnL}?QM8s1m zg3nkHd?$-Y!&xHYJ6nYP=SBFtU4%Xdi3op)2!2n9h;LsJdOl5roJZ;FWTK@of?Q}EeCg#9!T^0$i!f1wC}!$sK762YfRM7Wbh_*)|){4M$4qx6ga zfud5;5D|Q?5aI6|BIG8o(9=*6a_%RB-*F<+@pTdY4-gUG%PK6i-F!&mda|Dj*>{J01??iUfyN)hqgCPLmNBHZgm z=&f0V`$Z!BpDu#WCq<;=-$aC4CnDcgi;(Af5#i1kA@5g2pAbDK!u>oE;Xf_H-z6gS zd#Q+YUMC`+%S6~;B_f`SMac0P5$;!tNaq(s*k3Dx-;*NpdA*2y{hSCsH;T~vvm*H2 zEkf=`L_OyJrUurMY(GbE$C-1^&uua8H401b(u$Hzp3|Qm)1!eN4fJRr)WA8za&=|x z!#_Q_Tikrp*xF>*gG3jvZT7&jvTg6$scP3hJU{G-QGG6WvF!Fg(4%8jj8!Vm8nJSn zM4erS6Nb$4n_L-7b0<#LER*)OlPk-P-7BmwCf#hurLBOomdk2>m>W1g6JH50CJ??9LUrfB1e@L=OoA zrUwPaKbW2^;W6~&ZWqy$!hr7*h3?ovgs10<9Qf~(CuBn>*b$DnNH=yo)4PLkBYxaS z2Rw1-nXu>#Kcoqs_`P^cZdqCT-0ODhw61o1mOk@*c;ee>8+kN5`LQ&ewv4Lp_ydoB z=$g^*|LD?RJ-quXSIj=Vec0eBlcg{FGKCd*ws)n!krscsf+cOLN{a?w_>Zq9wav12 zJi|7K)o2j3Qry@yM3rKhon>>XyZN>)Gq!=0rS#$wq&KW3<0&4FCW-AHYzN4a*Qy_;-a7K@n&`++QWqWjjLR3dv4tBx?PzRR zW5Va+Igw0vR!(${Pg*No3l-Lwj=#SLf3_g9HOMwAvsEU(!&L2KhAGe6@k*g-#qi8z z1|ct=$JLMFZzFsG_6zMuJ&{iomm%TKG0q1I?CT38`4Zf#{>`W^bYK*a!joR!G1tU?en;}>2=(AsQ&w)JV z0pf2~gwOGD^1`d_`REO)@Z)!s3Ap=|W^(eCk#TtJ2&sK8r$Nun;)UL=+@m$@(&fsJ zcM!UmAJXlYXSkojgBtF_;VSaZ%K`HfTt8rPe9&;DHeFUdMsfl9IjW2PNMktqMUTvP zg@;;f7R(NjkmnpO8kuk5>Hqr}jc3LVj8m{*3v&hGjjHTK|E(`bq5x>OG?=2$d&)DbdB6#7>80QfY;~flR zvZq8IANYGB(uV(mqL)O`_(#8_^_L>jgBdLPv&hHeV7`w@d>Am_r+0b5I}4L;40vqb z9esfJ7G{hG9x9q8Onmx@HpVQ_gYzFDyJLmXD+bK>FBxNEzzxET^Dy96VV4KY_b?e( zV!&q$`*<46K@QT70e@MzUxW;N68?zu?ir zq5Kns!}L!Prrcrh5A_o%nkb*;ydi%XYnO>AANV00xL++$pQ@r)+`IJ^ra1;Bpb}!$inCNF;MAe|%ox@hwk! zywA;hpNM;(zAuz)`r}QW*H4e>(Lj#|dNk0ZfgTO~OKKo@O0J=-eb3w>-C)Wf<6|n( zI{6Q;xnl8!``>@V2~XWVc>S+x#!P+udd>?a`uBD<0X-iKJr#OG7@oa%h#lna?fr7~ zW$iO_Cw7C>&#SFosn4{ot&ARO=e4!)El=MoaO{?wG~T>xuXj(He$cXaA6@jdCvQIV zQ2J7~Hp&>=#;@U+$F)I!%eBEXsmHiB=xgzOVR>#vS^KoBw(17jIH0a-X=77sTU~Xl zzGvE0UE3Ocp&%*`KbZ0R-!8mnyQ=&Dw(7Q)A1=DGw%1js@y+?H(Z7ub8BMcxZ{trN zU&l7_h}!wS(kKtHUq%rX1=8?$%oksa+P_c;x3)bW1q<7irv+cfmtF_=$z4f zeUaTbKF7!f7F?7YmJhquB5lhjb8UwNA5$h>%x_q^Wfl&b_=*(gn@n9YmUurvS|6c~ zNfG6Ynb}xtKF4A+L7rmfX(?-lO*+%j1RXERudznsEXGb4#$2@Dv^m%@Zlf&&^UL^- zu^yOl+!T?|H!%L2DmZUj}v_Klm(>%gLDbMv;$u z!FP$g&17u(fQU8|1AasljSKVmIsG!`MIOemuZfTs!`Sn$BIL$^HA~QBiLj>!{25`!(irfq!XZEAJ3@IM6J|~U zgMY~1G3b@|4*t^FY? z^Bu;|`rHp*nts$NKW@3YS51Rn*Q|xpJ7-)%-(Kq!2fasD^ofy?3af?e(5{YlQpY`ddckn9HBR$INLKga-O_RI6(6f~#G-Ii z6Rw%t$}}t6@QTM~9fz_tUi-UR;aVgsJ!I<#GscNmf2~K(c+AEZtdG*4XQYsJ^L1zV z#N*0X`$>B)sb;mfm^(<1+k{!;EjeB)CnOCmxa**j3?vNM#t3 zG_xZBAMtbSBVOC~5pA|VyC%`DJhc1|{l%AvhPFNuOqQF@eT1a|?ZtA3E^#?4<|E#1 z5p&4SKWtkyx?{u@a!dNo&dp+BlajY;B*$kkY~*T(ygX;Dc9TnmXF@`0yljT$Je+aj zgHy>p2WCSJBMc>lT1G9gixjB^ZPA$uv>9p_Z7@;~cQBYuQYT^R3y*7!$-jeqd;#Q{ z@dM)&#vF_@7$5k!h5kNc2QcG{K_bF1mSC&^PsT79#uj^u@XL4yytgPC59pUM#X%y* z4)|dVa=ggLW30K>i*VPlDq4d*L%+y}DHp95F+PERx#+6=GyVsPt`&KF$a<@YVF>XJ z7TqZ#otUAbheXaF{B#O`Uzl+b2KQfzd^`$%Pvq$bZz4g^7Y5AwKYBwx@BlraKg=-E zXknKRJVDsU$0LMU{|D z;rv)Ly3pj%l>hm{o*w+yq};KitV+xcaxrG6{17i?o%oQEa)lfGNCV|)i#%k=au{HAw%#eF4CWi1K%PKLdo$@_+P6}_$Ste?*r(?@|9{T@=ooV)ib zTO)h=6JehczZ^M6a(1n?pL49!B$-4L|)-YG* z$Dfr;mV~yz-)hB1{fhm@@i9Ygl3Lv-m2T(0IACtOnkiw~v3{Zp z=dRH&?-S&iB)V0^y9Gm^@d*+9;17OL1tXKW3I_TVeEt0kba?9V0)uGViXR=pwW!dLVA%J5;ofF#5%Pj_5!=c>IS6 zvriL@nJcOhCO-Uw*_TOt;KN0q%Dd|^x)AO>VdNz~@`iN@k8hsv4Z^(Jai1?@U1F0w zChxv3+*iN)i7wcCR1fGEe5~lXJSO~cBF@|Bfq#sh^JbPvOIbU4Fu!AnfI1 zxp1{G^&NRuh+2g`Kk9|K(3|p$0q277;B$nXe}nMl!e0Ixg+Cwo2Y*SJz9yzg^pLRY zAN(C*Pe1r2Vfw%r@SlXy2l9eTrEK(%X%=lI?DBwj7IyudEIdls`GY6s{p&HhXmFaa zkBe|WM%c>>xLO$fVZe35=nn&4n{q!Rh0hlD`i1|?gk8VjYlK}N;5&rF_#YJBLiVH| z_s4}j{Vl>T1pdJ<3+sPmz&{o6_`$yyh93s}H(}3z@cY8VPki9bXLhlz0G-3R{#BHW1+d*0{xndx?-^rU-rqi}268 z26>l?NJpax{{uwWPZ5#V15#i_N@j?0}{2uw=(fTF66(Y(L?`r%{5MjTs2z}Lx(DO+m z@N`jc(L_-n5q&1yj~5}&{vyI3AR=9dh~Rsq2!Bl?TC=u?9M5Oa* z5%%;g;9Dmm{(2GVp?=DIl0QB#@QX#yo_EP!Tb&R8KBdQ%Y}Tjj2m0wTJsRlIK#vCg z8#K_qHg|Ga`_X5P=mxuZXEZf5H#OEaw#{j(sjaU(psKBET4Q5VTUA?KQ)9d=UHRQF z%&MCEy_KK1^GEM*zhL%h(`(NfFkGte={uWnWO~MzD4BR;%A`vF!f%oL!XVpzm+1xJ z3!_Z1`t6ZzoNtFar?sZ62SQC}u|^KG(_&YasBM9e$<%agN!P;o>Iy=z{GXO8 zoZ>EYWvbS`^k^vzCq*eI7+&pkH!wU?RxsGn{lgz+15DSLvIVA#Fib>O1k5j8JTH5M zotDCf3)6MN;C_+_K7%$$Y`e&12cIu;`N3YUU0%vI{3+X{ zm2!?B!jMk7Pw<1V!!L3XC*-;!41RDU46=RY>F8m6IyREv&Cwys%MwU)rh~YpPmm##N48ILkchI6>rb!`X@>f4XR!onBkL zZ~ZMtK62!b|FiuMJG?RRc1cdtvNr!WYgU=LS#Ap8Z?=1SZ~tQTG1=!57k-}+59hvP zyVxH$4e)tSsu-2aE1>O{vAsG}PV>>M`E2$P#Jf>wO3mF?TC#nl@6?D-PuMK{V#OQB z&0ch7m1&gYT{E1FU@t>_(t#On-}|2BW~rpQ$8-IKYd`E;SSdcX>jE9{!O!#>K^kY} z3oioXU90f^l@-+>2s6&9LYwSx>9wtR9U*@5T;rqJzTSjgI-g?Kthi!V zdmXL_xVcSM`r~lkL}P>gvtzLvFvAs)xXC7G3CBx;{U5gOLTTpqiP#?v|5DjtM@-{aDU1-5aS%sNMtTtT%L4C{JGWu1(eS5_JcK`gug@lTyxt7mLkTjW-kn1h!D zR&PREKDKO~7vBpPYdXEwYW0nJ=BsZ0`O~cRDzi(jR$&*{u;r4_QkpJ*Nq@W=S#4wA z68g9GRnDhSQVPS`ZoVuR{B!1pSc{#EvGz0cm96JAFWMq>TO{CeV?j zbzm5hyg@drJ+t?$t;EB_-l6tUcHVN7E8bPKC=7Zi+i4r#vXnsfYuG-*Wcx#1Zi&h* zYst3f&YlWGrrTroFT^#V(0{R3I=dEcTx;p?VA@bi18>5@Hk5kDj$QO)?P_-Hh5o#b zGk{3*i1Q%J)pmAdyC4VqE0ZmFQo_Rc;++v4xn=FkDD~A7vv^=CJeCDl48;G6dH&X$$Tvk)-<$?^>s|%kCr40w& z)cCkgfU@!e`@#~L3|Hvhbxz4Tk{z3u|7_Q=)OJ1IFqD<4xE1z3^y+A$i(Kk48?S)_ z^Ff%b@QD_lnebr30y`!vz!=sPnXqv?FzbX&YB1Ts^8gVO9hh>_Xc4?HhU{yfHgtmvB}myb2W=S2NQxPyN#a`~9> zdP9T`kq2G8FS35GtxayOfVg8=6Xd>j(u)D_F6{aO4-O~TIq0NI@)?CAyP0{`H1guT2_)-MrudBE4@ z{p&HR3ttfS@__qYDfb72JwDtY5vG1(z|RVMeuIB3?D_-$QJDP0fcq%1VSL*PQ?D_& zj~4dw0-h#JdBlJZ5iX06VeF{?=!{rtc6ofSfHRj z?LJ4L_5J5fa1M~Vo)i-m_}^Vbx@lu@A0onifQb00 z>*%vw1Rg3P+%OUT28)n`HUs_A7Gl4r2>(+>*iRB+KT{<0DgOApz+0zHIOLc`cN|2z z`{=WoTfVu)ebLu5@$^qMS61X!mbFj0{S)0_G|ySr!&~Ya>e}j7)y6AbYYx2Z=qZ;x z^Ue<&Z@%_3{SW)uMU(d*vzbbE@+#r*FeXE14o}!Xn_(@3PM_>6?nal`E==i&1H*h< zm9zWs2)?0VEBR8MGvNbn2*${&XRJ$&RORv47m^IXiC-`j=jGv0} zm@;AFgq-8pAOiv$xE5k2>`e;OJHs4?X4!hfCj(R)Nc!bL*u)dT;lyKM`jXQrKA0#T z<1)p^Ma?#hOiu^4|XX@$0NqC4EpP!o0F_ z6b_3?mknUiLR<>t8eYr?WsY=IOWyRw-XGP4Pn5y%@;B;Qs84UZ(3&6iP3B+dLTIM_ znHG%w7nbMHmDBB$xFM4qK=<;oVK z=zpBB>koI13A=v4GlVPji=j(hBTW8b!1cnO9`M=}UMKAO!kuB6mml!;!o*K{=u+RD zch_UoMZQ?qg(`E$_)Moh>&rF2)Razh;IiG{HX)*Vfe}KcoA|?HsDh! zLLSNn;V6^slX7ik?PJ=z!-Y6URn@PooxidpuAk^NQSR6ZvapdDrfRp8P z2kDfv5{kxHDYedH*v$%c7Cslg*6n8Bm~Z^Vo&vf*zAhTO6mp?}V<@0hUJTFV1A51f zisku20j6QV4+c!d@cac+!T2Tr_@zRSj~Mcs`2i{j1`NS3%xClI-2uNKeDAVHOZx4sKRu>L13en((Lj#|{)IGf?tU_UKjw4qb*`0>YFGwYV0mVNxXC(Ez+^@O?WCZ4*} zo5~2AZ(x&2){K&k^x2w`{>*)G7hdl+Bj@v9zJV%>k9SB2Wg9J!q>ux%bUyRItWi9> z$4ro&BjECo;&OH5mfQr^kx$!tN!N*)PvR{eBeN=YDN1oaq&7}VN8Fg#@r!8+XWWW) z-xwQU=(aEp!0=3027?{l9`71~8B@^>#()`HI3Mr19B2Sdcln@AK~dXk}jS}4_!UdNB58TaYHZgB7V|{U(!HWctP$)Sa=ZU`l{Tj zvi9RIU)5>D^3iX%JaT1YTU|qKB?rRl>T6r()wZmv(?=aDkE&~3Syew{LnHFVM|b@4 z1MN>uj;Jnue#x?WX^}C7RYEF~O};a2YT_xNzU;k)$mKPEG!dVh_ zW?OT^4pN#O8f&}J3XY6)H^%?+h^sBZSkr0C4)C(Q_I3{wXJ>5T%hG}`zJ0;?n(1Jg zF8ksslKaURxNsMwoo}(db#Sr8I&y$}C~aRqd7q`nusQQ7ecSnG=TMTRtuPHf4J|y88zLXbBX4-o4?4yVVbD8q;0M3FY#?+D@r+C~^2AN!Poqs3c;W{h#076; zKu$1zi6j4lYS-h2d4bQY{pJf_+3fyJh__Ga(0ts~6GchwpiM ztPDAMw_s@J^%{x{&$Ra#>>%2Ee$UxDx3;W(|Mi_8lK$vB@dwYXJh-)~zN)RZW?oxU zOV!fa4c+!@&guW?q%m`@zhl?$uln`-XAS=QU9Y|Uyu|lT5Q(QV86Oj7q|TlS>zuOx zh7qTA0@(!+9;D>M_jZN5?GvGkYCD`5v2yGI^>P&}oA236z*wHW9dr~s^3joNq0Aj~ z^AvT>S2Eol$>H638ydtz4LZYgT+v1Rse!Q2DFZq%-o>QoQCu-Rd)E&;@4nzhH^sY3 zjtA(0u{;KMwmNzd2Tv8zjlqEDis(90w82Y7bZ0Phe@+p3*A#r2$j9N}n?-b;FktpL zP<=39h%S=zrwd2dkaR&*D<4CX7P@Qj^KKPsrn`k~_;r4y2|wuOf{NUlvi7~N+@TvZ zNNjvOsI9Gec3o>*ZDVcAh6?%a-+uMer=ED^?AxE6xqrVSX1(%>#r-PplvcXFJuyD# zLzQB5lit+T@#aBm?`QxRS7vXUW0d5liHIe+Q7(yWJZ&Rmwlw-iIGO}16EQJvEoN^w z5ZHJZi8|+Gqi1iqi}5XNCW`sA?Ta)MG=_!xEEdj3r`A|@&~|0(Mb6wvZQWoQZZdViZ$o)OM#}^)`knewL%_IHvFWmZR87^I`qlxfo*?f z{==p^!wqrqCbQ1cQ0U$oY&WwituhBadhjUo*OhG!ZS8X)Y3ifDwuG%%AyK7M5k zNh3+aDe1m8p~P{;V|HnMKqc;Sm5*Xzxs(9+iUg9co9S6`|l!ew86Zn35Nmy zT;z=|_-&EP2i{ukNEm*kFzLhK&iR`VPfOw1!ZflN{GT99TJ;m*ll0(?I_YA(PQ!}< zHwn9L!F>NA^nbdr&v)Q{fiMlbexmT)D~$dzqzghnxHBfFu}9y?gnZVT$WFvlb;Jk>B{DBXCaVHNU;vg)%35zWFMHXJb5dPqS8)5N_4v8BXoHudi z^Xg1JZkQKX_iUf#14a($1+U({?k(A5ss8kse-RC=ADugmsr>HnWoDns*A#wTRejwl z(Oqtp2R5}dRJFC$w#26|CO-K7fnVREWcxin{>RZfF06j*vWt#-<4D!9@S241Ioy}c zOV_5L+1^v=QfOn-y!4TIp;)tTpXM#}YcDUGsJEC3{j_Gpnx4Eb4CQAn=#W_KK6%ZJ zb-w!?JGwi(d|B48RlY*ILOJQ`m~UQpwr4)x?ciaI( zP9zR}B)bmj>G0xG7IX1)FSr*^WpN2QPir_f@|?0!o8>{g$Dbw{L$geiiSg#0CLKGP zVqOgxnthsKA3K2uh-ktwG}(KIcxCXK0UsjbRe+%>pP&E59b7BIKZf7cBKHr@rSN)T zUI&E7{W=k^8w~dMh@2nz2@z=`J>cg=#7lV6_7jn(opih|qFaIi|49_O|3ld0$DL_= z?=~O@pD~6%2E4B@@ngUgy#Sgk54*cRyT=2q=M2W&;Ph7+cfgz6z{-l*S;N`FAOSaFQTGl?{`o7&{jCf@2 z$t!DHgD*j@Y&(1U-(H&Y{``ARyYnX}{^}2hwvF9y7iqYo@nN#UyHA>hWJ44mn(>~# zPmTDm^|h1ZnnJg5G{cb}Ze1#NEXrK6`4T2}3Au6`1q}*~scpO9uu<4V+5sUSOZjh{ zLK`{xXov=~e!~dVZE5!HuDaxi#I2cpPmSB=w91i{FVB-bKcmH;p|n7t?d$C@brQ=SR`9QfNoOY(kLo+Szp3 z2OW2YccZaYhm?1ej$(Nn=3Libq3Ka=q25e4h4yqzkdu4zvhqK8dw@lFkxuKX>4i8N9HkpXvoKiXi)J(Bg?sO8gVc$mf0d+2AJJM zb4A3*ivqkbkM&bhE~*p34^u8$Eu!(ql#AAj;EgF4T_mFM$CQh16yd*@s9bcfh%|yL zM9+wj6GK{mF7o)mZ-|f||KRsUgvSgNZ6^nRL4pSf^P<9lS?8vcfdL;ROnUp|G2h?u z@Iz$BxY=L$;58}t^MnbD!Tr<11yd^*U z#Z6iXgHFgd(n2`=@Qf@x`*@u>5XuW_!XJ49W)29RoFsu?g^13@AQ61f8F64o`U#7? zlpXBR0eot;Vr^obYphp8e8tBnLj|O@)(4&DK4fJSWg9dV^=RR51J~DS=cbM8* z*`QU3>UhmzMZaGzo8Pq0t8eyyan-kOT)fZAJDzeD-R1ZaVWuaNw~sJvz%V>uD1qUb zAp!>#De`eX_(BomT=;>n6S+HM z5i^lj1srX4Jd7&*&T9u!`nT2sGZl=lHYb-^1IyV()Q!Km5ejO9!T;s&XVuv zMwYf8-F?LkxAd31mm5;rKBxN%JEOIkVp{U;Ze9ka)h}&Q+quj>Jy`N{D*c|_ORXC| zj9Bt!u77F!@a`a;@2}#8vq`sUid?GXt}lw=54ue;%$70L6us8X#Z7LcEBSlw6Q%7_ zy2Go|wL811s>b?5TjvIrwjbP`WIMP~UA3m>4Yv!ZeD0E)P};tas9&?^|6RLY1d&2DbudH8w!E=x7 zGiB#7m)%wUM7z=*ZdePi%(N*&HgK^wnIm1cMUF#Q*{3}T5nq8B^0EzcYoZCp@WRY2 z?!~X$IE^Rtha64r0l3O7vJ7RSOXIg9&g-7uNQM3qmZ@$8dk*s-~WUnbF*C}VSr zV(R`KH-Ku;RKye=pi?<5I<@0Nx;tz&7D!!KI_izaEK6 zbJeXQT8_K(v3~D-dF*L7+|&1}rO#Z~_ZFooYwo(^bE15)*>4uIeVfS(>e*vT6^O4e z^F54wUCw9KIn2R{PIi1QRb}xb5UXXwZd8hD^0Nh59|HJbp|a8(ADv)z0pk9oRa&iZ z>Fw02El0)flZ(0+uDGOE6?|W8*V5Wmon)nsu!Vc4Z8tA_c{!2*8v!3}P7OpuRS6`xn&DAp4F&Li*kI7>_Mjw0NytuC~kCNRwVY*zT2h4eJ_G)9si0&3fE)4i(Vfti2*++OnNckp9pUqA;Z5HW}O&=``?7=-eSOgl=#qnYvGXp_QJj&0RMa+ zk*+WXJV}`JN=*@-p2vdGM=<6JdwR#pZn-e!1OvWEnDUMRLzHLuv1eZ5M)JzrhAuey zP4^nTBP;SFll!H7LLU?1MtMR;h`7)fZgly{8;EDz@Jo7$n{rHC3gJiM+s`0Vks zzdh`@l9r>Vt{J%b?-sp2X7$7;j;-BY9Xs|&Guq~Js_YeJ#LpO*xm9LgYzCE)F{jnJ zkh6FQrt|qC8h^tOJ|oL~N#Q3X3TLgDEn?olXI@#hVDW$ve8;jC`Ya}sbK(LXQWnoN zxC`?aeg{FUmGCLniH8YOZMWl_F3@m1$Kvy4xOvEUFF6|GFoMl4`F?b+KIIPnaQ4jZ zuut2bB45mvGRFchX2V$^VtxqD*w~^Cd&Hfu%aPa${sPP2?kSMh-`cd}PnaV`&PXCX7G$;eMXTWr5G-B1TZe z3I43eN3x9GJ}>f-KKK!lrwjZ&k@ExpR8%3tfQguq5C*)Ju#ben{Zsf8!pMWc9m2n? zH;h~v6*6)q-RKTKgkgk+U((Ana*`HCYRJflkY`4pgaM;d+>jABMv>?Vox{gRg4p4X z9dR-GJZpM;FD<05JMy2od3a7;bxTug(~`DI?TVQ&KI^0IkMF+AdCzQi*(t5#_C8_W zUoLp%hBxl4td{(Rv!q_1XkTm@l{si;HVfxysVO!qOIzSA3A28-mSHyGr0PuD}}K3CXFE&dmXhyw$L z;7=(f9JPs3MO>6H!h(t4OAz*ilR1|^J}=O#qUO`jUt3)l@#*zyNuMk9r^ozn)WDgQ z?WJYy6=!vaZ@qFavhTb&>g>}N4w!J?CgW~daO1dl_I>JvV~1_Jr!v4N=vjW^1scD! zZF!||k;RXf#Xjjg@d{?|g+GVaPRr++83h=ZLA1z z#iaGwlK%aT!rCGI;WR&YFZOLGclY;?t)mv_WBoSXL-Csn9-Pj!YaHoabGsJnmh@v+ zWJ-m!^mSP=L-wri8NrbrEWPx&hlp&}7cG=BJ{QV*9rs_wzFYHgP?g9H`t!(2)xa0> z6z5nxOxQ2?_xdq6sKN7HO>$}S83VFKe7HUx!yUHg8wb(RmtR<`yX z?n=q>={sEPxARmN_9^^kJ?{mDo5>1eG~d=2S}7U%`kC#lNtb`q0wWE+*tJ5roTX(O zgHRGE7s)*s+5VHgFAEWV4l!9?UCZHGcQIMe`kJW!*C?6!vRh&LZ5&0NE$+w4Kiv4r zSa#_SVoUE|i_thtWTrnFp{9hRIgB<1$G*iMG;ZHCbkg zwQ*U#tOce%FowwTQCQ=$d|AGcmuW6^J|^n5jA4{VmjJ^vBRBfp*fDaYUk+wGKv#h7 z0*2A!J|Zx$eDG`$Jb2wRN<2wKKOcA292-T9-suvs#&?d0ktFUFqN_wcx*w?LyF@-N z06!{XO%nfuL_Zc04`ztyEfHM~x+36rMaYf+p`tD1;PMX_-sS(Z_a5+d6xaLrl`XkT z3K(oUvW*+q0%MHnU~FRy7+k3iMwYH+VKpSVQtvfAl+b$%HPnQXLMWkzP#j7i34{=O zXrU&A5Xk@e?(ET)yDBC>@cq26Mml%)**PxIz`;e(q(?pp|-B-~pz2K+-|wSJOy1hpirjOCWzY}J*j@eT5wy?<${#@9G zZs6V$#D-$vb%k+9zO6*VeXL7wQhOo`k!1H3bPMG|V7+!cM37fvg z>fVLIHgp7EA#C{t{+Y1F2fjzx^b39_=Kcp^lLz-Vg)RNy&xK26W57LB(9j14ytZ(E z4>>$kI4tkBG54v$rf>WoBy9N!hM1R!fiRXn64{;GE{wYiF+X~JIT_Yc|AOkYOkM5C; zI*8jS5pL97_=bt#!7ud&nUIxh{0$Ki&QKBYjS;~^8G&yr5$@;>c}XksmHGA{+1%e; zL>h*Rhl1{tg@|}4t1_qXW9tHce{%cFPkp}ElgQJ(pm(aI zu-}fd{{L$-|18e-?2#S0@||PWAcTH#Oo|bS278yV= zfpRaBvEdQ}1BO^tslz250}Ojcf#DFt7hdJeD`$euh}@2y#Y0{hz0@0;Fz!$3c*C(*hIei=h9MPGHilR6ucf(xW^^dx?ztB(%WKy$zl9Y#0f8>uFw6e+8 zIes2PaHW70TP}9iFS$vcnm*zwK_WgZO-iVdZqgndQ0Mw_gH)?A@u75_pDjF&?mJ)T zjyjQC=A-&@n}05!-6XQ(bmPapCW`IB&g;u2!M0`D))XL~x&=xPEkkG0!*tR<1RgCv z@lcsGg%=S_n%dSaRlC!X_T5z1QrEHm9KUUzcFa%Rqtw{KL&rXXu%o$c_rn^Ea=8A2 z2ZCtXJC2DBPL>|vbfvYeiGN)Ggzi2!M-5`LnJ{R3S&ZV7bsfh}+2h0MNfYdC?0cHaVraB{Y5~ ztnH+FM6c;Sq>!t1WMlCSIp|%&wI;U@A)W4ngH2wVxpoT_L8)W4pQR2`Q!g&}r~(UA z_IY`y7g|=z0k5hYLSqU_$s=fj7AX9f?>PpWBdtZ1oRsK=<6EpOd~ znzqyX2dx@?^`Kwuzr$B=4F95Pou{6AU_H;(1_NfD!SWK!{N1MJV9pm14h9Ta*aulRVB|BO|NNS_KE6}8e&9+x&4N9F<(^1H=X3)>w}jr=yWu%4b^_gcxog^J zN~{^TMxQ5+sd;qBoPBf8urYLZgIDr2si`F7Xe}d@_`M)BWM_ZGch_iyY#R#(s5kzI%DCswHwNQ zB^qK->lBQ{K7qIxx%lYa61=# zt;z-lHaLWf)VL=hYrWwM!wPDQokI*>OcCd%dq>x<_C!MpyLEhuvAvK@4$|AXkaFKO zoV++ethv18NqDjx)b#LOw_8YyMGNI}EV=*_4aEkN)S_UQKDYeZl&pO&%7-gMlqXk$ z+V|1^5W9W9Hqdk}Zg|bADz!Yr^#^lt)@$5bYGBC->%edc5VHEAJd=kq`O|QtbSY6ZoUuXK91e zN$s__ZdPS=hB;M@dPLGjub4ZRN=h|-Gkv5xU)9!FgqZB?3d;-DLnW0h`Ue+I?mKa8 zED@gd<%Yq?1#R++e(P1=IvN!-hCrw2ZoY`k4VGitN>Tg#E_U?jMlIGl#8G_lKVEBA zmp@!%qJG;CIqteT;l$Grjkj~H!#DAhETe1NgYX>Ymzog2@758lWFjm5sTZQE}U8$8vj)65kZ zcO`9QwZ|Qu(dE|8_)G^5+O1&Zjy~O6Rg&U{KRS}jZI_Iv?I#_W$1sCrJQCi#jcYK> zmz!IGt7$g46CU;CN(i5uw*|2W_bevn|KW9kv*$h3=bVjh+ePKGE*NVoTO7 zuP3E~*lf&WJ~}Sj#u?33yX$%&N@s9~`a=uM2kV_&!5EM23HQDkcMj4m|GH=A+`^_? zV9hNxLA{`_VIzvrDLLd|`1EMdOWSBVS^Lg!xD`p_qZTA@dxb~Dx$=fxgSju7Km(NT z&TzPme%GG|UwwAtH$XRTqzb27abPr<#2?g+_FYYmXl&FY z*AgcA4qTIcBORrHnoMbRTV=c#58Xv$a(U;{-;sNAY_7j%#On^7(E25X6y;m)^Dv&{ z*-;xs2ECX&sZXoxo=ymIC-^dY^y}_yY;&F&N!n}Q>?jR&*o{Tw>#-ekm{g>dbH7#I zxZl>1kk!dSDPhD)tIPHB2%pmlImC7|wVUH5tO1jMJQwR$5|aAdr0q)LWTcEf<7r}} z^l&f5xh`ngy_c-5cFY}|aGSG)&wJE3FHEaIez+}IH!|m5ZY$^Ry4H)9BFt-d$vMXt ztOMF=D)(`9aWZ2M+BCNUNhtKF*0$lJy>=o#(v0#)`vNB!wcm}E(1%-J4BAqs*I*ri zQbCv|kDE0n-wnpA!8p}%@|*}W(LiHWN;#X(obaclF)oYxH{C|>x|tNboWghVQzC<2 zg`7pl#u4&QCbL}@<2&- zs~v8Ygp{Bm(roLyaJ$hUrJEXqzLL`%@VQZ|l^@p%xRO)RpOH>jr_#pX)4`^FzR z6Cb%p)8I;NTI(mS6-?r1-WndyQP1f0u-)j|xtpGYx{fcq>r%{&Iai`UX4jXvXKWaS zBNc~0liOq@2y-R3SaGhPzPgl9Q(QY2#g-21EvenaAT3n9mEc1N25f!Ot>`JQ|Zcj}E z#F5LH)Xq{r={;R}MYHsIR)T3GTnod!XzQ3HGg7%;@olarchb=QyrR zNg&L4Xm*&dqxDY57t9Zlkg~f-I&h^fDeS8`rzo!K`3yBexw1bB5d8@O@f8#scAcR==D5yRIjr9&p6h zak_i-QS|JLXtq`SxJRn@xhqydXE*WicyEY>^^v;JI=WILFpf*vG zgVrfY0{ZN>?$a_-7SWj7jg60rnW3T?&Y!Y(m|Kp56-;_jMsG*YHcPfKJ>vk#frn+s)L1^&{F;(nTMNZg_OY9UCWy zS$T`=!OedNCuyW+J)G5}&bNj^f8^5OT28Ca$U$vzdFbl6jla+q_1w)iNQHa<0>5Yi zf3D3#7r}`#Tv+XJZZ3?~@j=?ikEqXZZ*DHcWFd#$b4w#WsH@CU&_L4sp1fpiv&f5? zu^+XT+D+=*0dhCWw|Ruq2eP7D`kCCAofgA9R^kZNz4szs7D!iko`as_`w{R&XQv&v zlFm;s4K$_ip zDtE#w&$%*1;~>xBu@r|x4ch6pV`lZ4Rtas9+OYp{9cnuSv>1O{z?GEfDpE9TD=}?{ zyHwJ+_0r@X*yensk}@0)$=o`+*YT;&`7_#Tk0;*ew9RX+cgGwyOCfcn#r3oCB0CHP?th_^wxzLyb}YpsGY1$p7dVRm9TNq5$tcRa>)eLuCSqt!a&Y;S%G53MBQ z%1l|hr0_-q~4N$l=euDN`sR_2`r! zxBACgO~>5yd2a2_JrwHRT4l4eaNC&_R`6t1_`OuQEg_|^#@jQ`T^$X(b-X$Xw>xh_ zIS4;)?DD{A-mRYIN*whaulHeB_ZkL90ruYM_Cq6f*1_F8-FmV1VsPzmc>YCgaAS~U z4e~4uGDe??p`6=Yt4~PdJ}&AciI&HJ+to}fsmWY!m(I0dyqd$sPx-VfPF;}~wl)^H zaK-oxZZ|G6n~|3r!MghIRzSk7rE!uLW-4wB>1ME;)naX$aN{fa@VRs`Tcgf}?>MgY`{cPRKT(vFCyv|orNM~SFmbu{Hm)46?YhNrkjf~Zt$x}1X_6G^#&%7} zr(ky?eBaHnXdj5%wYx4Zbl~>esP|z%7HTxNti?(i#{|Azen-c_Hu5#Q{q^&JD|fVH zZj^W@wL5jgH6_cPp?5u~xlk&i^F#~9jiV`XZtlwX&drV)Z@MQks&t2$b5g4sghPyB zKjcSJ%Mm>zWd11yE`My*6u)h^CN7k=XPy==txCX!j^Zs7y(T4?U3-FSQS?xM$mNYi~yfNy9UjBw2H32dn2R9KMs2*1(k` zTW57I9a%2Dp(IhR{9h|i7j+-jSRhfTgDAL!Q2dEjD< zL+y5BU$-7WSmc2#yN)+}CpRUIhn%DBvKk+hC*ri#F~{rrGdD60-=X|cGQz31b|rkz zX(XKX_WRQ4NH~gIyH9`2K2*}2G3j1Xi)GKS=C&QdljD39nO29gZQ)wJCArbcq&%*OQJr0udEIRL}mqoG6FvV+ z#QOm;$BFvOqooZzOql2CA@CN$$PPY1G+vnJ{87!Rq8Y--gF74OhX~ud1I`kz6z08x z$PYeNcs<#e^F(|ja}(J->kqz57`^qMgKi68uLVcsc$xmq+(4)E)? zhsOvLKjs?Iv>2`tws(W#eylM1LSFE>!b5$0gX~`l`|_V5*!q5f&3j#Z>#;}u<1^hl z6Mft);=PuZ)}IN#BW&+I1$Wa63(zgHf=h(SJL3MiXj5VH|106~!j@L>Y~jJO(H(e+ zFliyY2Suj|o9-SGzE0S}1K%f%ZX{L;{Gu@LTacA{MD(^UEUzCEE|6f9ZNh(C)JK^2 zd%*vMXaix&DtMJ>jE@Qb8PT4?)EnY>PPDJErT?$O2Md!H^8Qs(h0m|c)LWuzVf}mI zgBJ-<*0}eMs96`}9p(ek$->Bo0beL=bqRc%F!_OeAB!IIG4X#YdR3UZ3H}%NgvlSw zSE52WSbl&936pjVcr#&n@eFu`F!d1qfwvX5^nNY8voP=2z;qYWKEmV|VS=lKdA|j? zhj4?irMI{6@xqin4EPM6pY(w*3gN!O*9apI?#05l`~H!+RQMiY$`gim;#pzd!HEHX zENtZi+*g@vb!}bY;lk)&mnragVT*5o@MK|Yd)5;^P?)xi_`$V4Mn2x*dz>(3hxBhE ze7Z3CDKS!mgs%}sAGp(w{Zbfx;eVv?!@`7*py12p*ve^h5mH2u~3ns%s4GX00&#Bs_3dnDUR=Uib`QlNWrEu+`Tcg@5Yv zlV0$>!Y1Et!cPlZ`?9<6JHoWB7;sNj7Rw*-kQm-onDikZ?)wYt-%HOV;X?(izDyBb zDop**WooK^P7x+OQd?>-;q!#i4`#aX)jozF{8OJFebJBHD{T6oE&Ql3VZjf6Qke9D z=ji7ZVJlDj3x6Q2BzyAmt>({!t^Uw2^;6)uqrXFi`wQc)ORt~WLKuCK{wm#^Dopvn zeSv-s6t?nJEnMgONB+ZwPY|~HP$ztaaGCF)Z$;lPO#bRJ)u^AxeSX2z5yEc>Q$9#D z_}{|BhrCOLOI5j*B+vg*!UKh^{v0j5xiH~lz~hANoju@5zPm2Het17&>mQEO%^KlB zo^RDP;ZudJzJM{hQj0z20U0e z%)f)Mm1o=!6t?;ct`ps?ldRl;?`%7T!JKPZ379m|KOX3R`&tA0%x3FL;@-MDPsw1YwgG ze37uFAAGei^@}*cHws&QxLx>RVT%v^dtvME!0!oLdk_9f*xH{vguf?cm^|Q(g-O3I zQ{ZvJ=!^L86rLnt@%=)0w(l5Tm0bjgiZbjg|8P@74+f<-yv-I{gCjz!j>NJV=?@kF!e=F zDct`oOn8`wh5sf@e~&x3K#8^T{D|=S!ea3Zcx23dg0RJp`#!?dUtOla6(RRWg=>Y8 zADw}hgxnt&&cyI(!ut0N?w1MRAAN(b7gm;e@jWU0Ghs{LQ^F4l+js)}yfA&OE>o-Y z^P({6BRsy*@UF1s-!sBr3!6T`1C%+s<@pB>7ak&vc~*EYVfqUUI4x}Pfe#Pi=Y$)4 z4FB(iTZB#D;NyiYJn$95mR|6!!qz`OFMOx4)o1V%!lXx+Dex=8HvV}*_$y%>PySJO zfRtta!J~yO{ou*M=t`F<@DyQ__fNtH2wQmo&ljfr;Rn3PcL%>Dyu^1GOua08tg!w) z13o*3uNAiT2lv~B=|3>wyM;|2@Z-YNSIQgsufmqUuL^%AOna%z6!=SFt1qt!7mC^H z=j+02InQT`y>(sS?&C(6znhx=Yu)-G@nGH%@4DhuaGn8=5T@+v(sSQh*!sFRb#sca z{yhUe#OLP*I4w+Hh5=`VZR`v_S(vozGWC{zE)=%B<$EJP6}Gkqe7~^%Jp+DDfVxB8 zfL{smza#vCu$2vPp@g@#2wWme`gNHCuPtohzbiaUSjEjV;O&Gh@4&kWQ@1eS8NPqy z0jER$-xppgtbZ>)@M!|pR(>FSp|HvKci|riTiFEP;=AiI1^&6P)vXVO9~IWWXFd{s zNx<|AeoxrK|5*4RG5lX)(>LzLDu|Q^U8cZg!srM5iGH>bw)B50JXzSn2k$3rWfOd$ zu$A@Cgck}^meCiuL0BSq;r~!4C@C+z|Ydu;u3$ z!XF4*+X((z*v49{;ccYCgFG1U7-364c(O3z=`!`Dehv^;5T5yuaGkK}2YigMwN2pj zh4tUce~W;{hx>!VR^Gsm3x~u1tFY-4_m6}v{owxy+gJ)bK#^Pd25&BG^%1<4u)KKY zE8!`^R{p>dSXh4t^E6aKM))o0xA5H|gR9~MS`N=gd+iq8-3F8q$L&AkhSi^OdD z1+On`SDiW?1HhqGR7q<2ce73NK556Yme!H-hC)^(q z*1u=Ke-*IwgFhCw`~de-V#Dzb5H|hcUM3t4Z%1M37y80|58**Bx>OJ0YGJ9+GvJJ{ zg%3Vcn6VlLe6Fyy7vM{Ut^9!R5;lE-9~ZXtfL{`}_67X0u$6x>$~FChHx>|!CqH<5 zA0tms;W@&Ve(*eDiyzz~Y~>N05w`s4C47#s$pikeu*nO)TiEmoem>^@maz2?xW6xK z^%eZ7u(faCuZ69Ag4b4O5RQL@u*r}6&cet`{(<)sw)prS+8kjk-{7>cg$F(|#-9 z!lVyY@I+xNAN_=93S0REA0}+_f|m;G-!tIz1;YNX6;>19>VB`Vm0$Q@5LOnox_>Hc z<5%227ql*0WMVJlCi!uJXjKKTWHMA-EIJ>lnkcR8oPF9}E#aQR#t-fcB&UsUP6}!Xra?9pNo~ENAcgh~tD!-+V7|Ct=H9@IJy8Ke#%Ev%;#vp27V} zVbd@8HsP|6`|pG;y|}+EZ1oGw!T{@j7;txC(=YgY!d70v>kC_Z1KvV79RCi&;q*<2 z`QJ;}@(2I3WBAY*f3>jHFZhoV4u`)o=KpkID_`)R6?4Bt*y*b+kOfkT@}kl#$~dJ>xZ(*8|Gb<0p?rq6DPVM4BU|gLVx%hDuRCx5%NqC!8=Wa zoU=s8cYuiW94I2p?~9P*a1rt@5+UzNBILSRgf4$0LI)d39^%|qHtBp-HsPZy^oL*M zKt|-+%D>)0HsS9kB0UpD$g!`8@b(uG-wh(-nWb<^?|rgK2Wf(DrigG~5W)AUi17X+ zBF>EXvCkBFdFIQvmu&dhdqEF`jr-Ojx+4ilm0BSf^RM~jg2SP^AE zD?&dvijeO%5%D}AB7M(_i0cm`^zwHR@_#KtR|6yudfZPo`k5)4{J2my@(>nsOcoLT zF(U5YD#GnK5#d}Ve!{&`Hu?Hz*~tAj*~CvhLGFV@gm;LD^dBlB{gooZuNEOktq8d? zBEtQVi1hqegnoW5B0V39h-Z}IL7o$2Q~!4tAx9r!_*crNjQmnI^8Z0L{x%cgZ&wj= z>?4AoJzM0YKS7RpBI0{cL_0%T$j9wO@EBGUaMg$LhnWy3d6HuBAu4PUKn#M~aB|IuZ9j5fR@@K0oWh$T2~LT!Z}kx5AIheDED*tewup3ZuKT1TErRb_5puCE z58vJ*+;{TB*-@-WYXZ?NyLS~ltWvj{o=C?Y)O z_k{nn2z~StA9B_B{_1^yb9E1W%n^qFmm>V{CQQ6PmQ8)B5m9cA5|RGnMAU|`BhUG=N&h3V zHvO?)?r;D1kqdvCcD-d7^xy+N3KK0r3{vOdNA%S7;PqWi@AifqE$ST^x4lufuN z$(9%I{4D$Kc7~=G!OBCSCW6NdJ=}7TL55 zuZf7~pThc2eJF!<%YT5XES~lVSLWG{*7g4U((S7u^ifd7+FmnD@#Qm*({E)6m z*Ha?G{hsa<&)%{LcURfC&y$TlZui|;S0=pm{QLiqP5e`3liq2vk>h&beq7gt_l1ab zf1vxc4^PS_{J)Aw&%Z>3J6`vZV`tgq-|Hg!het%{rBL_L(^|5LXDiu+f1+&Ucv&{` zvfe?ut`J7QTgujd>h~i2KQBVwKZ)S`yBvw{RS|lcD~x>W%O?JpMBtA^q~kN+y+AhM zJtdp+%Q_8mJ}L~~Uu7fb?`5wi`#-XY=Umyyy{Yehh-~;PWh4JHvXQU9@BSy*=;c!1 zURyTtJnOsnl#Tva*Fc{)3nNdFZ}*VR{jt71PB#7i5wel%E7_!DjBMh+KsNIARUpW} zhcNQ7?vH-96DA#tWFyy2vZ)upkd54|XOSN}2ov7jvi0wsNkQ(*1kmRU*@XL?Y~o># zjXUcrgx{q5#CN4^;<>};e_b}=-Yc7M8hw12Z1OWLoAhR7la8OrMxF}UgwJ|3{tp(W zJ!+9ndvcC!{GTP8_}`UHIKP(dl^fakL%GQPqA=y_H?ooA2fjP&r`$hNnD|PBiJyH9 z(z#0aN!Metk?*In3GZ>)r1L%5#P^PD^vV7U?yN%*-kbjYPkj4**~s~+Y{L6OHtF!z zNo9X7EU&45$(A{bpY`@T{OHLm)|qz7UydGh$ZmH(O}vFYMy85?*YA*?3v|(Cx-`(G zfi4YnX`o93VGU%r&-N|KZknB+2Ol|}x?k&eso&`K*<)3o?D*>R!sj17;GUyrRloIi z1!GNna+fz-*LjF1blrQKc#4)MY=ie`(CcF8tzBp7uIW|55IrruDc9JH6zHWfj20m< z?t}vmnER(3k?m8IJ>aYj@<4eL8|oSx>eKZt(;BMMwdIqS=yLap=5*DB=H>O3t%_~f z?E6!m`19t?cRo3<^0~u`R&DjsufM;u(#AvB?gJ0@*fWox^AJA|jq^Y-54770q&mkP zeKb7q!>cjuaw;EqR}n*U3`67DBBo4KQgD@s zij83?+$>_KjsdfjMR@RoPZhxr<~~ao$VGhIze!~NX&~+tVPmi#5m}=FenP}l3_^1%ekI z8Zq>RPPxxDHenJEVPHevlvH-MG26Q+J7eW0dC=%hs;Q{1Z)k3*scbIaqoy{!f4Zr; zrlEdn{ep(p7Vn%9uN?dNllO1)%l>s2uiE0xg3Ipdw*N4tgBRN5e(KX+0+{;>1YYqF zuAAX9Y#j}Hqs(BqMwb}wQJyUi!DT*{)!NaZf65?v1rPk>(eb0Ry^6A9Puw;SbiQx8 zrTl>O{OL^%%a*q)dGhnGpO@Ng_^*4^o_OBP2R?pq&&!XxX}SdGtwJ=*?yVK>i%s_Z z1>OcRUyTe6`7(7rywfUrhXxP7yd%ZEQ#+git^u-l|K!GF?|KPmR6GW&)D(0o5r%8K z&pp->$Vf5-JXA!ckWo~k5h5}QLxn3BaUTO7Cn8J?cz02le^39uEYBSt3J>8^Aczb~@!hgSB=cG!%UvgJTN%0Z=e%EhI z-;4Wv(Pv)oM|+QuLzn5&K$ix(G|;7iE)8^Ppi2Yaz6LV=3$r5&@?caX=$9(Qd3*g;tjY{k7ouJX1B}->GrRvU7Vi1xUn{k)>5Bk z)+@}8&4;|4-BeNETv6Gg$)J~^Gc%hOW_Qg8l|>}mr=hZ<)>GY!nRN@Zqw_*_3!Bmv zRWQfbUDb?&z$ z-BerA*qE;JRQX4B=iVIO&I=s;+=kOGeClp*oyvVzfOm89K6lb_LN61iKj=Y6W- z^_K7(%~^j5WB1J!x4fV0mirFksPE`IlH>lJG{JZ8SkBLVmuqKy@x2ii0pX3VQU$9= zd|knP<01Gu0E>aad-0LSz8esBiN6CJ%sWka&-Oya$(w(3-{$Y`vAl0@u6I0q$HaXn z$nLv0v)UF0n=^qQ=f?YXlfMX;^nO++k@J}=g}Wb>BG_vSud?O70oUF?9uC#+g+t^G z&wO1K?UHKB8+UkDI@?ja6P~RE-Ym^KhS4SW?cLk<-eEBB$#q~C=NLdxJ?oFE?;uQy%n7}q9Gf$unoJnKjSm{eTCd5=W1^Qi`;hg$i)@@ z(vDltq~@{*O6ges?T^?M!!dp=tUcOB4cDxj+CA1Tabx{*W6>~?tz&Mg>#-u^AEN7> zL~QEdAKn=vHc?my9Vx02vAIEbn~PS6@DCm(S}9@^3ID9YUMxZe) zE|7u_50CyaGew+7BYo%x%!RFc zvq5L)2yp`QT#V@hypb^Ziwtu_qkaFxcaUfYVN379!ZU=4A9wJ@?xq)4+;}M2K=P&j(_mW z!juI}TJ)MQ`H2C4CQN={z`YcaZh7ee_Yt=ISSY-143`O;K5!o?Y~j}k?_i-Z>l+a@JA6LUXDn7kr=xL+V#P0vC?uKs_ zHhtoLf6V3+HF0@B24@k@M7T- z4>`P2c&!jVSJ=`E|JA~lUyFtB6SnpM{Ci=`e=zSS*1u=KZ^qm|5$+#yFH+{3{^2hX zHvNFt5hj00-x5)ok9Fxi(={k@mIz$?<*!g4E&3QNk0Z0et$8T z_ZM4!fiDy``N3Dk!n;0(Z}I(;9{7JA^1n>@*TPm_z>f)Ad%IltcOkq&_yr&9(tD=r z7yJ| z&&Xd@6EB^V9oh?t;gvIa_woZBtSds-)Hh_H+(8?QCxDOEyvJ%cT5oy^*L|D^Br14M@X&WWt{sAKHA1ERW;>7<55n-VN z!Wk|?)`Lap%XG<@gzL>k#J`gWJyeL0d9Voir;14T{v!ONd-O6vMEtvm@P|$br%Z$# z)MexvE#m%mBJS@kBAoq1=;3e?_Zvm%eG3u(wiglZ6cOo|AtK#7i->=S2)=R=>DW?4 zJoO^NJ=(X&$%cQd2>s0z;cqh$@g62Zo)!^!D-r44T10$|xk%?^5qyV;;G=CK+%Y2J znNxkui;!za5$^klh_^-rUxSGID@269gNX2V6QPIQMbwo^BKYTt;GgK@`LYW{ zdx?l|t_Xj7h|t@2IBA6Rf-?ontG0kU!%%VW8w@`pg#2K8TWTA+I zL`>QFa5$6sz%_o1$bC>Ud|r{0mn=rOPc=sub=qDw3YJEKkK53^W2l}qDHyJ)W*F|# z{Zaj?vfvGT%srYBnt$_4b2m(cO_PGXjR?OOnkTwL3m;4~M6-+mTk~g_?uupugL{>T z<_7~_B%*mFJ}}KG%@KxXH!HIEz-NjqJn(rUnkx(#B5j06x{#gtXv&BOUc%=dyzmen zx`1$l2U!Tm!sD7S;KdJmhL14ugRV^XD~Dx^i?Sn+-#QO!;qHqUEYLB=*7|qfkZu#V zxa76J{eGuQ9)9DAXE%On#LB63iIhh^6~?EY+=3a)NelGn76ENp&<@ADB~Csn@0NAj zs{=vVwVXp!XcNOVxj~L`&vH?hUJjJWHh<*8Fp=?tM~B?W5r{CYL|Ms)mvD%~_-?Pv z_AAQn`uc!8$f=o&>sz!JRUX|2@EXl8ufF`_)0=*I(&W;c?|AwArUwShS+o}4BjHO{ ze8G&b(7R_C-1qHs@37Y1{#WLlA6ET1^lt0be4{HU8o08m%K>`|K%L^RRgnoojvs69 zm^0ioQUIeN+t^Bm$w8dgGSs_k29q=D7cXcNm<%n6k)CcJ(ez8_vg<~}Rz z>nXQwQ##NbiT!#^o7aJ`HSWUepo?wI|!`S zqcNlpI@Ksow3ANKU^qlqUMUN%Tt~ku>O!`BO+LiUa07W3MDjQ{UK^HR(=akb;0wNB z(wB6Xuk5*{Xfiup8UFnBs`yS0cb|u!;5z9F% z5!GIure;y+SID*&p=}qJgT!k)3~nIBFKvdM)TV^Hk`=zk9!<2IBDwo!qDe(-M9FjM z%9V{ACKP+D2Yx~^*$Ib};oRj*unge>8IYV|C83A!9^sXJ+YiZ=DeZk{6AcBvXw^tJ z+{oZ7T(Pzk{d3Qi5x!vQ^cZe~;Bnt$#J}68s_^*ee1q>%b5(WJOu{n8>BwVgK!;{u8*aHstt(H2 zL~j(Hl<-|nBumO0$|pSmwcKfxypQLXYmr@B?@}JEL)>GU!Z$u?wXH>o_PWMpyY%EY zwV2uvlrCh6ww`f+lsi|e2#KC6@S#!HIU>gEt?L5IF3apuy7?ZrF~ILu^kS;df%@q( zT^i`pK$ix(H1Pic4P;JEXTR4YJ0W{!UQDsm3u@EeG2ZfN>6VJBik6Djg^>dn?EUh! zbDkLc?$Cd4{qFH!jeFrYzr5`~>x36Z+-R1*nsFpOFXIM!Qtk!gB-h_Z=dp|(SeCSJ z$kV^Z=ekKe;eI;KZ_Au*-S3RwFb}o&ww-W`yAYDoMy*CUj98dAyHQtE7mN(t zvXavo`s|1!Ea&QRC#8zfDxPVPTA07MNA;bAgy_B?AIw!)f_AfbVq$jV<`m2V-28)?M_PMQ zxU+Im?Qs!Sc)^|V8u2sNU7)-pXPoRwT0|;0PQ(}UmpBengQxx%eqL z%o3AkzDfSz{=b-2Q!axtNf}Q|hG3pc-nr658BLb2t(oN_g+*(dB)`Rw6r!z%gy&>Q zVb~g?@w?gfVo&S2nhuB7ajN25LeaH2SJQLXGMN9t89eKb*5Ye6xn;o3(3oi^=_Bkv znqRIB3C~Ug9avrETmyzp4>n6MTth6gbB_%tmhi!BjIdm9?rf50G z8jN9MiT!St>oMRe-!{yK5%Wiu`*B|>A|B%JFFMP|vb=r&D`Z>z>+1UFBKR=i$3<)t zV8Bm{*k~g>@T(%*ei*3hzxh~}7w(6$ZNrLq{v)#VfbD&Zy7c%5N^sJR!F_lPhhN@- zJFnMadjkW8*pSlgRz2d*HV5*u?SVevK`z|L7xD^yam{8IZrno_(uW`PPTFxtC)`6< zgk{?-qz#N8u91hZ@WXwJ16jDQA(iJwIUx*mD04nPc3xof$L{;pioRFR(ya^Js!ep= zf%PfZ$|t!7qcbbF(f+!9-_d6UzDWqtUavh#qnx?zO#6~rTjh3WSfRJI=5Ok6ky;x@ z4&T&2t+%Zf(yp~1j_G!FN~@eq#@VZ zG1E@UiS}K?@pqoHEh(0H`k_{ad(L<(yg>DmT(Dk*-3|H|SBt~@8?K#ld#ll%*8s8K zLwR;>D(ygYpElRs)jKz8cV|0VzLB4>?!HN!VgE@Q?I_H!|JC8`I4&#U9pxmkws^B+ z_e#fw%1O8H24-f(ek66%?Y(!t^`rl`J@xk6L0VVhbbWHzpX*f{{gM&%wr(YcQt9%Y z6*X36D2J@kB)LRWLQBnTkaYn|xl3cbXQ%D4^`0;XnquvX-{ro3DAUU%Q#@bk4Oq8v zt@nI!*=Yt=CupmqdEnxqmvQR_ahY;c8SuK8C?V8Q(@)$zstsnjtRHN8h+#VhseUsA`l=0xa6l+dl>`E$m z9`teUiC%IyJX2sLiQRw7khS>uj-Rq1S6o?6E;sGFC$(wB+g_NK-(fzt8baT2iNXQS9agR93KmWBC$cwOMjK2slB`@>^?se2cG z^H7uZVyz!Fg)@zvqMJnS4-lC}e%K}k)zmmFK*C+yySJgh7* zYqj1eh%N4t+bTADt&Y=FoI5N*+hK;eR!`2h^DHijm6~V?U|hl+l{!TYCV$ysp_ib2 ziLN&|cUCUw(dbjK>4jPGG5>A5C+V)EFvGf89o{58(n4`^nLZWSqkECPunmeSAC=$K;Ybz2{D)(JRGy;<-l~6O1t1ipknTv=k39?3UEKw#QG;Y<+8UyCKKN z7rCMGpaSE`@a}D#%f^4Xaaq}AKGwcej+5F^?ez<^)ix^2jgK1Pco`j#_t?2w4921+ zTXdxDLXO@`t~=ytl+Ug2RBEi76iPVd@s=P63#rj9s})Hrs^O43;tkh^Z|bkDT4ZTQ zhWN@)Jg&HVdvdkM+mS3me~tvqPRKbomI}+%9$#Csb=FVkWOU=$T$$Ycj>;Q7k86)f z9VZn!_7NW!h2zd0HMLzngB?elX}F*mAD(nROD!s!U_mglZ;<=zSVZQnJigy;H*Yb%!{ zSxdPiAMV6g``x@g+6TcG-Y1FU_PJe&rB>1MR(c~a>WH0H588IZ4fn-yoYXfvp6GJ` zXvnPsqfv6b$%{4IPegl2o2%MLnV8(JPq6+H=iwPO&Rm6iYx;QFGiE2j?vWdVGcO50 zAz-;=GUobC;y`ZFgIn&tfg58497!dz;D3Sd+pG^Cy*J*D}x=1#8dTBd40Y zUAEvfn!C?#quYIpx38uZ8|fLpjn@e?h$Wgo@VfaceHagi#!osj&*Joo8xMu&mClXehkZFMR$fd>yoES%!PC}TJi$4fFWTyq`{C+_h+D9*QW z&TUiCXc6b%IAb?lG+D&?I?m2*C7L0EpL1{9iYi4L`Iz?u9V_CD9A-DsX(Gpanc z!pKYh@)DjpVa|8Lf2HU+Vak`H@yZ_WWW*i*t3@{ob0%0;>c^sobYbbcS@;#7l{|3xu@(0{3Z1O%Kd~Apxe4enC zcQEfHwETHW_#t77Z7k)z6(hGi7*xE1f$HL?n@xLLWa!@}A?@ge9m5;ZDHxwrSNzdOzqlGQ} z_k<@3Q=SPAJWW_C_3-<$X9*)8{yz{^`24y|eI!~WO!>utTVnWVVXI%bpC?RyATRi* z!lvI(gzt&r-^B2a;2iFTze!%|_trRx-J{LY$nD{Z^>x5~4kOzFPFz->s{7dwr@Nf?~ zT%g4D58-u$DWAj#{~%$~OL+eljTE;0{Ze?>kbm$@VM`Bqfw1Wxe1tIhO?cpAg(+{C z|A@{ICVmX~5@C}Me5)|&!9Vy3Vf}mNEB!t%VEP8XDQx-%|5w<;2ltb3rZ4aiVT1PMoA3{XNxv>r-Su;Wu*p*>e6KL+!5#dZu*p*-{Fbog75G!% zKm6ccax{G~uG~b}!UvBPwzdyELDyQ`qW1ct2qk36CELxV&N)b ztA8cJON326@TtPYhXG#{8~nfTV_3c?{8h+5xKzxRU*O@w zgJG5dPZhTM1)e2rxxXuH z^%?g9Dc8y;c!02#H}FVdYk$ELg{2bDfM*GZH;jn%`6Q;b1)#abC)eq*`-4(dy54c!ZRopY+4TViU@Rq_>Ucl30 z{tpng^x|G6tpC>VmI_$kiTk<2rVsG7!j>NJJ;J76@RPz;|G>`+hvVZO^+}fJk8&&) zZ!AeVH8t}1HO27aK^LT#Fp&eE4Mns$+#_zT(E;Tg*{F|{0rFvxi1bkAxkp<}f691@ za3yg7%fs3c<+s-oQx3-6^#>-Z`+FKKPHQ)2Qx)OLpDQX8Js=|e zmx=I?Y@~y@ksaBHk1&Y;KoRM^PK2KB5s^OH7W`}_BHq14gm;_>e16$gi;?{7)0%f4m5PQ$)nKP((bnBEmgeM7h{fgnnj-NdKWC+)oqX?>=V_m56j7Awoa1MBFFO(a!=Aa=#!V9P)zu zq!EAHi3sm-5&oBn(D&~|g!6k*k%%-9KWT#>-Qj;H5&rfP;jdmq_`8bWKT?D{Iwn2a zi;!oYi0~Ul@Sh?=&wmmT$3I2H@qH2HWU+`a&JhuRlZfz}MaZ#2MEoy`kQZIzPTe8h z4I=n5BK*H1Laqx$<_>AzA$x_&953_K=6U;hws|5qaX z?#9U}OS62bQi5%(YR?TNB+ z-&chD$s+W3g9v&4AR@dsMEKi5gd97I;6Go4KJONh54(%dSA~dhDn*1-BO<^4A|fAY zmkIB35&68EhH3?fyXYwq`S-L4f3J!tAHNn6-@_v0JzYe6SBTKle?;i{L=oZFiQqd=gxn8`;4hWj z!hb{r{!E0PJ`$m)Pek}<3<}?mMcjW@guH(i5#IeG;{Uk_{!c~7$y^0JpCN+( zR1xu{`$LV6)9J4DbpD4LDU)Sl@qi5i?TZ& ze{deCWM;a#VR4hxQGP&EO^f^7t@qNQX=hL9Tee`-nWNvFb=c^gPkj2AboU$SV0c6= z=}|5=*272r!!NK3AM=azHG5m~ZTSqV+0;oDrrE%7P1Azm-UcG$1DAqP89x}ZY@*2^Yw=Gv;WY`eX}#IKro zN}t}h+_CXl+Z1i~{sYaA-a6yK<@9lFzq2{4dQJdxss%M*Pz5T*aE%JV5IwPF59)(V zrKk;j-X__#^f8hf^5M;Y2iDb=A2_L@a&cX{zNPh@e*=2{V*i)U?|%8{gEt-a(4bv5 zym-b{pYk0)&L6opz}||Ke21rodD4of;NowraL*s*zMqNHLb!24g_BU6@!}oA?tc5O za0hWF@izP6M8oG)cGze19XF)Gp2f7cA8?w_eaDs(fjcL)-1A>N7Zg0x?w*h(MVvU} z)T%u#kn|+#H+#Ml*`x2V;EWIH=OmYF!Grf?*_qTDmF7C-jyqS!Gm7ph2D{&uKgWNB z{52>w#2kKNCCICIgJ;i9NBLbAGE%f8=9}kGXPrhn&ki?MC12Lhf@vniIKq>^v4Hf;qtxZ@Qz-5Y z2*Fiw;+%V~E(BNc7=yfb>2T+{oz&*LqjI)Pu>{{2h$44V)jc8JwoC8?xYZTjea*>V z8$Gx)Yy7%1Z0^ZxSBsYU_juyoy>Fa)6xEis$7)KyWi!qXpH7gL9>X=`ZR-@71JPO1 z>T`dH$U14}3*{m@XP9? z%sd*I2yZjd2_odd3>BRzqSMBJnIDrD!Utb1!aruX=w=b~77X}ak);p(8xiRtzAZ#A zh)g%5bp5)B9uEWlP=sDEVCF%{PyFES3W)S$&=u=*MY3@R_ZPMvb}Qlag)P1@!oz%b zU3zPkql9|`WN;rVY~h1`Q}!_6TZPdV2F&+{O+N6wG4}_BDR&s$ z|19jyZ+-l+u<36b-Q#=1CJ&giU6fx8c*7VTBW&dd_uYj}J}^Z13f4=PoLkEm{@`Vh z3J>{CTF5_Su)4=Jbp$>37f~M9@oBVd${S?|K6C{i<2}Nq4iY9|6CQ+qse8m(CIUma z*`RtOUE_~Bhdoq;T*F1gOOH5eX_E;OqT|_G|;7iE)8^Ppi2W?8tBr%|FH(LCE0;R*~ys& zd9haB`i+o;FL7Q`@M7tn173T++Z{)peer#(jym(&jjv+#%PJ4wEC@eI8(v#wM2cYq z%ZvcSH6v3D_aH{J*e4yC9Z;0r;`DsjJ=izhQa-(=zPfeUbYS&~4HNoq)9?0;-+uJ< z9bfPJ$lHJY+n*#fALdxDRw%kLRiLNsV=^>XguygP?n!^@3@yFyM+O@MEcIPY0dh4L|hAWBD%h+;o~tbUD%PQb2jZ7|Vvi(jgNe43kDCPZ+K#h8UYD zGU1{KgUdy>umK+vLMCGvCT@F+n6SYQo+Yw)m{?Vbm;mAqt`;%L#V~ zsh<5_OO-a1Zd`I_@p~ml6fYF)GF=+z(m46CpUGu|BW{DsMiloclNpS^ zsa1o^YU*3k)#;|PM$H~8nwFO>N-r;~Z)hp2UtC)|D#SauY`)Goj?AQb^c*;JXhCM8 zCxwpk9bT14mVpc=#VoqIpGDJX8REUUMt`tiunkpAobXpPH z7xfr8ZFoVdroJk@toevq%|7Q&ST;Ds;CUEa)=(e0J9vbb%Y#Qw@781B z7F!e?>kls%yC40MO}K7SVv|`3VIG4BH1gwFhin*F1tm- z3d@_T{iI^()LGe-=45Cah0@Qpky59(lwjut*57=m*I#-6u8+BSMDg*c`_9rYOaEE= zaq0V|ZFK2>m#!>5 zrgV8}i{|@>m!?Y(D?Oxi|I!(y`;<;8-Mw_@((OvemX?=}C>>n7QR#rv@0Io`EiC!E z@yWUM%^2$*PjaN**k^r{rfPKPkDff#izPtlGHBKrGYLDbZMYV16>;E z(m881LHI+>b%?%4$%EeXL(3CE(Xl$Ij zb@^81Tg`1sFPQ7!)lJ=-J8OA!OS-Pye=2ucLsh!A{DAa)fA_fCnDGby_Lb6A+hy-Q zrs0A5p;x{=Y~$D8sp+wa^EPvFeM?PUTApiKAAH=axuM=RbW!$yW!ypkpJaCwzAd|h zes9f=*Y7RaZS{L|mP6?`WjXSFV|GjZ-jL-K!?oEh^m|QqbN&7(J6yk4Wrynb%IskM zUXkTU`sG=|zAVcLgG;jn`zSTF_|OudsL=gzei^3^t&Q+xPF&s zYV_NZsn&0EX1;!#GKcB+hzt+WG-eLbZ$suF{nlp=)NgHOwtg37X6X0u%)a`q$xPGl zg3LbpO=tGhZ)Ii={Z?cq>G!bAF8ZC9L3?vEXzbt&x;iL>mJZBtlz#sVx|)+gSFu2k^`WbVuezuyUpDkzVXY_RajM`g2 zTacp7NzjPh^)sAA4ckdSL$}k^=(56(drU7}SaenI!+Lz&^YmU1^?kPc zZ~IOxpiJbc$!uDfolvlbTNA%sD4(iz#ioWvzj5)7q^zImRhaFcE8wigbZza#h3U#g z=_Z=IInC*&=D91`6nNJHRhWe_Crm8XJ7 zeEVI14iZglsB3J}TN!wM{otBLx*Ie#AhStfcGp}P!uRk-bgyz)C$mvucE@}WPi@u-nPG+5{qjMW*$bP}6;&Kuon6tqs5$n+1iG!onbC#W zL%QWOX5W3jT7za8>t6A&hj-9SO`O-Bc&{S*F?qdxK8WlWMcetI9(ymzs-v>(m=6-} ztG7Kg)l@c@@2}mX2B*Y=p?$`tew;TVCcT-Zpua@yky%#-bhk`tVRqAe(4`u0WpDvQ z+##7kh1rR@LVdTb^~`kZIsHjB&5ac;l?&BHEL-lC!&4;YA(^p-+3Gberkla!j8yyz z&rTeNN$C)&K-csend<8gv6P1OGV2v)$L2Ps->s_msi{9gt*7H;E71i|(%`H@P1{C|Nxs*E5tf$h`B|)lfLE zI~aDmC5tA%>Q-vds&dt&c>*sMYc5}0-(0aEJ$IY(aphxd#lz+Up(PLN(;4*QUwymt zKgaX$70#Rj;ckjiT0dfz!VJ^!h)4uiM(JA8epE_?D)Np6pT8 z^VcO$mW(O9O}p$H^gFX?=YH$-y`b;Vp56LX7N&aN-@Bmu)Lyf?-PCPV!F2`edawN@ z$ZyRoE6g;vuftANp1O2hL(}pO>&P^ZjjFJ78$+FN?sY0=4tX?HRPu~Uc}4T``pUUu z%g3mq=1knj+S;VIis1X0fDf-~UXmZv_hSk(NB=L4S$%qGOGCZ4Tzj}yPUnspqlMb7 z^9a3!e#8c$+QEfSF|jQzI;(TAUhRikNjV{nNHMz ziuuhgUPqu7XEiHtv?fdl1w^JV%dAzH9ooM1-=%IPQd4G>Rbn5?;$Y?y&%_{|m98s7_|1SxsZfdM7XM0*3H)9x3$V^Fx7eK3H7k>( zB(%_jp~i-5Oq2t3M!sQb^X?VRo?<3sdKPBaT4U1qeY@1Mab|rj0j+64`~`p8qHudp zYi9-)X2;}-XyFmiqP)?WDXevsx0@#KoU&+L7Z`ro`lo#P;F904F0j77G*r4!D*~Gr zpVjZne*5>my>CgMg}qnx9@^{Zo=^82(&Na~%%Z;(?Ou3u;riW=?e>1RJqvE|K8iqq zIVLl*Fgq)Ebo$*dEwKpJP_IWU+zFuB%Nx_`w6qNBzmC3Or@Rq0yvP__&+^`&Pa{>Z zE!)*Q=Yv)Q@tVsgrROj9Mpvn47@$nfH~Ey^-f-O8J}4N=7k4u~ zpL`XTCqF0D>j7MENa7Bce4IDuc49*X4>oJH*foaf%y6AA%EM|DQ)of=yy;FRHq_SY z1dO-xPGw)!#=iZUs6>HeioMc1MNU3gaakGfCm_OouhPqNFbz6REO)$$kq z!jt>i+Q{-ZPYT9ohU&b~8m;`kggO*Dr(R3RdSs%?o#fDqInot%UTJSU1?<62wAZ{rBEC)b$%@fT{)#SROC0#X3C#aRrUeJSds1Nys6Pq*`j;u z1#9O`jgE>rv7$E3r4i`!zauup!uTy^KtghR~tjqP&@@PHL)HYGcB|c{5}% zsiJ*J>aDyfdGTR&I@sAuJ(4#MdPbydXsGpSMssG%!fZueRE*F=H#{}qPU165N$*pm z7d~i(jFI9ldDH!c_31sY?a7LagYt61rvo>7)WppP-qR$O_ad~e3rsqBy|KNn`^m$s z3#{9H>r}7qJ*#^>-eY{xl|==GhnLRND#4KA6Z^f_ed~Vv=={KdK1cL^q4(JCPxZR0 z+kQGN(C9rULx7z&?t#g?Sq=+5{HGi&D9^*^Io%T~6tDulV4}wt)AFI(hV;e>jOgf~ zFEiuGc_wDG8yWe()>RG#jm?Ld^}hP3(yX+Wz-wB(M^+2Q|R%X$B`r>{Td&AihSZhA$N-p8f4XwkK7*~ar(-~DQ)CtK_x@&1|b>50sIX>QTi z|6}hx0IaCa_y4=F3nGdwV!^U>0a=<2D@aGNcd;zX0t?G7?k?4+*^9lzZj3c*EV0+b zZY(jjuNpO`SQ0gfCMIf((OC0)KJ(7Y%$=FbVvE=Re-Au6^UP`Qc~6s~T@QqY;Ou(4@Q@+_ABmdu=5Af$d3fzyKQcPN5N@q&i$!AXI>Utqz07j6H@pJ|H*>4ib$hDYCaWH~%5$r1(e(`N7MRlIiY}|J)X@3i&i%Dp;5QW`%fHw0@s9mE zoG8cb=G&-&l4-VmihS9jTXeU!=3V^F?g9#D@?E^08#y?H>a$wObY@((jMFSPC~}C^ z|Gs};Ovvz?Ik%Q#bI-PJS)Ok!g>Jt~mDFtbJkjEpZCvD|`EO3!6Zxbw+__RwGVdc- zYvKH1*(ycOwfN@L$8x;3H$+D-*-pSQ!Rzz=(rG*OUZ3B@(NfWgMrCW2%qJPqA%%W7 zCD`*7G^1skm7p5qlkcUwXrXOzOqy9V|x;XDLjQ zB_*A-bMWcPvhUE>D49)5F-cR0xt4V*nMt!M^uIsTK=v30 zvpz4-bLmwVUbg0yzgxNN#@yOvopWWKSL(g$oX$se`fI11DlRC0uY5wsb65Fk*=-%( z>-I#4eO9YkW%aHtD?hpNpe{$R*pT?!*6%BoF9^LKU3fx-AG}sJV5Mhr6+4wouYcKc zwcfrBHFfi2pV?(c90Xa45u#`o@L9Af`vjd?go&S$JrE?zbhgqdYh^eUI9i^Xsdd5<6hZ`jpIW zgu=t!sq7!2!O}l?zGRj_qE}74ceLN;Lr0F$Ic9Y;bV_tfI9K1lWV#*M?Pz$Ka#^JY zcz1j|mugDo>*8glf_MBzC9@eM91O+2BPin+E6)&?%?m8>>z*5% z>v}`i4Oc#`%cor$R(fHj13Uk=b9JYSDt^=LjEbuAIjfE9czZ`V>Tq(|2W5+MoK=u( z?NFZQis8PZ?KQvUAB_8@4y!NQl+R-h`LZ%J|IdE?qin+?bmHt+B=6_`!G+wzt!tI% z`+r5zYopdz@v94E>z2^ZH|mU)F>TM|F26))o>M;WtNHnZ9<9U5^EF>K12ZL@!C?en z{lVY4U$&0cxzt~q$n%!{;KJ8-`giW$6+D3K3zUnR_@RMc>O5__cW<Ye)HeDG(;o9yu;*H`-HHIz7Z zJ@;s9SN-73H>#m<*Pxowz9sVwi;vlQvf-wLe~mbo>oB%-f1&o9Kl?2#TfuSq!EfX6 zvi{eX{j&8d+rtvcwO{-^{j%KuawhBR>)95*^S`oR$tv5Xb!2(I`OCiQigw1Mp6yru zdt_z9HGIE-F}&{=nD?u#dyiZE?nSHWSy}F`9RI&%=AzO0bu04y@0{J{k9#k_pB~Nz zd_}|CtGje68*%k}cOP`+*ynE9rrVyMTs!oLZ3paf)DdfR%;l!U%q_AoOskomPggRZak{Zjm#Q|#yB;&c=rNf#bDaiHeK)ON})EiJDE6t}lB5VxmHT3m!YQ(>FF=jkcs&`MmLY{(T- zQm8>n1iD3b(@n&i_0&s<=@|c3!i$$*ayu#$o@QzarNFOgP1gsK93~f(y_t%cbRpYZ z`CSzLMWb^Am-g3qV~$!u4lI)UMx}bT?vcGw`ApfQb`mb>L}UD|l|)uIBcGm5!gU#& zf_$WmQA@0ro3`f#p?J+FMDD3U-1B#FaA$QEy$}LroO`c<@q5xri^8+RBptC4r!mT| z<=D)?cl_R^jcR9eZjLlHPd@DGx_7=%^^JOmRMhn*{avUhEqZR6p_F1re&S+|?)>VZ zIgdi)331?amV7h>`itLZ=@NUiRvnaJN&vZsRJ5FnL$>*-8bsV9J!-C<9?d#C@~8ZlGP+iq_vo&7rWZr5!Yz?7ISYPNTxSJlj-#p~HE~`5U?XmI9(gp;r6{;_ zsw=V*Cc65oK-l;nFT5qVyc2Z)iGX|T;T?5@elQb-)x-k8%r3&&;>e4E zUm#9-z&-p&A=hngSK-IvUUuO(#oWVh6ZiD(CVsCtWdj4hU)=Qze>i4OS$s6K*KJTX zpA;uO80?=HCqH!w_=_>Vhn~GEzJ{)tJ%xXXdw#(`3hi~t?Im^DjHuM+2bUJUkIiK9Q_hmVW7-$#5Waq2S$et@`#4?kGk^A|ot z-1B!|@y3wrHn*R!NZj=gKV00?2X7Vk{DvPR?)u(e{1kD|Pxv|Ft`GS6;vOFS5^>5i z27Xh*|DEElZ|v_E_xyrCBkuJH{&IrZcj;MEp1+XJukrn+=M`?G~3h%q?ikuq=xalciw~0XhZY4<60JtMg;vy{KB5dNp zEp~*BU4MbNX&do}Z1A-O+*7v+XQY6?@dEKscX*B;WF;-g#XE!h-U4xs5(tyJgxk#p z!ks8kW(Ns`Gekhn?F8JD=g7CAKsbE`{PB(=oQ(wJ>?a@>c@C#-$9_Ele|-e}4HS@T zQ-N@)yF6c4Al{(v>biq~zX<~2jSvWbTzIY26@Nno{EZQCN8KYGx$geIi8OWuUqR%I0HhyjjqJgOW-+m7Ju6c#8V~Ue`kSw8WvuM z>xw_#X}F&v;C`%tJhaWEdq;uiJB8O>b;X{#EW_(`*}TANZ||}FRULo#ck-*O%Y!-n zZ#V54XxBiy2HG{yu7P$9v}>SU1K$n}oIEnWUPXSJbH=y1KJqp0LkL$wqb>e+$2N&z zrDV-}@9%!)S>-29e`uF+=RMKq;D!@lUh{YjB3KKtxkR70XMWArOqkPUwSZZ(=3s7Z zdNBLO?D`zRRw9@;wUq~Eo0-#PE_c2{v6;6T*)vPYOdm6%(Y$`0=Hi%>i_ZW@Gk-Qm zj4Vx>U9`0jTr;1}Jm3;tZI+KYXbYR!Zkx|!M$qKOmRV_E1HmO}L{?@~eT674h3TYP zzL-I^Sdn$QSTyfxnqnTdNue|MT^IPUS;)AYu8a5#ZTvpI24Y%^#}mIN&7=&eqIHwB zpR{dlIO`s1G#>8q+}k?O^gvt09BIJj)ss(5W9WpLSuYj7#*>zn62?<2C(HmxF+@7f zewvm$?G72TpQe2?M#eBMXH1Uap7AGRZk{o&W~_{1{Khzuu|5VqQDEH1SP{;6l5s8m znRj5k8;tvOC7fvja|(<(nLB6^7?WcN_ZWe&Fz}NE#@>Vnzf52}i{bgz0^wueKNH+P z{2qbyVBk*(ar8H#408v)#9fc@ZN%!FYv232S2jvH3MD_ z%14K_bNb(I+BIMrIDck-{fd0=+qV8Ddm4#Nm_hGiT+c^)?Dpo6XXpO%=4T%|=GWit zI{ECSe^s^QP0QPGZt$kA(;cha^bKsK(R&5{ew?QFfUg7co@S2$y$Mz?dAHiW2j1LS zyCitdK7_gQQEbn|T-nlZ@xG0%sIni!`Z~^iC6Qi>tpl6AtxDTEx9!(pCq!XC$=-1G z)K{~k9UJrYo}*_%7`SN&dPFm&75Y)G3A5qt*H-U}5X==Tsl>x7s;!B#-+&(8EIskQ z5n7@*#U6uVdqD8T+A{09)8&^uVFe#uaLwv{BsIpnHR?N>PH@ATKdHCe!Ug@aXzv30 zpfAAMIxD^OzM3Tmeyk_Po(+0+)8xW?g045p3v1HmYgQ1#ydWj>f^tWiEX+npmy{VP zSz)I1SRdGWyvV~|nOf~sz_uZXw?QkeNJ*KYr%1^{_dK&5Mz)K^*6dAxq?Qoa=fD%| zb<;l~b*$(U20H)>^jE+!in}y5IgCvSKOqY(5Zc{d9;8{v;NZ4q7Lu`9a0`= z=o-%jo>3~%1ov6F$#c_|@0su?lxC|r$-Z&5Vyab%qy}4`5-F{wqdD?~@q_mUEswH$ z)AajomjhvtI@08&g4Uo}dBol)+f#xo@`pY&do!X@LgCH{-w$D>HQsl$Izee8=WHJm zWrKKa7X*wQBRum`*&Ot}ac#L_ZWk(qY07c_qQxjJR`*8ahKIF~R&Al&EYcd#P^~AS zS$g8^=(2GYWg7drN|)`SLh40&R{xd0J$DU5^F9@nd-^x@!?>saL_Z18e`39f{t$gD z`aQh`?080BXn=q_`fa$~T)-{;yIun8GxXgEAHNd>{L|m-D@+mScM;wu!rlUXF8E-f zRzN$EJe)wqu{V~i4frT9JuflH<=o8`|ey2csFq;Vv3#1Ku z_+tX{lOEFgwBYh=srwfM(vN|^D!@rE{I3GxVOZn(hd`f}@Zp~cga>EMtBY>d3^}^& zAx`=*+X;QeUElCc#XY^-i;oQLkrzHn+~Xf5K2{uE>ym>{(hdDy%xGahar|Q72PEw2 z?|XRIvu^@Udf|t~?8l0;kHXUnKUN(5W5x-m#@xft6elcXfS)6dJ}{J}tHjBF?BO?x zdwxt3zbnDnCqa5K*gr1r@xz}Jcm2X&7Weqz?x+B&-C56iiF^LRhlmrNF2PuI3*C5lyXe_yarY0Ol(64RocJ)p_@}KT{N5q&t1ICR3OQ+p^M1hJU;#O31CgJ$ zjrfQIpey`PchJd30&;93;BP>9W!z3)Oc4lw9RWGWH{xMG0i68<*l#5eULS#Q#tDSG zset<(1>6r6NY|L~Iw`#N*OmAN3b-33AnQ&7Wn;8JIAaCEr_G1cwi5qHf%MWANmh z2CPR-Eyd7EQ1da|(>h>yMhj1EFAKT%f<*&&v|jEPe}GmF_q2Mn93CdE1#Xu%<~OX! zA975$HYa>m=+m2~@USv{1st5^-dx+XppLWB=QlK0�ZcS=HuM!={GE^)|QY!2If_ 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
xIg_#Z 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 Date: Mon, 29 Oct 2018 17:57:43 +0100 Subject: [PATCH 25/91] Adservice: Add libc6-compat runtime dependency (#90) Fixes #89 --- src/adservice/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/adservice/Dockerfile b/src/adservice/Dockerfile index 7b41366..f6810c8 100644 --- a/src/adservice/Dockerfile +++ b/src/adservice/Dockerfile @@ -11,6 +11,8 @@ RUN ./gradlew installDist FROM openjdk:8-alpine +RUN apk add --no-cache libc6-compat + RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe From 9b055cabfbf1f4ed370f1ac17657c5a23bae1681 Mon Sep 17 00:00:00 2001 From: davidstanke Date: Mon, 29 Oct 2018 23:39:44 -0400 Subject: [PATCH 26/91] update requests package (#92) --- src/emailservice/requirements.txt | 2 +- src/recommendationservice/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/emailservice/requirements.txt b/src/emailservice/requirements.txt index 37f6f10..17f0799 100644 --- a/src/emailservice/requirements.txt +++ b/src/emailservice/requirements.txt @@ -35,7 +35,7 @@ PyGObject==3.30.1 python-json-logger==0.1.9 pytz==2018.5 pyxdg==0.26 -requests==2.19.1 +requests==2.20.0 rsa==4.0 SecretStorage==3.1.0 six==1.11.0 diff --git a/src/recommendationservice/requirements.txt b/src/recommendationservice/requirements.txt index 7e77517..54e9a43 100644 --- a/src/recommendationservice/requirements.txt +++ b/src/recommendationservice/requirements.txt @@ -23,7 +23,7 @@ pyasn1-modules==0.2.2 python-json-logger==0.1.9 pytz==2018.5 PyYAML==3.13 -requests==2.19.1 +requests==2.20.0 rsa==3.4.2 six==1.11.0 uritemplate==3.0.0 From b221f61f4f743cfb564d000cc7104f2bd8262345 Mon Sep 17 00:00:00 2001 From: sebright Date: Mon, 5 Nov 2018 09:45:34 -0800 Subject: [PATCH 27/91] adservice: upgrade opencensus-java to 0.17.0. (#93) 0.17.0 is the first stable version of opencensus-contrib-log-correlation-log4j2. This commit also updates log4j2.xml to work with the new version. --- src/adservice/build.gradle | 2 +- src/adservice/src/main/resources/log4j2.xml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/adservice/build.gradle b/src/adservice/build.gradle index 11e1be4..59b0313 100644 --- a/src/adservice/build.gradle +++ b/src/adservice/build.gradle @@ -25,7 +25,7 @@ repositories { group = "adservice" version = "0.1.0-SNAPSHOT" // CURRENT_OPENCENSUS_VERSION -def opencensusVersion = "0.16.1" // LATEST_OPENCENSUS_RELEASE_VERSION +def opencensusVersion = "0.17.0" // LATEST_OPENCENSUS_RELEASE_VERSION def grpcVersion = "1.15.0" // CURRENT_GRPC_VERSION def jacksonVersion = "2.9.6" def prometheusVersion = "0.3.0" diff --git a/src/adservice/src/main/resources/log4j2.xml b/src/adservice/src/main/resources/log4j2.xml index f050ded..177c483 100644 --- a/src/adservice/src/main/resources/log4j2.xml +++ b/src/adservice/src/main/resources/log4j2.xml @@ -6,9 +6,9 @@ - - - + + + From 547cbc1213a27cae4fe9db9fa5619202e8aa920d Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Mon, 5 Nov 2018 16:09:19 -0800 Subject: [PATCH 28/91] support skaffold 0.17 Signed-off-by: Ahmet Alp Balkan --- skaffold.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skaffold.yaml b/skaffold.yaml index b1cd87e..ce4eb49 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: skaffold/v1alpha4 +apiVersion: skaffold/v1alpha5 kind: Config build: artifacts: From 8b5d64b61f28665e9fc71e46ae1484423dedad2b Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Wed, 7 Nov 2018 14:52:31 -0800 Subject: [PATCH 29/91] README: add disk space + IP troubleshooting (#95) fixes #94 Signed-off-by: Ahmet Alp Balkan --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 72a7a09..dd510e1 100644 --- a/README.md +++ b/README.md @@ -126,11 +126,21 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). - applies the `./kubernetes-manifests` deploying the application to Kubernetes. + **Troubleshooting:** If you get "No space left on device" error on Google Cloud Shell, + you can build the images on Google Cloud Build: + [Enable the Cloud Build API](https://console.cloud.google.com/flows/enableapi?apiid=cloudbuild.googleapis.com), then run `skaffold run -p gcb` instead. + 6. Find the IP address of your application, then visit the application on your browser to confirm installation. kubectl get service frontend-external + **Troubleshooting:** A Kubernetes bug (will be fixed in 1.12) combined with + a Skaffold [bug](https://github.com/GoogleContainerTools/skaffold/issues/887) + causes load balancer to not to work even after getting an IP address. If you + are seeing this, run `kubectl get service frontend-external -o=yaml | kubectl apply -f-` + to trigger load balancer reconfiguration. + ### (Optional) Deploying on a Istio-installed cluster > **Note:** you followed GKE deployment steps above, run `skaffold delete` first From 424692befa68629e882ee64c3351b4556205e411 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Wed, 14 Nov 2018 11:21:23 -0800 Subject: [PATCH 30/91] upgrade skaffold to 0.18 (#97) Signed-off-by: Ahmet Alp Balkan --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4850744..50a839e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ services: - docker install: -- curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v0.16.0/skaffold-linux-amd64 +- curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v0.18.0/skaffold-linux-amd64 - chmod +x skaffold - sudo mv skaffold /usr/local/bin From d69f1a4f25dfb5ab260cf0e575ea8f4bd15b8d2b Mon Sep 17 00:00:00 2001 From: rghetia Date: Wed, 14 Nov 2018 14:49:17 -0500 Subject: [PATCH 31/91] increase reporting interval. (#96) also fixed a bug in SD export registration in Ads. --- .../src/main/java/hipstershop/AdService.java | 22 +++++++++++++------ src/checkoutservice/main.go | 1 + src/frontend/main.go | 1 + src/productcatalogservice/server.go | 1 + src/shippingservice/main.go | 1 + 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/adservice/src/main/java/hipstershop/AdService.java b/src/adservice/src/main/java/hipstershop/AdService.java index 9ba3329..1224efe 100644 --- a/src/adservice/src/main/java/hipstershop/AdService.java +++ b/src/adservice/src/main/java/hipstershop/AdService.java @@ -207,16 +207,24 @@ public class AdService { // Registers logging trace exporter. LoggingTraceExporter.register(); long sleepTime = 10; /* seconds */ - int maxAttempts = 3; + int maxAttempts = 5; + boolean statsExporterRegistered = false; + boolean traceExporterRegistered = false; for (int i=0; i Date: Mon, 3 Dec 2018 17:19:12 -0500 Subject: [PATCH 32/91] remove gcr repo name from images (#98) This removes hardcoded GCP project name from images and requires an explicit repository flag to skaffold. Also updating the cloudbuild.yaml for staging with the gcr.io/k8s-skaffold/skaffold image. Fixes #17. --- README.md | 23 +++++------- cloudbuild.yaml | 35 +++++++++++-------- kubernetes-manifests/adservice.yaml | 2 +- kubernetes-manifests/cartservice.yaml | 2 +- kubernetes-manifests/checkoutservice.yaml | 2 +- kubernetes-manifests/currencyservice.yaml | 2 +- kubernetes-manifests/emailservice.yaml | 2 +- kubernetes-manifests/frontend.yaml | 2 +- kubernetes-manifests/loadgenerator.yaml | 2 +- kubernetes-manifests/paymentservice.yaml | 2 +- .../productcatalogservice.yaml | 2 +- .../recommendationservice.yaml | 2 +- kubernetes-manifests/shippingservice.yaml | 2 +- skaffold.yaml | 26 ++++++++------ 14 files changed, 55 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index dd510e1..623046f 100644 --- a/README.md +++ b/README.md @@ -103,24 +103,17 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). kubectl get nodes -2. Enable Google Container Registry (GCR) on your GCP project and configure the +1. Enable Google Container Registry (GCR) on your GCP project and configure the `docker` CLI to authenticate to GCR: gcloud services enable containerregistry.googleapis.com gcloud auth configure-docker -q -3. Set your project ID on image names: - - - Edit `skaffold.yaml`, update the `imageName:` fields that look like - `gcr.io/[PROJECT_ID]` with your own GCP project ID. - - - Similarly, edit all Kubernetes Deployment manifests in the - [`./kubernetes-manifests`](./kubernetes-manifests) directory. Find the - `image:` fields with `gcr.io/[...]` and change them to your own GCP project - ID. - -5. Run `skaffold run` from the root of this repository. This command: +1. In the root of this repository, run `skaffold run --default-repo=gcr.io/[PROJECT_ID]`, + where [PROJECT_ID] is your GCP project ID. + + This command: - builds the container images - pushes them to GCR - applies the `./kubernetes-manifests` deploying the application to @@ -128,9 +121,9 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). **Troubleshooting:** If you get "No space left on device" error on Google Cloud Shell, you can build the images on Google Cloud Build: - [Enable the Cloud Build API](https://console.cloud.google.com/flows/enableapi?apiid=cloudbuild.googleapis.com), then run `skaffold run -p gcb` instead. + [Enable the Cloud Build API](https://console.cloud.google.com/flows/enableapi?apiid=cloudbuild.googleapis.com), then run `skaffold run -p gcb --default-repo=gcr.io/[PROJECT_ID]` instead. -6. Find the IP address of your application, then visit the application on your +1. Find the IP address of your application, then visit the application on your browser to confirm installation. kubectl get service frontend-external @@ -168,7 +161,7 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). This is required only once. -5. Deploy the application with `skaffold run`. +5. Deploy the application with `skaffold run --default-repo=gcr.io/[PROJECT_ID]`. 6. Run `kubectl get pods` to see pods are in a healthy and ready state. diff --git a/cloudbuild.yaml b/cloudbuild.yaml index bd3e4cc..d8404c8 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -1,17 +1,24 @@ -# This file is used to build and deploy the app into a GKE cluster using Google -# Cloud Build. +# Cloudbuild.yaml to deploy to staging # -# Requirements: -# - Give the Google Cloud Build service account "Kubernetes Engine Developer" -# IAM role on the GCP project. -# - Set up Google Cloud Build trigger on Cloud Console. +# PREREQUISITES: +# - Cloud Build service account must have role: "Kubernetes Engine Developer" + +# USAGE: +# GCP zone and GKE target cluster must be specified as substitutions +# Example invocation: +# `gcloud builds submit --config=cloudbuild.yaml --substitutions=_ZONE=us-central1-b,_CLUSTER=demo-app-staging .` steps: -- name: gcr.io/k8s-skaffold/skaffold:v0.16.0 - args: ['skaffold', 'run', '-f=skaffold.yaml'] - env: - - 'CLOUDSDK_COMPUTE_ZONE=us-central1-b' - - 'CLOUDSDK_CONTAINER_CLUSTER=demo-app-staging' -timeout: 1800s -options: # Add more power, and more time, for heavy Skaffold build - machineType: 'N1_HIGHCPU_8' +- id: 'Deploy application to cluster' + name: 'gcr.io/k8s-skaffold/skaffold:v0.18.0' + entrypoint: 'bash' + args: + - '-c' + - > + gcloud container clusters get-credentials --zone=$_ZONE $_CLUSTER; + skaffold run -f=skaffold.yaml --default-repo=gcr.io/$PROJECT_ID; + +# Add more power, and more time, for heavy Skaffold build +timeout: '3600s' +options: + machineType: 'N1_HIGHCPU_8' \ No newline at end of file diff --git a/kubernetes-manifests/adservice.yaml b/kubernetes-manifests/adservice.yaml index 37ee35a..dc0879f 100644 --- a/kubernetes-manifests/adservice.yaml +++ b/kubernetes-manifests/adservice.yaml @@ -25,7 +25,7 @@ spec: terminationGracePeriodSeconds: 5 containers: - name: server - image: gcr.io/microservices-demo-app/adservice + image: adservice ports: - containerPort: 9555 env: diff --git a/kubernetes-manifests/cartservice.yaml b/kubernetes-manifests/cartservice.yaml index 55aa5be..5484017 100644 --- a/kubernetes-manifests/cartservice.yaml +++ b/kubernetes-manifests/cartservice.yaml @@ -25,7 +25,7 @@ spec: terminationGracePeriodSeconds: 5 containers: - name: server - image: gcr.io/microservices-demo-app/cartservice + image: cartservice ports: - containerPort: 7070 env: diff --git a/kubernetes-manifests/checkoutservice.yaml b/kubernetes-manifests/checkoutservice.yaml index 23668a6..aec9591 100644 --- a/kubernetes-manifests/checkoutservice.yaml +++ b/kubernetes-manifests/checkoutservice.yaml @@ -24,7 +24,7 @@ spec: spec: containers: - name: server - image: gcr.io/microservices-demo-app/checkoutservice + image: checkoutservice ports: - containerPort: 5050 readinessProbe: diff --git a/kubernetes-manifests/currencyservice.yaml b/kubernetes-manifests/currencyservice.yaml index b344b1a..6e38247 100644 --- a/kubernetes-manifests/currencyservice.yaml +++ b/kubernetes-manifests/currencyservice.yaml @@ -25,7 +25,7 @@ spec: terminationGracePeriodSeconds: 5 containers: - name: server - image: gcr.io/microservices-demo-app/currencyservice + image: currencyservice ports: - name: grpc containerPort: 7000 diff --git a/kubernetes-manifests/emailservice.yaml b/kubernetes-manifests/emailservice.yaml index 7479c2e..4a5363d 100644 --- a/kubernetes-manifests/emailservice.yaml +++ b/kubernetes-manifests/emailservice.yaml @@ -25,7 +25,7 @@ spec: terminationGracePeriodSeconds: 5 containers: - name: server - image: gcr.io/microservices-demo-app/emailservice + image: emailservice ports: - containerPort: 8080 readinessProbe: diff --git a/kubernetes-manifests/frontend.yaml b/kubernetes-manifests/frontend.yaml index 27d1b8e..e4b8e89 100644 --- a/kubernetes-manifests/frontend.yaml +++ b/kubernetes-manifests/frontend.yaml @@ -24,7 +24,7 @@ spec: spec: containers: - name: server - image: gcr.io/microservices-demo-app/frontend + image: frontend ports: - containerPort: 8080 readinessProbe: diff --git a/kubernetes-manifests/loadgenerator.yaml b/kubernetes-manifests/loadgenerator.yaml index ee84c3a..2032b8c 100644 --- a/kubernetes-manifests/loadgenerator.yaml +++ b/kubernetes-manifests/loadgenerator.yaml @@ -38,7 +38,7 @@ spec: value: "frontend:80" containers: - name: main - image: gcr.io/microservices-demo-app/loadgenerator + image: loadgenerator env: - name: FRONTEND_ADDR value: "frontend:80" diff --git a/kubernetes-manifests/paymentservice.yaml b/kubernetes-manifests/paymentservice.yaml index 8f28410..a3c2e31 100644 --- a/kubernetes-manifests/paymentservice.yaml +++ b/kubernetes-manifests/paymentservice.yaml @@ -25,7 +25,7 @@ spec: terminationGracePeriodSeconds: 5 containers: - name: server - image: gcr.io/microservices-demo-app/paymentservice + image: paymentservice ports: - containerPort: 50051 readinessProbe: diff --git a/kubernetes-manifests/productcatalogservice.yaml b/kubernetes-manifests/productcatalogservice.yaml index 1196356..f6a15cd 100644 --- a/kubernetes-manifests/productcatalogservice.yaml +++ b/kubernetes-manifests/productcatalogservice.yaml @@ -25,7 +25,7 @@ spec: terminationGracePeriodSeconds: 5 containers: - name: server - image: gcr.io/microservices-demo-app/productcatalogservice + image: productcatalogservice ports: - containerPort: 3550 readinessProbe: diff --git a/kubernetes-manifests/recommendationservice.yaml b/kubernetes-manifests/recommendationservice.yaml index 15be40f..20a85d1 100644 --- a/kubernetes-manifests/recommendationservice.yaml +++ b/kubernetes-manifests/recommendationservice.yaml @@ -25,7 +25,7 @@ spec: terminationGracePeriodSeconds: 5 containers: - name: server - image: gcr.io/microservices-demo-app/recommendationservice + image: recommendationservice ports: - containerPort: 8080 readinessProbe: diff --git a/kubernetes-manifests/shippingservice.yaml b/kubernetes-manifests/shippingservice.yaml index 107b574..f0b0dae 100644 --- a/kubernetes-manifests/shippingservice.yaml +++ b/kubernetes-manifests/shippingservice.yaml @@ -24,7 +24,7 @@ spec: spec: containers: - name: server - image: gcr.io/microservices-demo-app/shippingservice + image: shippingservice ports: - containerPort: 50051 readinessProbe: diff --git a/skaffold.yaml b/skaffold.yaml index ce4eb49..eb2f9c4 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -16,27 +16,31 @@ apiVersion: skaffold/v1alpha5 kind: Config build: artifacts: - - image: gcr.io/microservices-demo-app/emailservice + # image tags are relative; to specify an image repo (e.g. GCR), you + # must provide a "default repo" using one of the methods described + # here: + # https://github.com/GoogleContainerTools/skaffold/blob/master/docs/concepts.adoc#2-push + - image: emailservice context: src/emailservice - - image: gcr.io/microservices-demo-app/productcatalogservice + - image: productcatalogservice context: src/productcatalogservice - - image: gcr.io/microservices-demo-app/recommendationservice + - image: recommendationservice context: src/recommendationservice - - image: gcr.io/microservices-demo-app/shippingservice + - image: shippingservice context: src/shippingservice - - image: gcr.io/microservices-demo-app/checkoutservice + - image: checkoutservice context: src/checkoutservice - - image: gcr.io/microservices-demo-app/paymentservice + - image: paymentservice context: src/paymentservice - - image: gcr.io/microservices-demo-app/currencyservice + - image: currencyservice context: src/currencyservice - - image: gcr.io/microservices-demo-app/cartservice + - image: cartservice context: src/cartservice - - image: gcr.io/microservices-demo-app/frontend + - image: frontend context: src/frontend - - image: gcr.io/microservices-demo-app/loadgenerator + - image: loadgenerator context: src/loadgenerator - - image: gcr.io/microservices-demo-app/adservice + - image: adservice context: src/adservice tagPolicy: gitCommit: {} From cb241e197d58b145720c443d15172d2e7edb1b48 Mon Sep 17 00:00:00 2001 From: Dave Stanke Date: Mon, 3 Dec 2018 17:59:18 -0500 Subject: [PATCH 33/91] Clarify description of cloudbuild.yaml (#102) --- cloudbuild.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cloudbuild.yaml b/cloudbuild.yaml index d8404c8..bf8aea7 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -1,4 +1,5 @@ -# Cloudbuild.yaml to deploy to staging +# This configuration file is used to build and deploy the app into a +# GKE cluster using Google Cloud Build. # # PREREQUISITES: # - Cloud Build service account must have role: "Kubernetes Engine Developer" From 5272a4d821011f85925883af067c1fc8c5c7e0b8 Mon Sep 17 00:00:00 2001 From: Chris Kleinknecht Date: Tue, 11 Dec 2018 16:15:51 -0800 Subject: [PATCH 34/91] Re-enable opencensus python (#103) Enables tracing in the email and recommendation services, which was disabled in 316db88 because of a memory leak in the stackdriver exporter. We fixed the leak in https://github.com/googleapis/google-cloud-python/pull/6856. The fix is included in the [0.1.10 release of opencensus-python](https://github.com/census-instrumentation/opencensus-python/releases/tag/v0.1.10). With this diff, traces show up as expected in stackdriver while running the demo on GKE. Using an `opencensus-python` package version before `0.1.10` causes the email and recommendation services to leak memory until they OOM. Memory use is back to normal (i.e. roughly constant) using the new package version. --- src/emailservice/Dockerfile | 4 +-- src/emailservice/email_client.py | 20 +++++------ src/emailservice/email_server.py | 22 ++++++------- src/emailservice/requirements.txt | 11 +++---- .../recommendation_server.py | 33 +++++++++---------- src/recommendationservice/requirements.txt | 9 +++-- 6 files changed, 47 insertions(+), 52 deletions(-) diff --git a/src/emailservice/Dockerfile b/src/emailservice/Dockerfile index 7aa7ec1..0bb5695 100644 --- a/src/emailservice/Dockerfile +++ b/src/emailservice/Dockerfile @@ -13,7 +13,7 @@ RUN apk add --update --no-cache \ # App Deps cairo-dev \ cairo \ - openssl-dev \ + openssl-dev \ gobject-introspection-dev # get packages @@ -42,4 +42,4 @@ RUN apk add --no-cache libstdc++ COPY . . EXPOSE 8080 -ENTRYPOINT [ "python", "email_server.py" ] \ No newline at end of file +ENTRYPOINT [ "python", "email_server.py" ] diff --git a/src/emailservice/email_client.py b/src/emailservice/email_client.py index 32593fe..c31f4ef 100644 --- a/src/emailservice/email_client.py +++ b/src/emailservice/email_client.py @@ -22,20 +22,20 @@ import demo_pb2_grpc from logger import getJSONLogger logger = getJSONLogger('emailservice-client') -# from opencensus.trace.tracer import Tracer -# from opencensus.trace.exporters import stackdriver_exporter -# from opencensus.trace.ext.grpc import client_interceptor +from opencensus.trace.tracer import Tracer +from opencensus.trace.exporters import stackdriver_exporter +from opencensus.trace.ext.grpc import client_interceptor -# try: -# exporter = stackdriver_exporter.StackdriverExporter() -# tracer = Tracer(exporter=exporter) -# tracer_interceptor = client_interceptor.OpenCensusClientInterceptor(tracer, host_port='0.0.0.0:8080') -# except: -# tracer_interceptor = client_interceptor.OpenCensusClientInterceptor() +try: + exporter = stackdriver_exporter.StackdriverExporter() + tracer = Tracer(exporter=exporter) + tracer_interceptor = client_interceptor.OpenCensusClientInterceptor(tracer, host_port='0.0.0.0:8080') +except: + tracer_interceptor = client_interceptor.OpenCensusClientInterceptor() def send_confirmation_email(email, order): channel = grpc.insecure_channel('0.0.0.0:8080') - # channel = grpc.intercept_channel(channel, tracer_interceptor) + channel = grpc.intercept_channel(channel, tracer_interceptor) stub = demo_pb2_grpc.EmailServiceStub(channel) try: response = stub.SendOrderConfirmation(demo_pb2.SendOrderConfirmationRequest( diff --git a/src/emailservice/email_server.py b/src/emailservice/email_server.py index 676b70e..f4a2162 100644 --- a/src/emailservice/email_server.py +++ b/src/emailservice/email_server.py @@ -28,19 +28,18 @@ import demo_pb2_grpc from grpc_health.v1 import health_pb2 from grpc_health.v1 import health_pb2_grpc -# from opencensus.trace.ext.grpc import server_interceptor -# from opencensus.trace.samplers import always_on -# from opencensus.trace.exporters import stackdriver_exporter -# from opencensus.trace.exporters import print_exporter +from opencensus.trace.exporters import stackdriver_exporter +from opencensus.trace.ext.grpc import server_interceptor +from opencensus.trace.samplers import always_on # import googleclouddebugger -# try: -# sampler = always_on.AlwaysOnSampler() -# exporter = stackdriver_exporter.StackdriverExporter() -# tracer_interceptor = server_interceptor.OpenCensusServerInterceptor(sampler, exporter) -# except: -# tracer_interceptor = server_interceptor.OpenCensusServerInterceptor() +try: + sampler = always_on.AlwaysOnSampler() + exporter = stackdriver_exporter.StackdriverExporter() + tracer_interceptor = server_interceptor.OpenCensusServerInterceptor(sampler, exporter) +except: + tracer_interceptor = server_interceptor.OpenCensusServerInterceptor() # try: # googleclouddebugger.enable( @@ -123,7 +122,8 @@ class HealthCheck(): status=health_pb2.HealthCheckResponse.SERVING) def start(dummy_mode): - server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))#, interceptors=(tracer_interceptor,)) + server = grpc.server(futures.ThreadPoolExecutor(max_workers=10), + interceptors=(tracer_interceptor,)) service = None if dummy_mode: service = DummyEmailService() diff --git a/src/emailservice/requirements.txt b/src/emailservice/requirements.txt index 17f0799..65e7717 100644 --- a/src/emailservice/requirements.txt +++ b/src/emailservice/requirements.txt @@ -8,13 +8,12 @@ cryptography==2.3.1 entrypoints==0.2.3 enum34==1.1.6 futures==3.1.1 -google-api-core==1.4.0 -google-auth==1.5.1 -google-cloud-core==0.28.1 -google-cloud-trace==0.19.0 +google-api-core==1.6.0 +google-auth==1.6.1 +google-cloud-core==0.29.0 googleapis-common-protos==1.5.3 grpc-google-iam-v1==0.11.4 -grpcio==1.12.1 +grpcio==1.16.1 grpcio-health-checking==1.12.1 grpcio-tools==1.12.1 idna==2.7 @@ -24,7 +23,7 @@ Jinja2==2.10 keyring==15.1.0 keyrings.alt==3.1 MarkupSafe==1.0 -opencensus==0.1.7 +opencensus[stackdriver]==0.1.10 protobuf==3.6.1 pyasn1==0.4.4 pyasn1-modules==0.2.2 diff --git a/src/recommendationservice/recommendation_server.py b/src/recommendationservice/recommendation_server.py index 09e6e0d..eb24f96 100644 --- a/src/recommendationservice/recommendation_server.py +++ b/src/recommendationservice/recommendation_server.py @@ -14,13 +14,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -import grpc -from concurrent import futures -import time -import traceback import os import random +import time +import traceback +from concurrent import futures + import googleclouddebugger +import grpc +from opencensus.trace.exporters import print_exporter +from opencensus.trace.exporters import stackdriver_exporter +from opencensus.trace.ext.grpc import server_interceptor +from opencensus.trace.samplers import always_on import demo_pb2 import demo_pb2_grpc @@ -30,11 +35,6 @@ from grpc_health.v1 import health_pb2_grpc from logger import getJSONLogger logger = getJSONLogger('recommendationservice-server') -# TODO(morganmclean,ahmetb) tracing currently disabled due to memory leak (see TODO below) -# from opencensus.trace.ext.grpc import server_interceptor -# from opencensus.trace.samplers import always_on -# from opencensus.trace.exporters import stackdriver_exporter -# from opencensus.trace.exporters import print_exporter class RecommendationService(demo_pb2_grpc.RecommendationServiceServicer): def ListRecommendations(self, request, context): @@ -63,15 +63,12 @@ class RecommendationService(demo_pb2_grpc.RecommendationServiceServicer): if __name__ == "__main__": logger.info("initializing recommendationservice") - # TODO(morganmclean,ahmetb) enabling the tracing interceptor/sampler below - # causes an unbounded memory leak eventually OOMing the container. - # ---- - # try: - # sampler = always_on.AlwaysOnSampler() - # exporter = stackdriver_exporter.StackdriverExporter() - # tracer_interceptor = server_interceptor.OpenCensusServerInterceptor(sampler, exporter) - # except: - # tracer_interceptor = server_interceptor.OpenCensusServerInterceptor() + try: + sampler = always_on.AlwaysOnSampler() + exporter = stackdriver_exporter.StackdriverExporter() + tracer_interceptor = server_interceptor.OpenCensusServerInterceptor(sampler, exporter) + except: + tracer_interceptor = server_interceptor.OpenCensusServerInterceptor() try: googleclouddebugger.enable( diff --git a/src/recommendationservice/requirements.txt b/src/recommendationservice/requirements.txt index 54e9a43..e2dda9b 100644 --- a/src/recommendationservice/requirements.txt +++ b/src/recommendationservice/requirements.txt @@ -3,12 +3,11 @@ certifi==2018.4.16 chardet==3.0.4 enum34==1.1.6 futures==3.2.0 -google-api-core==1.2.1 +google-api-core==1.6.0 google-api-python-client==1.7.4 -google-auth==1.5.0 +google-auth==1.6.1 google-auth-httplib2==0.0.3 -google-cloud-core==0.28.1 -google-cloud-trace==0.19.0 +google-cloud-core==0.29.0 google-python-cloud-debugger==2.8 googleapis-common-protos==1.5.3 grpcio==1.13.0 @@ -16,7 +15,7 @@ grpcio-health-checking==1.13.0 grpcio-tools==1.0.0 httplib2==0.11.3 idna==2.7 -opencensus==0.1.5 +opencensus[stackdriver]==0.1.10 protobuf==3.5.2.post1 pyasn1==0.4.3 pyasn1-modules==0.2.2 From c91dca764f5f29b26428fe21f44cee27016543e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Chamley?= Date: Mon, 17 Dec 2018 20:06:49 +0100 Subject: [PATCH 35/91] Toggle bug in ProductCatalogService for demos (#85) Fixes #84. --- src/productcatalogservice/README.md | 26 ++++++++++++ src/productcatalogservice/server.go | 63 +++++++++++++++++++++++------ 2 files changed, 76 insertions(+), 13 deletions(-) diff --git a/src/productcatalogservice/README.md b/src/productcatalogservice/README.md index 15d3cb2..13ff37c 100644 --- a/src/productcatalogservice/README.md +++ b/src/productcatalogservice/README.md @@ -3,3 +3,29 @@ Run the following command to restore dependencies to `vendor/` directory: dep ensure --vendor-only + +## Dynamic catalog reloading / artificial delay + +This service has a "dynamic catalog reloading" feature that is purposefully +not well implemented. The goal of this feature is to allow you to modify the +`products.json` file and have the changes be picked up without having to +restart the service. + +However, this feature is bugged: the catalog is actually reloaded on each +request, introducing a noticeable delay in the frontend. This delay will also +show up in profiling tools: the `parseCatalog` function will take more than 80% +of the CPU time. + +You can trigger this feature (and the delay) by sending a `USR1` signal and +remove it (if needed) by sending a `USR2` signal: + +``` +# Trigger bug +kubectl exec \ + $(kubectl get pods -l app=productcatalogservice -o jsonpath='{.items[0].metadata.name}') \ + -c server -- kill -USR1 1 +# Remove bug +kubectl exec \ + $(kubectl get pods -l app=productcatalogservice -o jsonpath='{.items[0].metadata.name}') \ + -c server -- kill -USR2 1 +``` diff --git a/src/productcatalogservice/server.go b/src/productcatalogservice/server.go index a727922..0fc929f 100644 --- a/src/productcatalogservice/server.go +++ b/src/productcatalogservice/server.go @@ -22,7 +22,10 @@ import ( "io/ioutil" "net" "os" + "os/signal" "strings" + "sync" + "syscall" "time" pb "github.com/GoogleCloudPlatform/microservices-demo/src/productcatalogservice/genproto" @@ -41,18 +44,16 @@ import ( ) var ( - catalogJSON []byte - log *logrus.Logger + cat pb.ListProductsResponse + catalogMutex *sync.Mutex + log *logrus.Logger port = flag.Int("port", 3550, "port to listen at") + + reloadCatalog bool ) func init() { - c, err := ioutil.ReadFile("products.json") - if err != nil { - log.Fatalf("failed to open product catalog json file: %v", err) - } - catalogJSON = c log = logrus.New() log.Formatter = &logrus.JSONFormatter{ FieldMap: logrus.FieldMap{ @@ -63,7 +64,11 @@ func init() { TimestampFormat: time.RFC3339Nano, } log.Out = os.Stdout - log.Info("successfully parsed product catalog json") + catalogMutex = &sync.Mutex{} + err := readCatalogFile(&cat) + if err != nil { + log.Warnf("could not parse product catalog") + } } func main() { @@ -71,6 +76,22 @@ func main() { go initProfiling("productcatalogservice", "1.0.0") flag.Parse() + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGUSR1, syscall.SIGUSR2) + go func() { + for { + sig := <-sigs + log.Printf("Received signal: %s", sig) + if sig == syscall.SIGUSR1 { + reloadCatalog = true + log.Infof("Enable catalog reloading") + } else { + reloadCatalog = false + log.Infof("Disable catalog reloading") + } + } + }() + log.Infof("starting grpc server at :%d", *port) run(*port) select {} @@ -146,12 +167,28 @@ func initProfiling(service, version string) { type productCatalog struct{} -func parseCatalog() []*pb.Product { - var cat pb.ListProductsResponse - - if err := jsonpb.Unmarshal(bytes.NewReader(catalogJSON), &cat); err != nil { +func readCatalogFile(catalog *pb.ListProductsResponse) error { + catalogMutex.Lock() + defer catalogMutex.Unlock() + catalogJSON, err := ioutil.ReadFile("products.json") + if err != nil { + log.Fatalf("failed to open product catalog json file: %v", err) + return err + } + if err := jsonpb.Unmarshal(bytes.NewReader(catalogJSON), catalog); err != nil { log.Warnf("failed to parse the catalog JSON: %v", err) - return nil + return err + } + log.Info("successfully parsed product catalog json") + return nil +} + +func parseCatalog() []*pb.Product { + if reloadCatalog || len(cat.Products) == 0 { + err := readCatalogFile(&cat) + if err != nil { + return []*pb.Product{} + } } return cat.Products } From d966bc7c5d079e3add40d818120a7688f1b41225 Mon Sep 17 00:00:00 2001 From: charlesbaer <30347307+charlesbaer@users.noreply.github.com> Date: Tue, 18 Dec 2018 13:06:19 -0500 Subject: [PATCH 36/91] Minor update to README.md (#104) Added the --region to gcloud container clusters create --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 623046f..bc075b2 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). gcloud services enable container.googleapis.com gcloud container clusters create demo --enable-autoupgrade \ - --enable-autoscaling --min-nodes=3 --max-nodes=10 --num-nodes=5 + --enable-autoscaling --min-nodes=3 --max-nodes=10 --num-nodes=5 --zone=us-central1-a kubectl get nodes From 90e43a87442d7a9fb04e326f9a970ac9d7f5390b Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Wed, 2 Jan 2019 13:34:01 -0800 Subject: [PATCH 37/91] move img/ to docs/img (#110) Signed-off-by: Ahmet Alp Balkan --- README.md | 4 ++-- {img => docs/img}/architecture-diagram.png | Bin {img => docs/img}/hipster-shop-frontend-1.png | Bin {img => docs/img}/hipster-shop-frontend-2.png | Bin 4 files changed, 2 insertions(+), 2 deletions(-) rename {img => docs/img}/architecture-diagram.png (100%) rename {img => docs/img}/hipster-shop-frontend-1.png (100%) rename {img => docs/img}/hipster-shop-frontend-2.png (100%) diff --git a/README.md b/README.md index bc075b2..9829ab3 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Stackdriver, gRPC** and similar cloud-native technologies nowadays. | Home Page | Checkout Screen | |-----------|-----------------| -| [![Screenshot of store homepage](./img/hipster-shop-frontend-1.png)](./img/hipster-shop-frontend-1.png) | [![Screenshot of checkout screen](./img/hipster-shop-frontend-2.png)](./img/hipster-shop-frontend-2.png) | +| [![Screenshot of store homepage](./docs/img/hipster-shop-frontend-1.png)](./docs/img/hipster-shop-frontend-1.png) | [![Screenshot of checkout screen](./docs/img/hipster-shop-frontend-2.png)](./docs/img/hipster-shop-frontend-2.png) | ## Service Architecture @@ -19,7 +19,7 @@ Stackdriver, gRPC** and similar cloud-native technologies nowadays. languages that talk to each other over gRPC. [![Architecture of -microservices](./img/architecture-diagram.png)](./img/architecture-diagram.png) +microservices](./docs/img/architecture-diagram.png)](./docs/img/architecture-diagram.png) Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). diff --git a/img/architecture-diagram.png b/docs/img/architecture-diagram.png similarity index 100% rename from img/architecture-diagram.png rename to docs/img/architecture-diagram.png diff --git a/img/hipster-shop-frontend-1.png b/docs/img/hipster-shop-frontend-1.png similarity index 100% rename from img/hipster-shop-frontend-1.png rename to docs/img/hipster-shop-frontend-1.png diff --git a/img/hipster-shop-frontend-2.png b/docs/img/hipster-shop-frontend-2.png similarity index 100% rename from img/hipster-shop-frontend-2.png rename to docs/img/hipster-shop-frontend-2.png From 94ed247c0b28d07b7fcf905c7dbbb556a9a0bdac Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Thu, 3 Jan 2019 11:25:03 -0800 Subject: [PATCH 38/91] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9829ab3..2455a52 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ web-based e-commerce app called **“Hipster Shop”** where users can browse it add them to the cart, and purchase them. **Google uses this application to demonstrate Kubernetes, GKE, Istio, -Stackdriver, gRPC** and similar cloud-native technologies nowadays. +Stackdriver, gRPC, OpenCensus** and similar cloud-native technologies. ## Screenshots From d944092100696aa4a5974ef5c2e710547a824622 Mon Sep 17 00:00:00 2001 From: rghetia Date: Thu, 3 Jan 2019 12:56:06 -0800 Subject: [PATCH 39/91] Add Jaeger support for Adservice. (#111) This is the first service that exports to jaeger. Others to follow. Requires jaeger to be instantiated using - helm install --name jaeger stable/jaeger-operator - kubectl apply -f jaeger.yaml === jaeger.yaml Content === apiVersion: io.jaegertracing/v1alpha1 kind: Jaeger metadata: name: jaeger Above steps will be added to README in subsequent PR. --- kubernetes-manifests/adservice.yaml | 2 ++ src/adservice/build.gradle | 4 +-- .../src/main/java/hipstershop/AdService.java | 31 +++++++++++++------ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/kubernetes-manifests/adservice.yaml b/kubernetes-manifests/adservice.yaml index dc0879f..0329a72 100644 --- a/kubernetes-manifests/adservice.yaml +++ b/kubernetes-manifests/adservice.yaml @@ -31,6 +31,8 @@ spec: env: - name: PORT value: "9555" + - name: JAEGER_ENABLED + value: "false" resources: requests: cpu: 200m diff --git a/src/adservice/build.gradle b/src/adservice/build.gradle index 59b0313..7450826 100644 --- a/src/adservice/build.gradle +++ b/src/adservice/build.gradle @@ -28,7 +28,6 @@ version = "0.1.0-SNAPSHOT" // CURRENT_OPENCENSUS_VERSION def opencensusVersion = "0.17.0" // LATEST_OPENCENSUS_RELEASE_VERSION def grpcVersion = "1.15.0" // CURRENT_GRPC_VERSION def jacksonVersion = "2.9.6" -def prometheusVersion = "0.3.0" tasks.withType(JavaCompile) { sourceCompatibility = '1.8' @@ -45,7 +44,7 @@ dependencies { compile fileTree(dir: offlineCompile, include: '*.jar') } else { compile "com.google.api.grpc:proto-google-common-protos:1.11.0", - "io.opencensus:opencensus-exporter-stats-prometheus:${opencensusVersion}", + "io.opencensus:opencensus-exporter-trace-jaeger:${opencensusVersion}", "io.opencensus:opencensus-exporter-stats-stackdriver:${opencensusVersion}", "io.opencensus:opencensus-exporter-trace-stackdriver:${opencensusVersion}", "io.opencensus:opencensus-exporter-trace-logging:${opencensusVersion}", @@ -53,7 +52,6 @@ dependencies { "io.grpc:grpc-stub:${grpcVersion}", "io.grpc:grpc-netty:${grpcVersion}", "io.grpc:grpc-services:${grpcVersion}", - "io.prometheus:simpleclient_httpserver:${prometheusVersion}", "org.apache.logging.log4j:log4j-core:2.11.1" runtime "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}", diff --git a/src/adservice/src/main/java/hipstershop/AdService.java b/src/adservice/src/main/java/hipstershop/AdService.java index 1224efe..b5d21a6 100644 --- a/src/adservice/src/main/java/hipstershop/AdService.java +++ b/src/adservice/src/main/java/hipstershop/AdService.java @@ -31,7 +31,7 @@ import io.grpc.services.*; import io.opencensus.common.Duration; import io.opencensus.common.Scope; import io.opencensus.contrib.grpc.metrics.RpcViews; -import io.opencensus.exporter.stats.prometheus.PrometheusStatsCollector; +import io.opencensus.exporter.trace.jaeger.JaegerTraceExporter; import io.opencensus.exporter.trace.logging.LoggingTraceExporter; import io.opencensus.exporter.stats.stackdriver.StackdriverStatsConfiguration; import io.opencensus.exporter.stats.stackdriver.StackdriverStatsExporter; @@ -46,7 +46,6 @@ import io.opencensus.trace.samplers.Samplers; import java.io.IOException; import java.util.Collection; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Random; import java.util.concurrent.TimeUnit; @@ -201,11 +200,6 @@ public class AdService { public static void initStackdriver() { logger.info("Initialize StackDriver"); - // Registers all RPC views. - RpcViews.registerAllViews(); - - // Registers logging trace exporter. - LoggingTraceExporter.register(); long sleepTime = 10; /* seconds */ int maxAttempts = 5; boolean statsExporterRegistered = false; @@ -243,18 +237,35 @@ public class AdService { logger.info("StackDriver initialization complete."); } + static void initJaeger() { + boolean enabled = Boolean.parseBoolean(System.getenv("JAEGER_ENABLED")); + if (enabled) { + // Register Jaeger Tracing. + JaegerTraceExporter.createAndRegister("http://jaeger-collector:14268/api/traces", "adservice"); + logger.info("Jaeger initialization complete."); + } else { + logger.info("Jaeger initialization disabled."); + } + } + /** Main launches the server from the command line. */ public static void main(String[] args) throws IOException, InterruptedException { // Add final keyword to pass checkStyle. + // Registers all RPC views. + RpcViews.registerAllViews(); + + // Registers logging trace exporter. + LoggingTraceExporter.register(); + new Thread( new Runnable() { public void run(){ initStackdriver(); } }).start(); - // Register Prometheus exporters and export metrics to a Prometheus HTTPServer. - PrometheusStatsCollector.createAndRegister(); + // Register Jaeger + initJaeger(); // Start the RPC server. You shouldn't see any output from gRPC before this. logger.info("AdService starting."); @@ -262,4 +273,4 @@ public class AdService { service.start(); service.blockUntilShutdown(); } -} \ No newline at end of file +} From 27e1b03c26b0397cf451c7d4d9bce52dfe8b6fd2 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Tue, 8 Jan 2019 10:51:36 -0800 Subject: [PATCH 40/91] Add conference videos --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 2455a52..70b2046 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,14 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). curl -v "http://$INGRESS_HOST" +## Conferences featuring Hipster Shop + +- [Google Cloud Next'18 London – Keynote](https://youtu.be/nIq2pkNcfEI?t=3071) showing Stackdriver Incident Response Management +- Google Cloud Next'18 SF + - [Day 1 Keynote](https://youtu.be/vJ9OaAqfxo4?t=2416) showing GKE On-Prem + - [Day 3 – Keynote](https://youtu.be/JQPOPV_VH5w?t=815) showing Stackdriver APM (Tracing, Code Search, Profiler, Google Cloud Build) + - [Introduction to Service Management with Istio](https://www.youtube.com/watch?v=wCJrdKdD6UM&feature=youtu.be&t=586) + --- **Note to fellow Googlers:** Please fill out the form at From 85c7131d43b02ea7c0c777354ee1bd5c538de202 Mon Sep 17 00:00:00 2001 From: rghetia Date: Tue, 8 Jan 2019 11:08:20 -0800 Subject: [PATCH 41/91] Add jaeger support for frontend. (#113) --- kubernetes-manifests/frontend.yaml | 2 + src/frontend/Gopkg.lock | 111 +++++++++++++++++++---------- src/frontend/main.go | 36 +++++++++- 3 files changed, 111 insertions(+), 38 deletions(-) diff --git a/kubernetes-manifests/frontend.yaml b/kubernetes-manifests/frontend.yaml index e4b8e89..c83a1a7 100644 --- a/kubernetes-manifests/frontend.yaml +++ b/kubernetes-manifests/frontend.yaml @@ -58,6 +58,8 @@ spec: value: "checkoutservice:5050" - name: AD_SERVICE_ADDR value: "adservice:9555" + # - name: JAEGER_SERVICE_ADDR + # value: "jaeger-collector:14268" resources: requests: cpu: 100m diff --git a/src/frontend/Gopkg.lock b/src/frontend/Gopkg.lock index fa48498..53289b0 100644 --- a/src/frontend/Gopkg.lock +++ b/src/frontend/Gopkg.lock @@ -16,16 +16,33 @@ version = "v0.27.0" [[projects]] - digest = "1:9fe70def8f0ceb3d455a0acad9dadd6632287cdbf9c8c2ea50e8dabe2ade40c4" + digest = "1:4b96dcd8534bc6450a922bd16a76360ba3381f0d1daf40abbaec91c053fbfeb5" name = "contrib.go.opencensus.io/exporter/stackdriver" - packages = [ - ".", - "propagation", - ] + packages = ["."] pruneopts = "UT" revision = "37aa2801fbf0205003e15636096ebf0373510288" version = "v0.5.0" +[[projects]] + branch = "master" + digest = "1:1d8f3cb93c42c5652bb509fde29ecdd1feede9334e355e8bbdc0f9f95b40c254" + name = "git.apache.org/thrift.git" + packages = ["lib/go/thrift"] + pruneopts = "UT" + revision = "6503043bc42ab96da14c25f3aee2bb4add719774" + source = "github.com/apache/thrift" + +[[projects]] + branch = "master" + digest = "1:6cbe7676244a1429f4c22601f799d377a70449469ef636f91d992d719b559ff3" + name = "github.com/GoogleCloudPlatform/microservices-demo" + packages = [ + "src/frontend/genproto", + "src/frontend/money", + ] + pruneopts = "UT" + revision = "d944092100696aa4a5974ef5c2e710547a824622" + [[projects]] digest = "1:72856926f8208767b837bf51e3373f49139f61889b67dc7fd3c2a0fd711e3f7a" name = "github.com/golang/protobuf" @@ -50,23 +67,26 @@ name = "github.com/google/pprof" packages = ["profile"] pruneopts = "UT" - revision = "84b7d314e22c8d12334e52726f68517973b6027b" + revision = "3ea8567a2e5752420fc544d2e2ad249721768934" [[projects]] - digest = "1:3a26588bc48b96825977c1b3df964f8fd842cd6860cc26370588d3563433cf11" + digest = "1:236d7e1bdb50d8f68559af37dbcf9d142d56b431c9b2176d41e2a009b664cda8" name = "github.com/google/uuid" packages = ["."] pruneopts = "UT" - revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494" - version = "v1.0.0" + revision = "9b3b1e0f5f99ae461456d768e7d301a7acdaa2d8" + version = "v1.1.0" [[projects]] - digest = "1:e145e9710a10bc114a6d3e2738aadf8de146adaa031854ffdf7bbfe15da85e63" + digest = "1:cd9864c6366515827a759931746738ede6079faa08df9c584596370d6add135c" name = "github.com/googleapis/gax-go" - packages = ["."] + packages = [ + ".", + "v2", + ] pruneopts = "UT" - revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f" - version = "v2.0.0" + revision = "c8a15bac9b9fe955bd9f900272f9a306465d28cf" + version = "v2.0.3" [[projects]] digest = "1:c79fb010be38a59d657c48c6ba1d003a8aa651fa56b579d959d74573b7dff8e1" @@ -84,6 +104,14 @@ revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf" version = "v1.6.2" +[[projects]] + digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8" + name = "github.com/konsorten/go-windows-terminal-sequences" + packages = ["."] + pruneopts = "UT" + revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242" + version = "v1.0.1" + [[projects]] digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747" name = "github.com/pkg/errors" @@ -93,18 +121,20 @@ version = "v0.8.0" [[projects]] - digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc" + digest = "1:69b1cc331fca23d702bd72f860c6a647afd0aa9fcbc1d0659b1365e26546dd70" name = "github.com/sirupsen/logrus" packages = ["."] pruneopts = "UT" - revision = "3e01752db0189b9157070a0e1668a620f9a85da2" - version = "v1.0.6" + revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95" + version = "v1.2.0" [[projects]] - digest = "1:1bb914cfb78f68f488a91cd7872d3d06a5f83c5bbacf0296dbef44e120b00a91" + digest = "1:a5154dfd6b37bef5a3eab759e13296348e639dc8c7604f538368167782b08ccd" name = "go.opencensus.io" packages = [ ".", + "exporter/jaeger", + "exporter/jaeger/internal/gen-go/jaeger", "internal", "internal/tagencoding", "plugin/ocgrpc", @@ -125,15 +155,15 @@ [[projects]] branch = "master" - digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8" + digest = "1:38f553aff0273ad6f367cb0a0f8b6eecbaef8dc6cb8b50e57b6a81c1d5b1e332" name = "golang.org/x/crypto" packages = ["ssh/terminal"] pruneopts = "UT" - revision = "0e37d006457bf46f9e6692014ba72ef82c33022c" + revision = "ff983b9c42bc9fbf91556e191cc8efb585c16908" [[projects]] branch = "master" - digest = "1:1c14517b2f106c61d75006199b46a46576058661d469658cb0f90739919641d2" + digest = "1:8ecb828bb550a8c6b7d75b8261a42c369461311616ebe5451966d067f5f993bf" name = "golang.org/x/net" packages = [ "context", @@ -146,11 +176,11 @@ "trace", ] pruneopts = "UT" - revision = "26e67e76b6c3f6ce91f7c52def5af501b4e0f3a2" + revision = "927f97764cc334a6575f4b7a1584a147864d5723" [[projects]] branch = "master" - digest = "1:f645667d687fc8bf228865a2c5455824ef05bad08841e673673ef2bb89ac5b90" + digest = "1:23443edff0740e348959763085df98400dcfd85528d7771bb0ce9f5f2754ff4a" name = "golang.org/x/oauth2" packages = [ ".", @@ -160,26 +190,26 @@ "jwt", ] pruneopts = "UT" - revision = "d2e6202438beef2727060aa7cabdd924d92ebfd9" + revision = "d668ce993890a79bda886613ee587a69dd5da7a6" [[projects]] branch = "master" - digest = "1:e0140c0c868c6e0f01c0380865194592c011fe521d6e12d78bfd33e756fe018a" + digest = "1:75515eedc0dc2cb0b40372008b616fa2841d831c63eedd403285ff286c593295" name = "golang.org/x/sync" packages = ["semaphore"] pruneopts = "UT" - revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca" + revision = "37e7f081c4d4c64e13b10787722085407fe5d15f" [[projects]] branch = "master" - digest = "1:374fc90fcb026e9a367e3fad29e988e5dd944b68ca3f24a184d77abc5307dda4" + digest = "1:191cccd950a4aeadb60306062f2bdc2f924d750d0156ec6c691b17211bfd7349" name = "golang.org/x/sys" packages = [ "unix", "windows", ] pruneopts = "UT" - revision = "d0be0721c37eeb5299f245a996a483160fc36940" + revision = "82a175fd1598e8a172e58ebdf5ed262bb29129e5" [[projects]] digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" @@ -206,7 +236,7 @@ [[projects]] branch = "master" - digest = "1:e9e388241f9f0f02000dddaeeb91153d53f0cd09dcec33879cc7e043a2e65d75" + digest = "1:2e81813e8e072aa700e101369890e55539729d817d32dbc3fab228d6b40c4d83" name = "google.golang.org/api" packages = [ "googleapi/transport", @@ -217,12 +247,13 @@ "transport", "transport/grpc", "transport/http", + "transport/http/internal/propagation", ] pruneopts = "UT" - revision = "7ca32eb868bf53ea2fc406698eb98583a8073d19" + revision = "19e022d8cf43ce81f046bae8cc18c5397cc7732f" [[projects]] - digest = "1:26619fcd2452b4044174d26acd8b09c09dffee9a1c3a22d2383b873aa9a0131f" + digest = "1:c4eaa5f79d36f76ef4bd0c4f96e36bc1b7b5a359528d1267f0cb7a5d58b7b5bb" name = "google.golang.org/appengine" packages = [ ".", @@ -239,12 +270,12 @@ "urlfetch", ] pruneopts = "UT" - revision = "b1f26356af11148e710935ed1ac8a7f5702c7612" - version = "v1.1.0" + revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1" + version = "v1.4.0" [[projects]] branch = "master" - digest = "1:7a3da01a8f840fbbef1f027dc091ae52a29c6ab9374e126b6bdc5bf3b0ff2687" + digest = "1:3552e7267a98c605e6cbfe6b03c34589265ab72e6078b95fb2e10e0cb44f5cc8" name = "google.golang.org/genproto" packages = [ "googleapis/api/annotations", @@ -260,28 +291,33 @@ "protobuf/field_mask", ] pruneopts = "UT" - revision = "36d5787dc5356b711fe8f3040271aaf51c35955b" + revision = "bd9b4fb69e2ffd37621a6caa54dcbead29b546f2" [[projects]] - digest = "1:4ad047d772a7d4841687df9534a767a9e243885ed6d7d2ced6af5995a5dc44b3" + digest = "1:3fc54ad826c0183f803bb97e0927dfc05fcb7b7a6ddabed646ee8184d861fa9b" name = "google.golang.org/grpc" packages = [ ".", "balancer", "balancer/base", "balancer/roundrobin", + "binarylog/grpc_binarylog_v1", "codes", "connectivity", "credentials", + "credentials/internal", "credentials/oauth", "encoding", "encoding/proto", "grpclog", "internal", "internal/backoff", + "internal/binarylog", "internal/channelz", "internal/envconfig", "internal/grpcrand", + "internal/grpcsync", + "internal/syscall", "internal/transport", "keepalive", "metadata", @@ -295,8 +331,8 @@ "tap", ] pruneopts = "UT" - revision = "8dea3dc473e90c8179e519d91302d0597c0ca1d1" - version = "v1.15.0" + revision = "df014850f6dee74ba2fc94874043a9f3f75fbfd8" + version = "v1.17.0" [solve-meta] analyzer-name = "dep" @@ -311,6 +347,7 @@ "github.com/gorilla/mux", "github.com/pkg/errors", "github.com/sirupsen/logrus", + "go.opencensus.io/exporter/jaeger", "go.opencensus.io/plugin/ocgrpc", "go.opencensus.io/plugin/ochttp", "go.opencensus.io/plugin/ochttp/propagation/b3", diff --git a/src/frontend/main.go b/src/frontend/main.go index 5046432..61ac8ce 100644 --- a/src/frontend/main.go +++ b/src/frontend/main.go @@ -26,6 +26,7 @@ import ( "github.com/gorilla/mux" "github.com/pkg/errors" "github.com/sirupsen/logrus" + "go.opencensus.io/exporter/jaeger" "go.opencensus.io/plugin/ocgrpc" "go.opencensus.io/plugin/ochttp" "go.opencensus.io/plugin/ochttp/propagation/b3" @@ -142,6 +143,29 @@ func main() { log.Fatal(http.ListenAndServe(addr+":"+srvPort, handler)) } +func initJaegerTracing(log logrus.FieldLogger) { + + svcAddr := os.Getenv("JAEGER_SERVICE_ADDR") + if svcAddr == "" { + log.Info("jaeger initialization disabled.") + return + } + + // Register the Jaeger exporter to be able to retrieve + // the collected spans. + exporter, err := jaeger.NewExporter(jaeger.Options{ + Endpoint: fmt.Sprintf("http://%s", svcAddr), + Process: jaeger.Process{ + ServiceName: "frontend", + }, + }) + if err != nil { + log.Fatal(err) + } + trace.RegisterExporter(exporter) + log.Info("jaeger initialization completed.") +} + func initStats(log logrus.FieldLogger, exporter *stackdriver.Exporter) { view.SetReportingPeriod(60 * time.Second) view.RegisterExporter(exporter) @@ -158,16 +182,26 @@ func initStats(log logrus.FieldLogger, exporter *stackdriver.Exporter) { } func initTracing(log logrus.FieldLogger) { + // This is a demo app with low QPS. trace.AlwaysSample() is used here + // to make sure traces are available for observation and analysis. + // In a production environment or high QPS setup please use + // trace.ProbabilitySampler set at the desired probability. + trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) + + initJaegerTracing(log) + // TODO(ahmetb) this method is duplicated in other microservices using Go // since they are not sharing packages. for i := 1; i <= 3; i++ { log = log.WithField("retry", i) exporter, err := stackdriver.NewExporter(stackdriver.Options{}) if err != nil { + // log.Warnf is used since there are multiple backends (stackdriver & jaeger) + // to store the traces. In production setup most likely you would use only one backend. + // In that case you should use log.Fatalf. log.Warnf("failed to initialize stackdriver exporter: %+v", err) } else { trace.RegisterExporter(exporter) - trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) log.Info("registered stackdriver tracing") // Register the views to collect server stats. From 33ca3b63d82698035ffc1230dcb650885a005197 Mon Sep 17 00:00:00 2001 From: rghetia Date: Wed, 9 Jan 2019 05:42:54 -0800 Subject: [PATCH 42/91] Unify jaeger enabling method for adservice. (#115) --- kubernetes-manifests/adservice.yaml | 8 ++++---- src/adservice/src/main/java/hipstershop/AdService.java | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/kubernetes-manifests/adservice.yaml b/kubernetes-manifests/adservice.yaml index 0329a72..76f35ae 100644 --- a/kubernetes-manifests/adservice.yaml +++ b/kubernetes-manifests/adservice.yaml @@ -31,8 +31,8 @@ spec: env: - name: PORT value: "9555" - - name: JAEGER_ENABLED - value: "false" + #- name: JAEGER_SERVICE_ADDR + # value: "jaeger-collector:14268" resources: requests: cpu: 200m @@ -42,12 +42,12 @@ spec: memory: 300Mi readinessProbe: initialDelaySeconds: 20 - periodSeconds: 5 + periodSeconds: 15 exec: command: ["/bin/grpc_health_probe", "-addr=:9555"] livenessProbe: initialDelaySeconds: 20 - periodSeconds: 5 + periodSeconds: 15 exec: command: ["/bin/grpc_health_probe", "-addr=:9555"] --- diff --git a/src/adservice/src/main/java/hipstershop/AdService.java b/src/adservice/src/main/java/hipstershop/AdService.java index b5d21a6..7320764 100644 --- a/src/adservice/src/main/java/hipstershop/AdService.java +++ b/src/adservice/src/main/java/hipstershop/AdService.java @@ -238,10 +238,11 @@ public class AdService { } static void initJaeger() { - boolean enabled = Boolean.parseBoolean(System.getenv("JAEGER_ENABLED")); - if (enabled) { + String jaegerAddr = System.getenv("JAEGER_SERVICE_ADDR"); + if (jaegerAddr != null && !jaegerAddr.isEmpty()) { + String jaegerUrl = String.format("http://%s/api/traces", jaegerAddr); // Register Jaeger Tracing. - JaegerTraceExporter.createAndRegister("http://jaeger-collector:14268/api/traces", "adservice"); + JaegerTraceExporter.createAndRegister(jaegerUrl, "adservice"); logger.info("Jaeger initialization complete."); } else { logger.info("Jaeger initialization disabled."); From 2b074f7ff3d6dfbd4220dc29c1abd8ea052012df Mon Sep 17 00:00:00 2001 From: rghetia Date: Thu, 10 Jan 2019 10:25:07 -0800 Subject: [PATCH 43/91] Add jaeger export to checkoutservice. (#116) * Add jaeger export to checkoutservice. * fix review comments. --- kubernetes-manifests/checkoutservice.yaml | 2 + src/checkoutservice/Gopkg.lock | 153 +++++++++++++++++----- src/checkoutservice/main.go | 31 ++++- 3 files changed, 149 insertions(+), 37 deletions(-) diff --git a/kubernetes-manifests/checkoutservice.yaml b/kubernetes-manifests/checkoutservice.yaml index aec9591..1b537df 100644 --- a/kubernetes-manifests/checkoutservice.yaml +++ b/kubernetes-manifests/checkoutservice.yaml @@ -46,6 +46,8 @@ spec: value: "currencyservice:7000" - name: CART_SERVICE_ADDR value: "cartservice:7070" + # - name: JAEGER_SERVICE_ADDR + # value: "jaeger-collector:14268" resources: requests: cpu: 100m diff --git a/src/checkoutservice/Gopkg.lock b/src/checkoutservice/Gopkg.lock index 364e527..273cb71 100644 --- a/src/checkoutservice/Gopkg.lock +++ b/src/checkoutservice/Gopkg.lock @@ -2,27 +2,49 @@ [[projects]] + digest = "1:467af0aad47996b25b838d6f14c8371123a8a76ec239020a6c5894e1f8f60272" name = "cloud.google.com/go" packages = [ "compute/metadata", "internal/version", "monitoring/apiv3", "profiler", - "trace/apiv2" + "trace/apiv2", ] + pruneopts = "UT" revision = "c728a003b238b26cef9ab6753a5dc424b331c3ad" version = "v0.27.0" [[projects]] + digest = "1:4b96dcd8534bc6450a922bd16a76360ba3381f0d1daf40abbaec91c053fbfeb5" name = "contrib.go.opencensus.io/exporter/stackdriver" - packages = [ - ".", - "propagation" - ] + packages = ["."] + pruneopts = "UT" revision = "37aa2801fbf0205003e15636096ebf0373510288" version = "v0.5.0" [[projects]] + branch = "master" + digest = "1:1d8f3cb93c42c5652bb509fde29ecdd1feede9334e355e8bbdc0f9f95b40c254" + name = "git.apache.org/thrift.git" + packages = ["lib/go/thrift"] + pruneopts = "UT" + revision = "a5df39032ca206e2e6a9ec975147e81746d9a255" + source = "github.com/apache/thrift" + +[[projects]] + branch = "master" + digest = "1:f6bdf3d8d3cbb2f98d3ebaa66b3ac25166a06830027ece7d592d9ea09dedf504" + name = "github.com/GoogleCloudPlatform/microservices-demo" + packages = [ + "src/checkoutservice/genproto", + "src/checkoutservice/money", + ] + pruneopts = "UT" + revision = "33ca3b63d82698035ffc1230dcb650885a005197" + +[[projects]] + digest = "1:72856926f8208767b837bf51e3373f49139f61889b67dc7fd3c2a0fd711e3f7a" name = "github.com/golang/protobuf" packages = [ "proto", @@ -33,41 +55,62 @@ "ptypes/empty", "ptypes/struct", "ptypes/timestamp", - "ptypes/wrappers" + "ptypes/wrappers", ] + pruneopts = "UT" revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" version = "v1.2.0" [[projects]] branch = "master" + digest = "1:089d56c0adb79140365b5c86815ce97233986da6f3a525c6b706773e4b83876f" name = "github.com/google/pprof" packages = ["profile"] - revision = "e027b505a088ac3c68c339a1d7ce7724bf34538b" + pruneopts = "UT" + revision = "985cf9b4fdd2b479e4563ec57352005f69d5f9f6" [[projects]] + digest = "1:236d7e1bdb50d8f68559af37dbcf9d142d56b431c9b2176d41e2a009b664cda8" name = "github.com/google/uuid" packages = ["."] - revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494" - version = "v1.0.0" + pruneopts = "UT" + revision = "9b3b1e0f5f99ae461456d768e7d301a7acdaa2d8" + version = "v1.1.0" [[projects]] + digest = "1:cd9864c6366515827a759931746738ede6079faa08df9c584596370d6add135c" name = "github.com/googleapis/gax-go" - packages = ["."] - revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f" - version = "v2.0.0" + packages = [ + ".", + "v2", + ] + pruneopts = "UT" + revision = "c8a15bac9b9fe955bd9f900272f9a306465d28cf" + version = "v2.0.3" [[projects]] - digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc" + digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8" + name = "github.com/konsorten/go-windows-terminal-sequences" + packages = ["."] + pruneopts = "UT" + revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242" + version = "v1.0.1" + +[[projects]] + digest = "1:87c2e02fb01c27060ccc5ba7c5a407cc91147726f8f40b70cceeedbc52b1f3a8" name = "github.com/sirupsen/logrus" packages = ["."] pruneopts = "UT" - revision = "3e01752db0189b9157070a0e1668a620f9a85da2" - version = "v1.0.6" + revision = "e1e72e9de974bd926e5c56f83753fba2df402ce5" + version = "v1.3.0" [[projects]] + digest = "1:a5154dfd6b37bef5a3eab759e13296348e639dc8c7604f538368167782b08ccd" name = "go.opencensus.io" packages = [ ".", + "exporter/jaeger", + "exporter/jaeger/internal/gen-go/jaeger", "internal", "internal/tagencoding", "plugin/ocgrpc", @@ -80,21 +123,23 @@ "trace", "trace/internal", "trace/propagation", - "trace/tracestate" + "trace/tracestate", ] + pruneopts = "UT" revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89" version = "v0.16.0" [[projects]] branch = "master" - digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8" + digest = "1:38f553aff0273ad6f367cb0a0f8b6eecbaef8dc6cb8b50e57b6a81c1d5b1e332" name = "golang.org/x/crypto" packages = ["ssh/terminal"] pruneopts = "UT" - revision = "0e37d006457bf46f9e6692014ba72ef82c33022c" + revision = "ff983b9c42bc9fbf91556e191cc8efb585c16908" [[projects]] branch = "master" + digest = "1:8ecb828bb550a8c6b7d75b8261a42c369461311616ebe5451966d067f5f993bf" name = "golang.org/x/net" packages = [ "context", @@ -104,35 +149,46 @@ "http2/hpack", "idna", "internal/timeseries", - "trace" + "trace", ] - revision = "26e67e76b6c3f6ce91f7c52def5af501b4e0f3a2" + pruneopts = "UT" + revision = "1e06a53dbb7e2ed46e91183f219db23c6943c532" [[projects]] branch = "master" + digest = "1:23443edff0740e348959763085df98400dcfd85528d7771bb0ce9f5f2754ff4a" name = "golang.org/x/oauth2" packages = [ ".", "google", "internal", "jws", - "jwt" + "jwt", ] - revision = "d2e6202438beef2727060aa7cabdd924d92ebfd9" + pruneopts = "UT" + revision = "d668ce993890a79bda886613ee587a69dd5da7a6" [[projects]] branch = "master" + digest = "1:75515eedc0dc2cb0b40372008b616fa2841d831c63eedd403285ff286c593295" name = "golang.org/x/sync" packages = ["semaphore"] - revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca" + pruneopts = "UT" + revision = "37e7f081c4d4c64e13b10787722085407fe5d15f" [[projects]] branch = "master" + digest = "1:12ef3ef293a3a3930a82e5f38a3c45a1b03a9ed72dedc192d90e89d59b1f13a5" name = "golang.org/x/sys" - packages = ["unix"] - revision = "1561086e645b2809fb9f8a1e2a38160bf8d53bf4" + packages = [ + "unix", + "windows", + ] + pruneopts = "UT" + revision = "7fbe1cd0fcc20051e1fcb87fbabec4a1bacaaeba" [[projects]] + digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" name = "golang.org/x/text" packages = [ "collate", @@ -148,13 +204,15 @@ "unicode/bidi", "unicode/cldr", "unicode/norm", - "unicode/rangetable" + "unicode/rangetable", ] + pruneopts = "UT" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] branch = "master" + digest = "1:b74a0ae8b7755bf9cdadead4dea674d76517cd2fea7bd482a6a46bb6b3ce085b" name = "google.golang.org/api" packages = [ "googleapi/transport", @@ -164,11 +222,14 @@ "support/bundler", "transport", "transport/grpc", - "transport/http" + "transport/http", + "transport/http/internal/propagation", ] - revision = "19ff8768a5c0b8e46ea281065664787eefc24121" + pruneopts = "UT" + revision = "032faecc3e7e2c445ec37a1b1ec4e5a3016d96f2" [[projects]] + digest = "1:c4eaa5f79d36f76ef4bd0c4f96e36bc1b7b5a359528d1267f0cb7a5d58b7b5bb" name = "google.golang.org/appengine" packages = [ ".", @@ -182,13 +243,15 @@ "internal/socket", "internal/urlfetch", "socket", - "urlfetch" + "urlfetch", ] - revision = "ae0ab99deb4dc413a2b4bd6c8bdd0eb67f1e4d06" - version = "v1.2.0" + pruneopts = "UT" + revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1" + version = "v1.4.0" [[projects]] branch = "master" + digest = "1:3552e7267a98c605e6cbfe6b03c34589265ab72e6078b95fb2e10e0cb44f5cc8" name = "google.golang.org/genproto" packages = [ "googleapis/api/annotations", @@ -201,11 +264,13 @@ "googleapis/monitoring/v3", "googleapis/rpc/errdetails", "googleapis/rpc/status", - "protobuf/field_mask" + "protobuf/field_mask", ] - revision = "c3f76f3b92d1ffa4c58a9ff842a58b8877655e0f" + pruneopts = "UT" + revision = "ae2f86662275e140f395167f1dab7081a5bd5fa8" [[projects]] + digest = "1:6497ab07ec89179db8d5a563d33635be04ceffaa29007a3ae74b9f15f4d3068e" name = "google.golang.org/grpc" packages = [ ".", @@ -235,14 +300,32 @@ "resolver/passthrough", "stats", "status", - "tap" + "tap", ] + pruneopts = "UT" revision = "32fb0ac620c32ba40a4626ddf94d90d12cce3455" version = "v1.14.0" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "0c103e5e32d8ecdd70048b6d91e02b910e30bad54f06b230a9664f585433a669" + input-imports = [ + "cloud.google.com/go/profiler", + "contrib.go.opencensus.io/exporter/stackdriver", + "github.com/GoogleCloudPlatform/microservices-demo/src/checkoutservice/genproto", + "github.com/GoogleCloudPlatform/microservices-demo/src/checkoutservice/money", + "github.com/golang/protobuf/proto", + "github.com/google/uuid", + "github.com/sirupsen/logrus", + "go.opencensus.io/exporter/jaeger", + "go.opencensus.io/plugin/ocgrpc", + "go.opencensus.io/stats/view", + "go.opencensus.io/trace", + "golang.org/x/net/context", + "google.golang.org/grpc", + "google.golang.org/grpc/codes", + "google.golang.org/grpc/health/grpc_health_v1", + "google.golang.org/grpc/status", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/src/checkoutservice/main.go b/src/checkoutservice/main.go index 990b004..fdf1c83 100644 --- a/src/checkoutservice/main.go +++ b/src/checkoutservice/main.go @@ -25,6 +25,7 @@ import ( "contrib.go.opencensus.io/exporter/stackdriver" "github.com/google/uuid" "github.com/sirupsen/logrus" + "go.opencensus.io/exporter/jaeger" "go.opencensus.io/plugin/ocgrpc" "go.opencensus.io/stats/view" "go.opencensus.io/trace" @@ -98,6 +99,28 @@ func main() { log.Fatal(err) } +func initJaegerTracing() { + svcAddr := os.Getenv("JAEGER_SERVICE_ADDR") + if svcAddr == "" { + log.Info("jaeger initialization disabled.") + return + } + + // Register the Jaeger exporter to be able to retrieve + // the collected spans. + exporter, err := jaeger.NewExporter(jaeger.Options{ + Endpoint: fmt.Sprintf("http://%s", svcAddr), + Process: jaeger.Process{ + ServiceName: "checkoutservice", + }, + }) + if err != nil { + log.Fatal(err) + } + trace.RegisterExporter(exporter) + log.Info("jaeger initialization completed.") +} + func initStats(exporter *stackdriver.Exporter) { view.SetReportingPeriod(60 * time.Second) view.RegisterExporter(exporter) @@ -108,7 +131,7 @@ func initStats(exporter *stackdriver.Exporter) { } } -func initTracing() { +func initStackDriverTracing() { // TODO(ahmetb) this method is duplicated in other microservices using Go // since they are not sharing packages. for i := 1; i <= 3; i++ { @@ -117,7 +140,6 @@ func initTracing() { log.Infof("failed to initialize stackdriver exporter: %+v", err) } else { trace.RegisterExporter(exporter) - trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) log.Info("registered stackdriver tracing") // Register the views to collect server stats. @@ -131,6 +153,11 @@ func initTracing() { log.Warn("could not initialize stackdriver exporter after retrying, giving up") } +func initTracing() { + initJaegerTracing() + initStackDriverTracing() +} + func initProfiling(service, version string) { // TODO(ahmetb) this method is duplicated in other microservices using Go // since they are not sharing packages. From 823e993104bb78d584153d4087e29159bdadb5aa Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Thu, 10 Jan 2019 10:35:17 -0800 Subject: [PATCH 44/91] update skaffold manifest to clear warnings (#117) Signed-off-by: Ahmet Alp Balkan --- .travis.yml | 2 +- skaffold.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 50a839e..124f5dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ services: - docker install: -- curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v0.18.0/skaffold-linux-amd64 +- curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v0.20.0/skaffold-linux-amd64 - chmod +x skaffold - sudo mv skaffold /usr/local/bin diff --git a/skaffold.yaml b/skaffold.yaml index eb2f9c4..5c880dd 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: skaffold/v1alpha5 +apiVersion: skaffold/v1beta2 kind: Config build: artifacts: From aaf2f8717dc3c7ca17b42fea8706f27667c20244 Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Fri, 11 Jan 2019 16:59:27 -0600 Subject: [PATCH 45/91] Simplify package management for python services (#120) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR does a few things: 1. **Removes unnecessary Python dependencies currently being installed for `emailservice`** There are quite a few packages being installed that aren't actual dependencies. 2. **Removes a number of related, also unnecessary system-level dependencies for `emailservice`** These were a result of the Python dependencies that are unnecessary. 3. **Pins all of the sub-dependencies for `loadgenerator`** This is good practice to ensure that things don't break one day in the future when a newer version of an unpinned sub-dependenency is released. 4. **Compile all Python dependencies from `requirements.in` files** This is mostly bookkeeping. It allows us to only specify the top-level dependencies we care about in the requirements.in files, which are then compiled to frozen dependencies in the requirements.txt files. This ensures that we only install the dependencies we need, and that we're not missing any unpinned sub-dependencies. It also makes it more clear where our sub-dependencies are coming from. 5. **Switch to -slim images from -alpine** Python's built distribution format (wheel) is incompatible with alpine-based images, causing dependencies like `grpcio` to be compiled from scratch, rather than from a pre-built wheel. This should improve or possibly fi​x #58, while keeping the image size roughly the same: ``` emailservice latest d1b818eabe05 6 seconds ago 286MB loadgenerator latest 4d9b5acbfbbb 6 seconds ago 125MB ``` --- src/emailservice/Dockerfile | 23 +++-------- src/emailservice/requirements.in | 6 +++ src/emailservice/requirements.txt | 64 ++++++++++++------------------ src/loadgenerator/Dockerfile | 12 ++---- src/loadgenerator/requirements.in | 1 + src/loadgenerator/requirements.txt | 23 ++++++++++- 6 files changed, 64 insertions(+), 65 deletions(-) create mode 100644 src/emailservice/requirements.in create mode 100644 src/loadgenerator/requirements.in diff --git a/src/emailservice/Dockerfile b/src/emailservice/Dockerfile index 0bb5695..b4b2a94 100644 --- a/src/emailservice/Dockerfile +++ b/src/emailservice/Dockerfile @@ -1,21 +1,7 @@ -FROM python:3-alpine as base +FROM python:3-slim as base FROM base as builder -# gRPC and app deps -RUN apk add --update --no-cache \ - gcc \ - linux-headers \ - make \ - musl-dev \ - python-dev \ - g++ \ - # App Deps - cairo-dev \ - cairo \ - openssl-dev \ - gobject-introspection-dev - # get packages COPY requirements.txt . RUN pip install -r requirements.txt @@ -25,6 +11,10 @@ FROM base as final # Enable unbuffered logging ENV PYTHONUNBUFFERED=1 +RUN apt-get -qq update \ + && apt-get install -y --no-install-recommends \ + wget + # Download the grpc health probe RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ @@ -35,9 +25,6 @@ WORKDIR /email_server # Grab packages from builder COPY --from=builder /usr/local/lib/python3.7/ /usr/local/lib/python3.7/ -# Need libstdc++ for grpc -RUN apk add --no-cache libstdc++ - # Add the application COPY . . diff --git a/src/emailservice/requirements.in b/src/emailservice/requirements.in new file mode 100644 index 0000000..fa3f39c --- /dev/null +++ b/src/emailservice/requirements.in @@ -0,0 +1,6 @@ +google-api-core==1.6.0 +grpcio-health-checking==1.12.1 +grpcio==1.16.1 +jinja2==2.10 +opencensus[stackdriver]==0.1.10 +python-json-logger==0.1.9 diff --git a/src/emailservice/requirements.txt b/src/emailservice/requirements.txt index 65e7717..6a763b2 100644 --- a/src/emailservice/requirements.txt +++ b/src/emailservice/requirements.txt @@ -1,41 +1,29 @@ -asn1crypto==0.24.0 -cachetools==2.1.0 -certifi==2018.8.24 -cffi==1.11.5 -chardet==3.0.4 -configparser==3.5.0 -cryptography==2.3.1 -entrypoints==0.2.3 -enum34==1.1.6 -futures==3.1.1 -google-api-core==1.6.0 -google-auth==1.6.1 -google-cloud-core==0.29.0 -googleapis-common-protos==1.5.3 -grpc-google-iam-v1==0.11.4 -grpcio==1.16.1 +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile --output-file requirements.txt requirements.in +# +cachetools==3.0.0 # via google-auth +certifi==2018.11.29 # via requests +chardet==3.0.4 # via requests +google-api-core[grpc]==1.6.0 +google-auth==1.6.2 # via google-api-core +google-cloud-core==0.29.1 # via google-cloud-trace +google-cloud-trace==0.20.2 # via opencensus +googleapis-common-protos==1.5.5 # via google-api-core grpcio-health-checking==1.12.1 -grpcio-tools==1.12.1 -idna==2.7 -ipaddress==1.0.22 -jeepney==0.4 -Jinja2==2.10 -keyring==15.1.0 -keyrings.alt==3.1 -MarkupSafe==1.0 +grpcio==1.16.1 +idna==2.8 # via requests +jinja2==2.10 +markupsafe==1.1.0 # via jinja2 opencensus[stackdriver]==0.1.10 -protobuf==3.6.1 -pyasn1==0.4.4 -pyasn1-modules==0.2.2 -pycairo==1.17.1 -pycparser==2.19 -pycrypto==2.6.1 -PyGObject==3.30.1 +protobuf==3.6.1 # via google-api-core, googleapis-common-protos, grpcio-health-checking +pyasn1-modules==0.2.3 # via google-auth +pyasn1==0.4.5 # via pyasn1-modules, rsa python-json-logger==0.1.9 -pytz==2018.5 -pyxdg==0.26 -requests==2.20.0 -rsa==4.0 -SecretStorage==3.1.0 -six==1.11.0 -urllib3==1.23 +pytz==2018.9 # via google-api-core +requests==2.21.0 # via google-api-core +rsa==4.0 # via google-auth +six==1.12.0 # via google-api-core, google-auth, grpcio, protobuf +urllib3==1.24.1 # via requests diff --git a/src/loadgenerator/Dockerfile b/src/loadgenerator/Dockerfile index b0004cf..cebb98c 100644 --- a/src/loadgenerator/Dockerfile +++ b/src/loadgenerator/Dockerfile @@ -1,14 +1,10 @@ -FROM python:3-alpine as base +FROM python:3-slim as base FROM base as builder -RUN apk add --update --no-cache \ - gcc \ - linux-headers \ - make \ - musl-dev \ - python-dev \ - g++ +RUN apt-get -qq update \ + && apt-get install -y --no-install-recommends \ + g++ COPY requirements.txt . diff --git a/src/loadgenerator/requirements.in b/src/loadgenerator/requirements.in new file mode 100644 index 0000000..0b66c0a --- /dev/null +++ b/src/loadgenerator/requirements.in @@ -0,0 +1 @@ +locustio==0.8.1 diff --git a/src/loadgenerator/requirements.txt b/src/loadgenerator/requirements.txt index fa77c1c..ac69aca 100644 --- a/src/loadgenerator/requirements.txt +++ b/src/loadgenerator/requirements.txt @@ -1,2 +1,23 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile --output-file requirements.txt requirements.in +# +certifi==2018.11.29 # via requests +chardet==3.0.4 # via requests +click==7.0 # via flask +flask==1.0.2 # via locustio +gevent==1.4.0 # via locustio +greenlet==0.4.15 # via gevent +idna==2.8 # via requests +itsdangerous==1.1.0 # via flask +jinja2==2.10 # via flask locustio==0.8.1 -pyzmq==17.0.0 +markupsafe==1.1.0 # via jinja2 +msgpack-python==0.5.6 # via locustio +pyzmq==17.0.0 # via locustio +requests==2.21.0 # via locustio +six==1.12.0 # via locustio +urllib3==1.24.1 # via requests +werkzeug==0.14.1 # via flask From 791a2822ad78c69cf5463ca700df7d346d7557c4 Mon Sep 17 00:00:00 2001 From: Dave Stanke Date: Mon, 14 Jan 2019 11:11:18 -0500 Subject: [PATCH 46/91] Update skaffold to v0.20.0 (to support newer skaffold config) (#123) --- cloudbuild.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudbuild.yaml b/cloudbuild.yaml index bf8aea7..2d031ce 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -11,7 +11,7 @@ steps: - id: 'Deploy application to cluster' - name: 'gcr.io/k8s-skaffold/skaffold:v0.18.0' + name: 'gcr.io/k8s-skaffold/skaffold:v0.20.0' entrypoint: 'bash' args: - '-c' From dcdd657d82440c2ca285448908ae89ad1191ad3e Mon Sep 17 00:00:00 2001 From: Oussema CHERNI Date: Mon, 14 Jan 2019 17:12:52 +0100 Subject: [PATCH 47/91] Fix broken doc link (#122) --- skaffold.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skaffold.yaml b/skaffold.yaml index 5c880dd..d39d561 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -19,7 +19,7 @@ build: # image tags are relative; to specify an image repo (e.g. GCR), you # must provide a "default repo" using one of the methods described # here: - # https://github.com/GoogleContainerTools/skaffold/blob/master/docs/concepts.adoc#2-push + # https://skaffold.dev/docs/concepts/#image-repository-handling - image: emailservice context: src/emailservice - image: productcatalogservice From 8deb49e5ecb2a8f16e02b507a175480a8d788163 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Mon, 14 Jan 2019 14:42:13 -0800 Subject: [PATCH 48/91] Update README.md --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 70b2046..2d285a3 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,11 @@ add them to the cart, and purchase them. **Google uses this application to demonstrate Kubernetes, GKE, Istio, Stackdriver, gRPC, OpenCensus** and similar cloud-native technologies. +> **Note to Googlers:** Please fill out the form at +[go/microservices-demo](http://go/microservices-demo) if you are using this +application. + + ## Screenshots | Home Page | Checkout Screen | @@ -184,8 +189,4 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). --- -**Note to fellow Googlers:** Please fill out the form at -[go/microservices-demo](http://go/microservices-demo) if you are using this -application. - -This is not an official Google project. +This is not an official Google project. From 10dfd04ab174cc680ed6ffef26cc4fb09ec40404 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Tue, 15 Jan 2019 10:14:33 -0800 Subject: [PATCH 49/91] README: use GKE add-on for Istio instructions (#121) I also edited some irrelevant parts of the file, don't mind those. Signed-off-by: Ahmet Alp Balkan --- README.md | 57 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 2d285a3..e6d0828 100644 --- a/README.md +++ b/README.md @@ -80,15 +80,17 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). here](https://docs.docker.com/docker-for-mac/kubernetes/). - [skaffold](https://github.com/GoogleContainerTools/skaffold/#installation) -1. Launch “Docker for Desktop”. Go to Preferences and choose “Enable Kubernetes”. +1. Launch “Docker for Desktop”. Go to Preferences: + - choose “Enable Kubernetes”, + - set CPUs to at least 3, and Memory to at least 6.0 GiB -1. Run `kubectl get nodes` to verify you're connected to “Kubernetes on Docker”. +3. Run `kubectl get nodes` to verify you're connected to “Kubernetes on Docker”. -1. Run `skaffold run` (first time will be slow, it can take ~20-30 minutes). +4. Run `skaffold run` (first time will be slow, it can take ~20-30 minutes). This will build and deploy the application. If you need to rebuild the images automatically as you refactor he code, run `skaffold dev` command. -1. Run `kubectl get pods` to verify the Pods are ready and running. The +5. Run `kubectl get pods` to verify the Pods are ready and running. The application frontend should be available at http://localhost:80 on your machine. @@ -117,16 +119,18 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). 1. In the root of this repository, run `skaffold run --default-repo=gcr.io/[PROJECT_ID]`, where [PROJECT_ID] is your GCP project ID. - + This command: - builds the container images - pushes them to GCR - applies the `./kubernetes-manifests` deploying the application to Kubernetes. - **Troubleshooting:** If you get "No space left on device" error on Google Cloud Shell, - you can build the images on Google Cloud Build: - [Enable the Cloud Build API](https://console.cloud.google.com/flows/enableapi?apiid=cloudbuild.googleapis.com), then run `skaffold run -p gcb --default-repo=gcr.io/[PROJECT_ID]` instead. + **Troubleshooting:** If you get "No space left on device" error on Google + Cloud Shell, you can build the images on Google Cloud Build: [Enable the + Cloud Build + API](https://console.cloud.google.com/flows/enableapi?apiid=cloudbuild.googleapis.com), + then run `skaffold run -p gcb --default-repo=gcr.io/[PROJECT_ID]` instead. 1. Find the IP address of your application, then visit the application on your browser to confirm installation. @@ -139,38 +143,47 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). are seeing this, run `kubectl get service frontend-external -o=yaml | kubectl apply -f-` to trigger load balancer reconfiguration. -### (Optional) Deploying on a Istio-installed cluster +### (Optional) Deploying on a Istio-installed GKE cluster > **Note:** you followed GKE deployment steps above, run `skaffold delete` first > to delete what's deployed. -1. Create a GKE cluster. +1. Create a GKE cluster (described above). -2. Install Istio **without mutual TLS** authentication option. +2. Use [Istio on GKE add-on](https://cloud.google.com/istio/docs/istio-on-gke/installing) + to install Istio to your existing GKE cluster. - > (Optional) If you'd like to enable mTLS in the demo app, you need to - > make a few changes to the deployment manifests: + gcloud beta container clusters update demo \ + --zone=us-central1-a \ + --update-addons=Istio=ENABLED \ + --istio-config=auth=MTLS_PERMISSIVE + + > NOTE: If you need to enable `MTLS_STRICT` mode, you will need to update + > several manifest files: > > - `kubernetes-manifests/frontend.yaml`: delete "livenessProbe" and > "readinessProbe" fields. > - `kubernetes-manifests/loadgenerator.yaml`: delete "initContainers" field. -3. Install the automatic sidecar injection (annotate the `default` namespace +3. (Optional) Enable Stackdriver Tracing/Logging with Istio Stackdriver Adapter + by [following this guide](https://cloud.google.com/istio/docs/istio-on-gke/installing#enabling_tracing_and_logging). + +4. Install the automatic sidecar injection (annotate the `default` namespace with the label): kubectl label namespace default istio-injection=enabled -4. Apply the manifests in [`./istio-manifests`](./istio-manifests) directory. +5. Apply the manifests in [`./istio-manifests`](./istio-manifests) directory. kubectl apply -f ./istio-manifests This is required only once. -5. Deploy the application with `skaffold run --default-repo=gcr.io/[PROJECT_ID]`. +6. Deploy the application with `skaffold run --default-repo=gcr.io/[PROJECT_ID]`. -6. Run `kubectl get pods` to see pods are in a healthy and ready state. +7. Run `kubectl get pods` to see pods are in a healthy and ready state. -7. Find the IP address of your istio gateway Ingress or Service, and visit the +8. Find the IP address of your istio gateway Ingress or Service, and visit the application. INGRESS_HOST="$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')" @@ -179,12 +192,14 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). curl -v "http://$INGRESS_HOST" -## Conferences featuring Hipster Shop +## Conferences featuring Hipster Shop -- [Google Cloud Next'18 London – Keynote](https://youtu.be/nIq2pkNcfEI?t=3071) showing Stackdriver Incident Response Management +- [Google Cloud Next'18 London – Keynote](https://youtu.be/nIq2pkNcfEI?t=3071) + showing Stackdriver Incident Response Management - Google Cloud Next'18 SF - [Day 1 Keynote](https://youtu.be/vJ9OaAqfxo4?t=2416) showing GKE On-Prem - - [Day 3 – Keynote](https://youtu.be/JQPOPV_VH5w?t=815) showing Stackdriver APM (Tracing, Code Search, Profiler, Google Cloud Build) + - [Day 3 – Keynote](https://youtu.be/JQPOPV_VH5w?t=815) showing Stackdriver + APM (Tracing, Code Search, Profiler, Google Cloud Build) - [Introduction to Service Management with Istio](https://www.youtube.com/watch?v=wCJrdKdD6UM&feature=youtu.be&t=586) --- From 54f0a8d058663a1a9b6060bcdd744eecd2259963 Mon Sep 17 00:00:00 2001 From: rghetia Date: Tue, 22 Jan 2019 09:56:39 -0800 Subject: [PATCH 50/91] add jaeger support for productcatalog and shipping. (#126) --- .../productcatalogservice.yaml | 3 + kubernetes-manifests/shippingservice.yaml | 3 + src/frontend/main.go | 22 +-- src/productcatalogservice/Gopkg.lock | 148 ++++++++++++++---- src/productcatalogservice/server.go | 30 +++- src/shippingservice/Gopkg.lock | 141 +++++++++++++---- src/shippingservice/main.go | 30 +++- 7 files changed, 299 insertions(+), 78 deletions(-) diff --git a/kubernetes-manifests/productcatalogservice.yaml b/kubernetes-manifests/productcatalogservice.yaml index f6a15cd..54416d6 100644 --- a/kubernetes-manifests/productcatalogservice.yaml +++ b/kubernetes-manifests/productcatalogservice.yaml @@ -34,6 +34,9 @@ spec: livenessProbe: exec: command: ["/bin/grpc_health_probe", "-addr=:3550"] +# env: +# - name: JAEGER_SERVICE_ADDR +# value: "jaeger-collector:14268" resources: requests: cpu: 100m diff --git a/kubernetes-manifests/shippingservice.yaml b/kubernetes-manifests/shippingservice.yaml index f0b0dae..9213e58 100644 --- a/kubernetes-manifests/shippingservice.yaml +++ b/kubernetes-manifests/shippingservice.yaml @@ -34,6 +34,9 @@ spec: livenessProbe: exec: command: ["/bin/grpc_health_probe", "-addr=:50051"] +# env: +# - name: JAEGER_SERVICE_ADDR +# value: "jaeger-collector:14268" resources: requests: cpu: 100m diff --git a/src/frontend/main.go b/src/frontend/main.go index 61ac8ce..9a19f2e 100644 --- a/src/frontend/main.go +++ b/src/frontend/main.go @@ -181,15 +181,7 @@ func initStats(log logrus.FieldLogger, exporter *stackdriver.Exporter) { } } -func initTracing(log logrus.FieldLogger) { - // This is a demo app with low QPS. trace.AlwaysSample() is used here - // to make sure traces are available for observation and analysis. - // In a production environment or high QPS setup please use - // trace.ProbabilitySampler set at the desired probability. - trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) - - initJaegerTracing(log) - +func initStackDriverTracing(log logrus.FieldLogger) { // TODO(ahmetb) this method is duplicated in other microservices using Go // since they are not sharing packages. for i := 1; i <= 3; i++ { @@ -215,6 +207,18 @@ func initTracing(log logrus.FieldLogger) { log.Warn("could not initialize stackdriver exporter after retrying, giving up") } +func initTracing(log logrus.FieldLogger) { + // This is a demo app with low QPS. trace.AlwaysSample() is used here + // to make sure traces are available for observation and analysis. + // In a production environment or high QPS setup please use + // trace.ProbabilitySampler set at the desired probability. + trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) + + initJaegerTracing(log) + initStackDriverTracing(log) + +} + func initProfiling(log logrus.FieldLogger, service, version string) { // TODO(ahmetb) this method is duplicated in other microservices using Go // since they are not sharing packages. diff --git a/src/productcatalogservice/Gopkg.lock b/src/productcatalogservice/Gopkg.lock index e1c01e0..9e3a02b 100644 --- a/src/productcatalogservice/Gopkg.lock +++ b/src/productcatalogservice/Gopkg.lock @@ -2,27 +2,46 @@ [[projects]] + digest = "1:467af0aad47996b25b838d6f14c8371123a8a76ec239020a6c5894e1f8f60272" name = "cloud.google.com/go" packages = [ "compute/metadata", "internal/version", "monitoring/apiv3", "profiler", - "trace/apiv2" + "trace/apiv2", ] + pruneopts = "UT" revision = "c728a003b238b26cef9ab6753a5dc424b331c3ad" version = "v0.27.0" [[projects]] + digest = "1:4b96dcd8534bc6450a922bd16a76360ba3381f0d1daf40abbaec91c053fbfeb5" name = "contrib.go.opencensus.io/exporter/stackdriver" - packages = [ - ".", - "propagation" - ] + packages = ["."] + pruneopts = "UT" revision = "37aa2801fbf0205003e15636096ebf0373510288" version = "v0.5.0" [[projects]] + branch = "master" + digest = "1:d3a57cdbaefaceca4ebe6258ed86a992bdcfc93a8442dbda5343e2d43a8f8a6a" + name = "git.apache.org/thrift.git" + packages = ["lib/go/thrift"] + pruneopts = "UT" + revision = "67df34afa782be67154034b31e4ad7cb3834fed1" + source = "github.com/apache/thrift" + +[[projects]] + branch = "master" + digest = "1:14e66208d324c0ecb49934b5ac311c50a94e3a458e92b0026ef9e26919ac8d9d" + name = "github.com/GoogleCloudPlatform/microservices-demo" + packages = ["src/productcatalogservice/genproto"] + pruneopts = "UT" + revision = "10dfd04ab174cc680ed6ffef26cc4fb09ec40404" + +[[projects]] + digest = "1:4fbf68bee2a60f6af6414572936edb295f6f26b73c6fb25ab0e7b03b013854f5" name = "github.com/golang/protobuf" packages = [ "jsonpb", @@ -34,46 +53,67 @@ "ptypes/empty", "ptypes/struct", "ptypes/timestamp", - "ptypes/wrappers" + "ptypes/wrappers", ] + pruneopts = "UT" revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" version = "v1.2.0" [[projects]] + digest = "1:2e3c336fc7fde5c984d2841455a658a6d626450b1754a854b3b32e7a8f49a07a" name = "github.com/google/go-cmp" packages = [ "cmp", "cmp/internal/diff", "cmp/internal/function", - "cmp/internal/value" + "cmp/internal/value", ] + pruneopts = "UT" revision = "3af367b6b30c263d47e8895973edcca9a49cf029" version = "v0.2.0" [[projects]] branch = "master" + digest = "1:fc55304e290027108ae0cac675a171bcd854f9c657678c20ceea837718ea6819" name = "github.com/google/pprof" packages = ["profile"] - revision = "e027b505a088ac3c68c339a1d7ce7724bf34538b" + pruneopts = "UT" + revision = "e84dfd68c163c45ea47aa24b3dc7eaa93f6675b1" [[projects]] + digest = "1:cd9864c6366515827a759931746738ede6079faa08df9c584596370d6add135c" name = "github.com/googleapis/gax-go" - packages = ["."] - revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f" - version = "v2.0.0" + packages = [ + ".", + "v2", + ] + pruneopts = "UT" + revision = "c8a15bac9b9fe955bd9f900272f9a306465d28cf" + version = "v2.0.3" [[projects]] - digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc" + digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8" + name = "github.com/konsorten/go-windows-terminal-sequences" + packages = ["."] + pruneopts = "UT" + revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242" + version = "v1.0.1" + +[[projects]] + digest = "1:87c2e02fb01c27060ccc5ba7c5a407cc91147726f8f40b70cceeedbc52b1f3a8" name = "github.com/sirupsen/logrus" packages = ["."] pruneopts = "UT" - revision = "3e01752db0189b9157070a0e1668a620f9a85da2" - version = "v1.0.6" + revision = "e1e72e9de974bd926e5c56f83753fba2df402ce5" + version = "v1.3.0" [[projects]] + digest = "1:a5154dfd6b37bef5a3eab759e13296348e639dc8c7604f538368167782b08ccd" name = "go.opencensus.io" packages = [ ".", + "exporter/jaeger", + "exporter/jaeger/internal/gen-go/jaeger", "internal", "internal/tagencoding", "plugin/ocgrpc", @@ -86,21 +126,23 @@ "trace", "trace/internal", "trace/propagation", - "trace/tracestate" + "trace/tracestate", ] + pruneopts = "UT" revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89" version = "v0.16.0" [[projects]] branch = "master" - digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8" + digest = "1:38f553aff0273ad6f367cb0a0f8b6eecbaef8dc6cb8b50e57b6a81c1d5b1e332" name = "golang.org/x/crypto" packages = ["ssh/terminal"] pruneopts = "UT" - revision = "0e37d006457bf46f9e6692014ba72ef82c33022c" + revision = "ff983b9c42bc9fbf91556e191cc8efb585c16908" [[projects]] branch = "master" + digest = "1:9d2f08c64693fbe7177b5980f80c35672c80f12be79bb3bc86948b934d70e4ee" name = "golang.org/x/net" packages = [ "context", @@ -110,35 +152,46 @@ "http2/hpack", "idna", "internal/timeseries", - "trace" + "trace", ] - revision = "26e67e76b6c3f6ce91f7c52def5af501b4e0f3a2" + pruneopts = "UT" + revision = "ed066c81e75eba56dd9bd2139ade88125b855585" [[projects]] branch = "master" + digest = "1:511a6232760c10dcb1ebf1ab83ef0291e2baf801f203ca6314759c5458b73a6a" name = "golang.org/x/oauth2" packages = [ ".", "google", "internal", "jws", - "jwt" + "jwt", ] - revision = "d2e6202438beef2727060aa7cabdd924d92ebfd9" + pruneopts = "UT" + revision = "5dab4167f31cbd76b407f1486c86b40748bc5073" [[projects]] branch = "master" + digest = "1:75515eedc0dc2cb0b40372008b616fa2841d831c63eedd403285ff286c593295" name = "golang.org/x/sync" packages = ["semaphore"] - revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca" + pruneopts = "UT" + revision = "37e7f081c4d4c64e13b10787722085407fe5d15f" [[projects]] branch = "master" + digest = "1:43cde116ff48f299eddb7e6515677e6d0a2c915854bb05a333877f07c3bb3033" name = "golang.org/x/sys" - packages = ["unix"] - revision = "1561086e645b2809fb9f8a1e2a38160bf8d53bf4" + packages = [ + "unix", + "windows", + ] + pruneopts = "UT" + revision = "11f53e03133963fb11ae0588e08b5e0b85be8be5" [[projects]] + digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" name = "golang.org/x/text" packages = [ "collate", @@ -154,13 +207,15 @@ "unicode/bidi", "unicode/cldr", "unicode/norm", - "unicode/rangetable" + "unicode/rangetable", ] + pruneopts = "UT" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] branch = "master" + digest = "1:26a71f62c83707b9952821c2a895bd041588501fa370cc267221817fcc721253" name = "google.golang.org/api" packages = [ "googleapi/transport", @@ -170,11 +225,14 @@ "support/bundler", "transport", "transport/grpc", - "transport/http" + "transport/http", + "transport/http/internal/propagation", ] - revision = "19ff8768a5c0b8e46ea281065664787eefc24121" + pruneopts = "UT" + revision = "43037ff31f6958582e5d3c19d9ac1a4d2819669c" [[projects]] + digest = "1:c4eaa5f79d36f76ef4bd0c4f96e36bc1b7b5a359528d1267f0cb7a5d58b7b5bb" name = "google.golang.org/appengine" packages = [ ".", @@ -188,13 +246,15 @@ "internal/socket", "internal/urlfetch", "socket", - "urlfetch" + "urlfetch", ] - revision = "ae0ab99deb4dc413a2b4bd6c8bdd0eb67f1e4d06" - version = "v1.2.0" + pruneopts = "UT" + revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1" + version = "v1.4.0" [[projects]] branch = "master" + digest = "1:3552e7267a98c605e6cbfe6b03c34589265ab72e6078b95fb2e10e0cb44f5cc8" name = "google.golang.org/genproto" packages = [ "googleapis/api/annotations", @@ -207,11 +267,13 @@ "googleapis/monitoring/v3", "googleapis/rpc/errdetails", "googleapis/rpc/status", - "protobuf/field_mask" + "protobuf/field_mask", ] - revision = "c3f76f3b92d1ffa4c58a9ff842a58b8877655e0f" + pruneopts = "UT" + revision = "db91494dd46c1fdcbbde05e5ff5eb56df8f7d79a" [[projects]] + digest = "1:6497ab07ec89179db8d5a563d33635be04ceffaa29007a3ae74b9f15f4d3068e" name = "google.golang.org/grpc" packages = [ ".", @@ -241,14 +303,32 @@ "resolver/passthrough", "stats", "status", - "tap" + "tap", ] + pruneopts = "UT" revision = "32fb0ac620c32ba40a4626ddf94d90d12cce3455" version = "v1.14.0" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "b68fd9438c2eb711d9fc51c1f23c5ca0d5169bf4022351dfc400cd35ba39dfaa" + input-imports = [ + "cloud.google.com/go/profiler", + "contrib.go.opencensus.io/exporter/stackdriver", + "github.com/GoogleCloudPlatform/microservices-demo/src/productcatalogservice/genproto", + "github.com/golang/protobuf/jsonpb", + "github.com/golang/protobuf/proto", + "github.com/google/go-cmp/cmp", + "github.com/sirupsen/logrus", + "go.opencensus.io/exporter/jaeger", + "go.opencensus.io/plugin/ocgrpc", + "go.opencensus.io/stats/view", + "go.opencensus.io/trace", + "golang.org/x/net/context", + "google.golang.org/grpc", + "google.golang.org/grpc/codes", + "google.golang.org/grpc/health/grpc_health_v1", + "google.golang.org/grpc/status", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/src/productcatalogservice/server.go b/src/productcatalogservice/server.go index 0fc929f..4fb7018 100644 --- a/src/productcatalogservice/server.go +++ b/src/productcatalogservice/server.go @@ -35,6 +35,7 @@ import ( "contrib.go.opencensus.io/exporter/stackdriver" "github.com/golang/protobuf/jsonpb" "github.com/sirupsen/logrus" + "go.opencensus.io/exporter/jaeger" "go.opencensus.io/plugin/ocgrpc" "go.opencensus.io/stats/view" "go.opencensus.io/trace" @@ -110,6 +111,28 @@ func run(port int) string { return l.Addr().String() } +func initJaegerTracing() { + svcAddr := os.Getenv("JAEGER_SERVICE_ADDR") + if svcAddr == "" { + log.Info("jaeger initialization disabled.") + return + } + + // Register the Jaeger exporter to be able to retrieve + // the collected spans. + exporter, err := jaeger.NewExporter(jaeger.Options{ + Endpoint: fmt.Sprintf("http://%s", svcAddr), + Process: jaeger.Process{ + ServiceName: "productcatalogservice", + }, + }) + if err != nil { + log.Fatal(err) + } + trace.RegisterExporter(exporter) + log.Info("jaeger initialization completed.") +} + func initStats(exporter *stackdriver.Exporter) { view.SetReportingPeriod(60 * time.Second) view.RegisterExporter(exporter) @@ -120,7 +143,7 @@ func initStats(exporter *stackdriver.Exporter) { } } -func initTracing() { +func initStackDriverTracing() { // TODO(ahmetb) this method is duplicated in other microservices using Go // since they are not sharing packages. for i := 1; i <= 3; i++ { @@ -143,6 +166,11 @@ func initTracing() { log.Warn("could not initialize stackdriver exporter after retrying, giving up") } +func initTracing() { + initJaegerTracing() + initStackDriverTracing() +} + func initProfiling(service, version string) { // TODO(ahmetb) this method is duplicated in other microservices using Go // since they are not sharing packages. diff --git a/src/shippingservice/Gopkg.lock b/src/shippingservice/Gopkg.lock index 9250ec1..d190836 100644 --- a/src/shippingservice/Gopkg.lock +++ b/src/shippingservice/Gopkg.lock @@ -2,27 +2,46 @@ [[projects]] + digest = "1:467af0aad47996b25b838d6f14c8371123a8a76ec239020a6c5894e1f8f60272" name = "cloud.google.com/go" packages = [ "compute/metadata", "internal/version", "monitoring/apiv3", "profiler", - "trace/apiv2" + "trace/apiv2", ] + pruneopts = "UT" revision = "c728a003b238b26cef9ab6753a5dc424b331c3ad" version = "v0.27.0" [[projects]] + digest = "1:4b96dcd8534bc6450a922bd16a76360ba3381f0d1daf40abbaec91c053fbfeb5" name = "contrib.go.opencensus.io/exporter/stackdriver" - packages = [ - ".", - "propagation" - ] + packages = ["."] + pruneopts = "UT" revision = "37aa2801fbf0205003e15636096ebf0373510288" version = "v0.5.0" [[projects]] + branch = "master" + digest = "1:d3a57cdbaefaceca4ebe6258ed86a992bdcfc93a8442dbda5343e2d43a8f8a6a" + name = "git.apache.org/thrift.git" + packages = ["lib/go/thrift"] + pruneopts = "UT" + revision = "67df34afa782be67154034b31e4ad7cb3834fed1" + source = "github.com/apache/thrift" + +[[projects]] + branch = "master" + digest = "1:27490301253ac5063d502480ef3794b95222eea6cb997ae6e689a058b1cd5253" + name = "github.com/GoogleCloudPlatform/microservices-demo" + packages = ["src/shippingservice/genproto"] + pruneopts = "UT" + revision = "10dfd04ab174cc680ed6ffef26cc4fb09ec40404" + +[[projects]] + digest = "1:72856926f8208767b837bf51e3373f49139f61889b67dc7fd3c2a0fd711e3f7a" name = "github.com/golang/protobuf" packages = [ "proto", @@ -33,35 +52,54 @@ "ptypes/empty", "ptypes/struct", "ptypes/timestamp", - "ptypes/wrappers" + "ptypes/wrappers", ] + pruneopts = "UT" revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" version = "v1.2.0" [[projects]] branch = "master" + digest = "1:fc55304e290027108ae0cac675a171bcd854f9c657678c20ceea837718ea6819" name = "github.com/google/pprof" packages = ["profile"] - revision = "e027b505a088ac3c68c339a1d7ce7724bf34538b" + pruneopts = "UT" + revision = "e84dfd68c163c45ea47aa24b3dc7eaa93f6675b1" [[projects]] + digest = "1:cd9864c6366515827a759931746738ede6079faa08df9c584596370d6add135c" name = "github.com/googleapis/gax-go" - packages = ["."] - revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f" - version = "v2.0.0" + packages = [ + ".", + "v2", + ] + pruneopts = "UT" + revision = "c8a15bac9b9fe955bd9f900272f9a306465d28cf" + version = "v2.0.3" [[projects]] - digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc" + digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8" + name = "github.com/konsorten/go-windows-terminal-sequences" + packages = ["."] + pruneopts = "UT" + revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242" + version = "v1.0.1" + +[[projects]] + digest = "1:87c2e02fb01c27060ccc5ba7c5a407cc91147726f8f40b70cceeedbc52b1f3a8" name = "github.com/sirupsen/logrus" packages = ["."] pruneopts = "UT" - revision = "3e01752db0189b9157070a0e1668a620f9a85da2" - version = "v1.0.6" + revision = "e1e72e9de974bd926e5c56f83753fba2df402ce5" + version = "v1.3.0" [[projects]] + digest = "1:a5154dfd6b37bef5a3eab759e13296348e639dc8c7604f538368167782b08ccd" name = "go.opencensus.io" packages = [ ".", + "exporter/jaeger", + "exporter/jaeger/internal/gen-go/jaeger", "internal", "internal/tagencoding", "plugin/ocgrpc", @@ -74,21 +112,23 @@ "trace", "trace/internal", "trace/propagation", - "trace/tracestate" + "trace/tracestate", ] + pruneopts = "UT" revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89" version = "v0.16.0" [[projects]] branch = "master" - digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8" + digest = "1:38f553aff0273ad6f367cb0a0f8b6eecbaef8dc6cb8b50e57b6a81c1d5b1e332" name = "golang.org/x/crypto" packages = ["ssh/terminal"] pruneopts = "UT" - revision = "0e37d006457bf46f9e6692014ba72ef82c33022c" + revision = "ff983b9c42bc9fbf91556e191cc8efb585c16908" [[projects]] branch = "master" + digest = "1:9d2f08c64693fbe7177b5980f80c35672c80f12be79bb3bc86948b934d70e4ee" name = "golang.org/x/net" packages = [ "context", @@ -98,35 +138,46 @@ "http2/hpack", "idna", "internal/timeseries", - "trace" + "trace", ] - revision = "26e67e76b6c3f6ce91f7c52def5af501b4e0f3a2" + pruneopts = "UT" + revision = "ed066c81e75eba56dd9bd2139ade88125b855585" [[projects]] branch = "master" + digest = "1:511a6232760c10dcb1ebf1ab83ef0291e2baf801f203ca6314759c5458b73a6a" name = "golang.org/x/oauth2" packages = [ ".", "google", "internal", "jws", - "jwt" + "jwt", ] - revision = "d2e6202438beef2727060aa7cabdd924d92ebfd9" + pruneopts = "UT" + revision = "5dab4167f31cbd76b407f1486c86b40748bc5073" [[projects]] branch = "master" + digest = "1:75515eedc0dc2cb0b40372008b616fa2841d831c63eedd403285ff286c593295" name = "golang.org/x/sync" packages = ["semaphore"] - revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca" + pruneopts = "UT" + revision = "37e7f081c4d4c64e13b10787722085407fe5d15f" [[projects]] branch = "master" + digest = "1:43cde116ff48f299eddb7e6515677e6d0a2c915854bb05a333877f07c3bb3033" name = "golang.org/x/sys" - packages = ["unix"] - revision = "1561086e645b2809fb9f8a1e2a38160bf8d53bf4" + packages = [ + "unix", + "windows", + ] + pruneopts = "UT" + revision = "11f53e03133963fb11ae0588e08b5e0b85be8be5" [[projects]] + digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" name = "golang.org/x/text" packages = [ "collate", @@ -142,13 +193,15 @@ "unicode/bidi", "unicode/cldr", "unicode/norm", - "unicode/rangetable" + "unicode/rangetable", ] + pruneopts = "UT" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] branch = "master" + digest = "1:26a71f62c83707b9952821c2a895bd041588501fa370cc267221817fcc721253" name = "google.golang.org/api" packages = [ "googleapi/transport", @@ -158,11 +211,14 @@ "support/bundler", "transport", "transport/grpc", - "transport/http" + "transport/http", + "transport/http/internal/propagation", ] - revision = "19ff8768a5c0b8e46ea281065664787eefc24121" + pruneopts = "UT" + revision = "43037ff31f6958582e5d3c19d9ac1a4d2819669c" [[projects]] + digest = "1:c4eaa5f79d36f76ef4bd0c4f96e36bc1b7b5a359528d1267f0cb7a5d58b7b5bb" name = "google.golang.org/appengine" packages = [ ".", @@ -176,13 +232,15 @@ "internal/socket", "internal/urlfetch", "socket", - "urlfetch" + "urlfetch", ] - revision = "ae0ab99deb4dc413a2b4bd6c8bdd0eb67f1e4d06" - version = "v1.2.0" + pruneopts = "UT" + revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1" + version = "v1.4.0" [[projects]] branch = "master" + digest = "1:3552e7267a98c605e6cbfe6b03c34589265ab72e6078b95fb2e10e0cb44f5cc8" name = "google.golang.org/genproto" packages = [ "googleapis/api/annotations", @@ -195,11 +253,13 @@ "googleapis/monitoring/v3", "googleapis/rpc/errdetails", "googleapis/rpc/status", - "protobuf/field_mask" + "protobuf/field_mask", ] - revision = "c3f76f3b92d1ffa4c58a9ff842a58b8877655e0f" + pruneopts = "UT" + revision = "db91494dd46c1fdcbbde05e5ff5eb56df8f7d79a" [[projects]] + digest = "1:f3fea5ef1fb1f632ae0dd9a86af6aa2048f3243d1da0075706fca1def38d9fbb" name = "google.golang.org/grpc" packages = [ ".", @@ -231,14 +291,29 @@ "resolver/passthrough", "stats", "status", - "tap" + "tap", ] + pruneopts = "UT" revision = "32fb0ac620c32ba40a4626ddf94d90d12cce3455" version = "v1.14.0" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "5dac84cd5efcc89491aa3cda06a774c1b370c8e0cbdb99668cbfd8ba27b3e32c" + input-imports = [ + "cloud.google.com/go/profiler", + "contrib.go.opencensus.io/exporter/stackdriver", + "github.com/GoogleCloudPlatform/microservices-demo/src/shippingservice/genproto", + "github.com/golang/protobuf/proto", + "github.com/sirupsen/logrus", + "go.opencensus.io/exporter/jaeger", + "go.opencensus.io/plugin/ocgrpc", + "go.opencensus.io/stats/view", + "go.opencensus.io/trace", + "golang.org/x/net/context", + "google.golang.org/grpc", + "google.golang.org/grpc/health/grpc_health_v1", + "google.golang.org/grpc/reflection", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/src/shippingservice/main.go b/src/shippingservice/main.go index 523731c..ea324fe 100644 --- a/src/shippingservice/main.go +++ b/src/shippingservice/main.go @@ -23,6 +23,7 @@ import ( "cloud.google.com/go/profiler" "contrib.go.opencensus.io/exporter/stackdriver" "github.com/sirupsen/logrus" + "go.opencensus.io/exporter/jaeger" "go.opencensus.io/plugin/ocgrpc" "go.opencensus.io/stats/view" "go.opencensus.io/trace" @@ -128,6 +129,28 @@ func (s *server) ShipOrder(ctx context.Context, in *pb.ShipOrderRequest) (*pb.Sh }, nil } +func initJaegerTracing() { + svcAddr := os.Getenv("JAEGER_SERVICE_ADDR") + if svcAddr == "" { + log.Info("jaeger initialization disabled.") + return + } + + // Register the Jaeger exporter to be able to retrieve + // the collected spans. + exporter, err := jaeger.NewExporter(jaeger.Options{ + Endpoint: fmt.Sprintf("http://%s", svcAddr), + Process: jaeger.Process{ + ServiceName: "shippingservice", + }, + }) + if err != nil { + log.Fatal(err) + } + trace.RegisterExporter(exporter) + log.Info("jaeger initialization completed.") +} + func initStats(exporter *stackdriver.Exporter) { view.SetReportingPeriod(60 * time.Second) view.RegisterExporter(exporter) @@ -138,7 +161,7 @@ func initStats(exporter *stackdriver.Exporter) { } } -func initTracing() { +func initStackDriverTracing() { // TODO(ahmetb) this method is duplicated in other microservices using Go // since they are not sharing packages. for i := 1; i <= 3; i++ { @@ -161,6 +184,11 @@ func initTracing() { log.Warn("could not initialize stackdriver exporter after retrying, giving up") } +func initTracing() { + initJaegerTracing() + initStackDriverTracing() +} + func initProfiling(service, version string) { // TODO(ahmetb) this method is duplicated in other microservices using Go // since they are not sharing packages. From 2ef073f6009783049a5feb8628e0797c7053319b Mon Sep 17 00:00:00 2001 From: sebright Date: Tue, 22 Jan 2019 09:56:50 -0800 Subject: [PATCH 51/91] adservice: Add "time" field to JSON log entries. (#129) The Log4j JsonLayout puts the log entry timestamp in a field named "instant" by default, but the Stackdriver Logging agent does not understand that field. The logging agent instead uses the time that it received the log entry, which is less accurate and has only second-level precision. This commit adds a key-value pair to the JsonLayout pattern that can be understood by the logging agent. It uses a "time" key as described in https://cloud.google.com/logging/docs/agent/configuration#timestamp-processing and formats the timestamp as described in the Protocol Buffer JSON mapping, https://developers.google.com/protocol-buffers/docs/proto3#json. Allowing the Stackdriver Logging agent to read the more accurate timestamps inserted by Log4j is especially important in the adservice, because the logs are correlated with traces, and it is important to see where each message was logged on the timeline of the trace. --- src/adservice/src/main/resources/log4j2.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/adservice/src/main/resources/log4j2.xml b/src/adservice/src/main/resources/log4j2.xml index 177c483..9d85f97 100644 --- a/src/adservice/src/main/resources/log4j2.xml +++ b/src/adservice/src/main/resources/log4j2.xml @@ -3,12 +3,14 @@ - + + From 3812cf741da92bf4c4140f26b8ede047b69e0732 Mon Sep 17 00:00:00 2001 From: rghetia Date: Tue, 22 Jan 2019 10:37:03 -0800 Subject: [PATCH 52/91] fix typo in Stackdriver init method name. (#130) --- src/frontend/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/main.go b/src/frontend/main.go index 9a19f2e..a6bccda 100644 --- a/src/frontend/main.go +++ b/src/frontend/main.go @@ -181,7 +181,7 @@ func initStats(log logrus.FieldLogger, exporter *stackdriver.Exporter) { } } -func initStackDriverTracing(log logrus.FieldLogger) { +func initStackdriverTracing(log logrus.FieldLogger) { // TODO(ahmetb) this method is duplicated in other microservices using Go // since they are not sharing packages. for i := 1; i <= 3; i++ { @@ -215,7 +215,7 @@ func initTracing(log logrus.FieldLogger) { trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) initJaegerTracing(log) - initStackDriverTracing(log) + initStackdriverTracing(log) } From ea424cb9f7a23f69d0ce1b7793c28ec6660550df Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Tue, 22 Jan 2019 12:30:30 -0800 Subject: [PATCH 53/91] add skaffold version note Fixes #127 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e6d0828..a6476dc 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). - Docker for Desktop (Mac/Windows): It provides Kubernetes support as [noted here](https://docs.docker.com/docker-for-mac/kubernetes/). - [skaffold](https://github.com/GoogleContainerTools/skaffold/#installation) + (ensure version ≥v0.20) 1. Launch “Docker for Desktop”. Go to Preferences: - choose “Enable Kubernetes”, From 1d452f449a56608e72d88372ae47b8dce9e364c8 Mon Sep 17 00:00:00 2001 From: Megan O'Keefe <3137106+m-okeefe@users.noreply.github.com> Date: Tue, 29 Jan 2019 11:23:33 -0800 Subject: [PATCH 54/91] Adds make-release script, static k8s manifests (#132) Closes #75. ### Changelog Adds 4 scripts to the `hack/` directory for building/pushing images, injecting images tags into static manifests, and tagging new releases. See [hack/README.md](https://github.com/m-okeefe/microservices-demo/tree/release-script/hack). **Note**: since we have not pushed images yet, the images in the `./release/` manifests are still set to the skaffold defaults (eg. `adservice`). --- README.md | 17 ++++++++++- hack/README.md | 18 +++++++++++ hack/make-docker-images.sh | 39 ++++++++++++++++++++++++ hack/make-release-artifacts.sh | 55 ++++++++++++++++++++++++++++++++++ hack/make-release.sh | 41 +++++++++++++++++++++++++ release/.googleheader | 13 ++++++++ 6 files changed, 182 insertions(+), 1 deletion(-) create mode 100755 hack/README.md create mode 100755 hack/make-docker-images.sh create mode 100755 hack/make-release-artifacts.sh create mode 100755 hack/make-release.sh create mode 100644 release/.googleheader diff --git a/README.md b/README.md index a6476dc..a603b4c 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,21 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). are seeing this, run `kubectl get service frontend-external -o=yaml | kubectl apply -f-` to trigger load balancer reconfiguration. +### Option 3: Using Static Images + +> 💡 Recommended for test-driving the application on an existing cluster. + +**Prerequisite**: a running Kubernetes cluster. + +1. Clone this repository. +1. Deploy the application: `kubectl apply -f ./release/kubernetes-manifests` +1. Run `kubectl get pods` to see pods are in a healthy and ready state. +1. Find the IP address of your application, then visit the application on your + browser to confirm installation. + + kubectl get service frontend-external + + ### (Optional) Deploying on a Istio-installed GKE cluster > **Note:** you followed GKE deployment steps above, run `skaffold delete` first @@ -205,4 +220,4 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). --- -This is not an official Google project. +This is not an official Google project. \ No newline at end of file diff --git a/hack/README.md b/hack/README.md new file mode 100755 index 0000000..41d89df --- /dev/null +++ b/hack/README.md @@ -0,0 +1,18 @@ +## `hack/` + +This directory provides scripts for building and pushing Docker images, and tagging new demo +releases. + +### env variables + +- `TAG` - git release tag / Docker tag. +- `REPO_PREFIX` - Docker repo prefix to push images. Format: `$user/$project`. Resulting images will be of the + format `$user/$project/$svcname:$tag` (where `svcname` = `adservice`, `cartservice`, + etc.) + +### scripts + +1. `./make-docker-images.sh`: builds and pushes images to the specified Docker repository. +2. `./make-release-artifacts.sh`: generates a combined YAML file with image $TAG at: + `./release/kubernetes-manifests/demo.yaml`. +3. `./make-release.sh`: runs scripts 1 and 2, then runs `git tag` / pushes updated manifests to master. diff --git a/hack/make-docker-images.sh b/hack/make-docker-images.sh new file mode 100755 index 0000000..51a8e10 --- /dev/null +++ b/hack/make-docker-images.sh @@ -0,0 +1,39 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Builds and pushes docker image for each demo microservice. + +#!/usr/bin/env bash +set -euo pipefail + +log() { echo "$1" >&2; } +fail() { log "$1"; exit 1; } + +TAG="${TAG?TAG env variable must be specified}" +REPO_PREFIX="${REPO_PREFIX?REPO_PREFIX env variable must be specified}" + + +for dir in ./src/*/ +do + # build image + svcname="$(basename $dir)" + image="$REPO_PREFIX/$svcname:$TAG" + echo "Building and pushing $image..." + docker build -t $image -f $dir/Dockerfile $dir + + # push image + docker push $image +done + +log "Successfully built and pushed images." diff --git a/hack/make-release-artifacts.sh b/hack/make-release-artifacts.sh new file mode 100755 index 0000000..1479f8a --- /dev/null +++ b/hack/make-release-artifacts.sh @@ -0,0 +1,55 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# injects new image/tag into the images in ./release/kubernetes-manifests/demo.yaml + +#!/usr/bin/env bash +set -euo pipefail + +log() { echo "$1" >&2; } +fail() { log "$1"; exit 1; } + +TAG="${TAG?TAG env variable must be specified}" +REPO_PREFIX="${REPO_PREFIX?REPO_PREFIX env variable must be specified}" + +# overwrite release/ with the latest manifests, adding "---" separator. +src="./kubernetes-manifests/*" +manifestfile="./release/kubernetes-manifests/demo.yaml" +tmp="./release/kubernetes-manifests/tmp.yaml" +[ -e $manifestfile ] && rm $manifestfile +for f in $src; do (cat "${f}"; echo "---") >> $tmp; done + +# remove extra google headers +gsed -i '/^#/d' $tmp + +# remove empty lines +gsed -r -i '/^\s*$/d' $tmp + +# add 1 google header to the top +cat "./release/.googleheader" $tmp > $manifestfile +rm $tmp + + +# replace image repo, tag for each deployment +for dir in ./src/*/ +do + svcname="$(basename $dir)" + image="$REPO_PREFIX/$svcname:$TAG" + + pattern="^(\s*)image:\s.*$svcname(.*)(\s*)" + replace="\1image: $image\3" + gsed -r -i "s|$pattern|$replace|g" $manifestfile +done + +log "Successfully added image tags > wrote to demo.yaml". diff --git a/hack/make-release.sh b/hack/make-release.sh new file mode 100755 index 0000000..1eb8bce --- /dev/null +++ b/hack/make-release.sh @@ -0,0 +1,41 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Creates a new release by 1) building/pushing images, 2) injecting tag into YAML, +# 3) creating a new git tag, and 4) pushing tags/updated YAML to $BRANCH. + +#!/usr/bin/env bash +set -euo pipefail + +log() { echo "$1" >&2; } +fail() { log "$1"; exit 1; } + +TAG="${TAG?TAG env variable must be specified}" +REPO_PREFIX="${REPO_PREFIX?REPO_PREFIX env variable must be specified}" + +# build and push images +./hack/make-docker-images.sh + +# update yaml +./hack/make-release-artifacts.sh + +# create git release / push to master +log "Pushing k8s manifests to master..." +git tag "$TAG" +git add release/ +git commit --allow-empty -m "Release $TAG" +git push --tags +git push origin master + +log "Successfully tagged release $TAG." diff --git a/release/.googleheader b/release/.googleheader new file mode 100644 index 0000000..ddd71c0 --- /dev/null +++ b/release/.googleheader @@ -0,0 +1,13 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. From 3da0ae3b3122f35f6e0984e8c2e58ec1ec758e26 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Tue, 29 Jan 2019 14:05:37 -0800 Subject: [PATCH 55/91] hack: polish scripts (#133) Signed-off-by: Ahmet Alp Balkan --- hack/make-docker-images.sh | 32 ++++++++++++----------- hack/make-release-artifacts.sh | 47 +++++++++++++++++----------------- hack/make-release.sh | 11 ++++---- release/.googleheader | 13 ---------- 4 files changed, 47 insertions(+), 56 deletions(-) delete mode 100644 release/.googleheader diff --git a/hack/make-docker-images.sh b/hack/make-docker-images.sh index 51a8e10..cd4cc63 100755 --- a/hack/make-docker-images.sh +++ b/hack/make-docker-images.sh @@ -1,3 +1,5 @@ +#!/usr/bin/env bash + # Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,28 +14,28 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Builds and pushes docker image for each demo microservice. +# Builds and pushes docker image for each demo microservice. -#!/usr/bin/env bash set -euo pipefail +SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" log() { echo "$1" >&2; } -fail() { log "$1"; exit 1; } TAG="${TAG?TAG env variable must be specified}" REPO_PREFIX="${REPO_PREFIX?REPO_PREFIX env variable must be specified}" +while IFS= read -d $'\0' -r dir; do + # build image + svcname="$(basename "${dir}")" + image="${REPO_PREFIX}/$svcname:$TAG" + ( + cd "${dir}" + log "Building: ${image}" + docker build -t "${image}" . -for dir in ./src/*/ -do - # build image - svcname="$(basename $dir)" - image="$REPO_PREFIX/$svcname:$TAG" - echo "Building and pushing $image..." - docker build -t $image -f $dir/Dockerfile $dir + log "Pushing: ${image}" + docker push "${image}" + ) +done < <(find "${SCRIPTDIR}/../src" -mindepth 1 -maxdepth 1 -type d -print0) - # push image - docker push $image -done - -log "Successfully built and pushed images." +log "Successfully built and pushed all images." diff --git a/hack/make-release-artifacts.sh b/hack/make-release-artifacts.sh index 1479f8a..aacb4b1 100755 --- a/hack/make-release-artifacts.sh +++ b/hack/make-release-artifacts.sh @@ -1,3 +1,5 @@ +#!/usr/bin/env bash + # Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,42 +16,41 @@ # injects new image/tag into the images in ./release/kubernetes-manifests/demo.yaml -#!/usr/bin/env bash set -euo pipefail +SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" log() { echo "$1" >&2; } -fail() { log "$1"; exit 1; } TAG="${TAG?TAG env variable must be specified}" REPO_PREFIX="${REPO_PREFIX?REPO_PREFIX env variable must be specified}" +out_file="${SCRIPTDIR}/../release/kubernetes-manifests/demo.yaml" -# overwrite release/ with the latest manifests, adding "---" separator. -src="./kubernetes-manifests/*" -manifestfile="./release/kubernetes-manifests/demo.yaml" -tmp="./release/kubernetes-manifests/tmp.yaml" -[ -e $manifestfile ] && rm $manifestfile -for f in $src; do (cat "${f}"; echo "---") >> $tmp; done +read_manifests() { + local src_manifest_dir + src_manifest_dir="${SCRIPTDIR}/../kubernetes-manifests" -# remove extra google headers -gsed -i '/^#/d' $tmp + while IFS= read -d $'\0' -r file; do + cat "${file}" + echo "---" + done < <(find "${src_manifest_dir}" -name '*.yaml' -type f -print0) +} -# remove empty lines -gsed -r -i '/^\s*$/d' $tmp +# read and merge all manifests +out_manifest="$(read_manifests)" -# add 1 google header to the top -cat "./release/.googleheader" $tmp > $manifestfile -rm $tmp - - -# replace image repo, tag for each deployment -for dir in ./src/*/ +# replace "image" repo, tag for each service +for dir in ./src/*/ do - svcname="$(basename $dir)" + svcname="$(basename "${dir}")" image="$REPO_PREFIX/$svcname:$TAG" pattern="^(\s*)image:\s.*$svcname(.*)(\s*)" - replace="\1image: $image\3" - gsed -r -i "s|$pattern|$replace|g" $manifestfile + replace="\1image: $image\3" + out_manifest="$(gsed -r "s|$pattern|$replace|g" <(echo "${out_manifest}") )" done -log "Successfully added image tags > wrote to demo.yaml". +rm -rf -- "${out_file}" +mkdir -p "$(dirname "${out_file}")" +echo "${out_manifest}" > "${out_file}" + +log "Successfully saved merged manifests to ${out_file}." diff --git a/hack/make-release.sh b/hack/make-release.sh index 1eb8bce..ff49ff4 100755 --- a/hack/make-release.sh +++ b/hack/make-release.sh @@ -1,3 +1,5 @@ +#!/usr/bin/env bash + # Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +17,6 @@ # Creates a new release by 1) building/pushing images, 2) injecting tag into YAML, # 3) creating a new git tag, and 4) pushing tags/updated YAML to $BRANCH. -#!/usr/bin/env bash set -euo pipefail log() { echo "$1" >&2; } @@ -24,13 +25,13 @@ fail() { log "$1"; exit 1; } TAG="${TAG?TAG env variable must be specified}" REPO_PREFIX="${REPO_PREFIX?REPO_PREFIX env variable must be specified}" -# build and push images +# build and push images ./hack/make-docker-images.sh -# update yaml -./hack/make-release-artifacts.sh +# update yaml +./hack/make-release-artifacts.sh -# create git release / push to master +# create git release / push to master log "Pushing k8s manifests to master..." git tag "$TAG" git add release/ diff --git a/release/.googleheader b/release/.googleheader deleted file mode 100644 index ddd71c0..0000000 --- a/release/.googleheader +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2019 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. From 1d045de655edf595b037937d9d107d97f498a374 Mon Sep 17 00:00:00 2001 From: Megan O'Keefe <3137106+m-okeefe@users.noreply.github.com> Date: Tue, 29 Jan 2019 16:08:24 -0800 Subject: [PATCH 56/91] productcatalog: introduce configurable latency (#134) --- src/productcatalogservice/README.md | 7 +++++++ src/productcatalogservice/server.go | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/productcatalogservice/README.md b/src/productcatalogservice/README.md index 13ff37c..5dc8fea 100644 --- a/src/productcatalogservice/README.md +++ b/src/productcatalogservice/README.md @@ -29,3 +29,10 @@ kubectl exec \ $(kubectl get pods -l app=productcatalogservice -o jsonpath='{.items[0].metadata.name}') \ -c server -- kill -USR2 1 ``` + +## Latency injection + +This service has an `EXTRA_LATENCY` environment variable. This will inject a sleep for the specified [time.Duration](https://golang.org/pkg/time/#ParseDuration) on every call to +to the server. + +For example, use `EXTRA_LATENCY="5.5s"` to sleep for 5.5 seconds on every request. diff --git a/src/productcatalogservice/server.go b/src/productcatalogservice/server.go index 4fb7018..c55e0af 100644 --- a/src/productcatalogservice/server.go +++ b/src/productcatalogservice/server.go @@ -48,6 +48,7 @@ var ( cat pb.ListProductsResponse catalogMutex *sync.Mutex log *logrus.Logger + extraLatency time.Duration port = flag.Int("port", 3550, "port to listen at") @@ -77,6 +78,18 @@ func main() { go initProfiling("productcatalogservice", "1.0.0") flag.Parse() + // set injected latency + if s := os.Getenv("EXTRA_LATENCY"); s != "" { + v, err := time.ParseDuration(s) + if err != nil { + log.Fatalf("failed to parse EXTRA_LATENCY (%s) as time.Duration: %+v", v, err) + } + extraLatency = v + log.Infof("extra latency enabled (duration: %v)", extraLatency) + } else { + extraLatency = time.Duration(0) + } + sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGUSR1, syscall.SIGUSR2) go func() { @@ -117,7 +130,6 @@ func initJaegerTracing() { log.Info("jaeger initialization disabled.") return } - // Register the Jaeger exporter to be able to retrieve // the collected spans. exporter, err := jaeger.NewExporter(jaeger.Options{ @@ -226,10 +238,12 @@ func (p *productCatalog) Check(ctx context.Context, req *healthpb.HealthCheckReq } func (p *productCatalog) ListProducts(context.Context, *pb.Empty) (*pb.ListProductsResponse, error) { + time.Sleep(extraLatency) return &pb.ListProductsResponse{Products: parseCatalog()}, nil } func (p *productCatalog) GetProduct(ctx context.Context, req *pb.GetProductRequest) (*pb.Product, error) { + time.Sleep(extraLatency) var found *pb.Product for i := 0; i < len(parseCatalog()); i++ { if req.Id == parseCatalog()[i].Id { @@ -243,6 +257,7 @@ func (p *productCatalog) GetProduct(ctx context.Context, req *pb.GetProductReque } func (p *productCatalog) SearchProducts(ctx context.Context, req *pb.SearchProductsRequest) (*pb.SearchProductsResponse, error) { + time.Sleep(extraLatency) // Intepret query as a substring match in name or description. var ps []*pb.Product for _, p := range parseCatalog() { From 02b2018b0ee61f3e0d41094bef3203bdb6ab3eb5 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Wed, 30 Jan 2019 00:24:07 -0800 Subject: [PATCH 57/91] recommendationservice: compile deps from requirements.in (#135) Signed-off-by: Ahmet Alp Balkan --- src/recommendationservice/requirements.in | 6 +++ src/recommendationservice/requirements.txt | 59 ++++++++++++---------- 2 files changed, 38 insertions(+), 27 deletions(-) create mode 100644 src/recommendationservice/requirements.in diff --git a/src/recommendationservice/requirements.in b/src/recommendationservice/requirements.in new file mode 100644 index 0000000..10d437d --- /dev/null +++ b/src/recommendationservice/requirements.in @@ -0,0 +1,6 @@ +google-api-core==1.6.0 +google-python-cloud-debugger==2.9 +grpcio-health-checking==1.13.0 +grpcio==1.16.1 +opencensus[stackdriver]==0.1.10 +python-json-logger==0.1.9 diff --git a/src/recommendationservice/requirements.txt b/src/recommendationservice/requirements.txt index e2dda9b..50114b2 100644 --- a/src/recommendationservice/requirements.txt +++ b/src/recommendationservice/requirements.txt @@ -1,30 +1,35 @@ -cachetools==2.1.0 -certifi==2018.4.16 -chardet==3.0.4 -enum34==1.1.6 -futures==3.2.0 -google-api-core==1.6.0 -google-api-python-client==1.7.4 -google-auth==1.6.1 -google-auth-httplib2==0.0.3 -google-cloud-core==0.29.0 -google-python-cloud-debugger==2.8 -googleapis-common-protos==1.5.3 -grpcio==1.13.0 +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile --output-file requirements.txt requirements.in +# +cachetools==3.1.0 # via google-auth +certifi==2018.11.29 # via requests +chardet==3.0.4 # via requests +enum34==1.1.6 # via grpcio +futures==3.2.0 # via google-api-core, grpcio +google-api-core[grpc]==1.6.0 +google-api-python-client==1.7.8 # via google-python-cloud-debugger +google-auth-httplib2==0.0.3 # via google-api-python-client, google-python-cloud-debugger +google-auth==1.6.2 # via google-api-core, google-api-python-client, google-auth-httplib2, google-python-cloud-debugger +google-cloud-core==0.29.1 # via google-cloud-trace +google-cloud-trace==0.20.2 # via opencensus +google-python-cloud-debugger==2.9 +googleapis-common-protos==1.5.6 # via google-api-core grpcio-health-checking==1.13.0 -grpcio-tools==1.0.0 -httplib2==0.11.3 -idna==2.7 +grpcio==1.16.1 +httplib2==0.12.0 # via google-api-python-client, google-auth-httplib2 +idna==2.8 # via requests opencensus[stackdriver]==0.1.10 -protobuf==3.5.2.post1 -pyasn1==0.4.3 -pyasn1-modules==0.2.2 +protobuf==3.6.1 # via google-api-core, googleapis-common-protos, grpcio-health-checking +pyasn1-modules==0.2.4 # via google-auth +pyasn1==0.4.5 # via pyasn1-modules, rsa python-json-logger==0.1.9 -pytz==2018.5 -PyYAML==3.13 -requests==2.20.0 -rsa==3.4.2 -six==1.11.0 -uritemplate==3.0.0 -urllib3==1.23 -virtualenv==16.0.0 +pytz==2018.9 # via google-api-core +pyyaml==3.13 # via google-python-cloud-debugger +requests==2.21.0 # via google-api-core +rsa==4.0 # via google-auth +six==1.12.0 # via google-api-core, google-api-python-client, google-auth, google-python-cloud-debugger, grpcio, protobuf +uritemplate==3.0.0 # via google-api-python-client +urllib3==1.24.1 # via requests From 31df60f050a113c771a91477863ce93c8ed0f078 Mon Sep 17 00:00:00 2001 From: Bogdan Drutu Date: Wed, 30 Jan 2019 13:35:03 -0800 Subject: [PATCH 58/91] Updates deps, OC instrumentation, formatting. (#131) --- src/adservice/build.gradle | 16 +- .../src/main/java/hipstershop/AdService.java | 145 ++++++++++-------- .../java/hipstershop/AdServiceClient.java | 103 ++++++------- 3 files changed, 138 insertions(+), 126 deletions(-) diff --git a/src/adservice/build.gradle b/src/adservice/build.gradle index 7450826..dde9248 100644 --- a/src/adservice/build.gradle +++ b/src/adservice/build.gradle @@ -10,12 +10,14 @@ buildscript { } dependencies { classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.3' + classpath "gradle.plugin.com.github.sherter.google-java-format:google-java-format-gradle-plugin:0.7.1" } } apply plugin: 'idea' apply plugin: 'java' apply plugin: 'com.google.protobuf' +apply plugin: 'com.github.sherter.google-java-format' repositories { mavenCentral() @@ -23,10 +25,10 @@ repositories { } group = "adservice" -version = "0.1.0-SNAPSHOT" // CURRENT_OPENCENSUS_VERSION +version = "0.1.0-SNAPSHOT" -def opencensusVersion = "0.17.0" // LATEST_OPENCENSUS_RELEASE_VERSION -def grpcVersion = "1.15.0" // CURRENT_GRPC_VERSION +def opencensusVersion = "0.18.0" +def grpcVersion = "1.17.0" def jacksonVersion = "2.9.6" tasks.withType(JavaCompile) { @@ -43,7 +45,9 @@ dependencies { if (speed) { compile fileTree(dir: offlineCompile, include: '*.jar') } else { - compile "com.google.api.grpc:proto-google-common-protos:1.11.0", + compile "com.google.api.grpc:proto-google-common-protos:1.12.0", + "io.opencensus:opencensus-api:${opencensusVersion}", + "io.opencensus:opencensus-contrib-grpc-util:${opencensusVersion}", "io.opencensus:opencensus-exporter-trace-jaeger:${opencensusVersion}", "io.opencensus:opencensus-exporter-stats-stackdriver:${opencensusVersion}", "io.opencensus:opencensus-exporter-trace-stackdriver:${opencensusVersion}", @@ -79,6 +83,10 @@ protobuf { } } +googleJavaFormat { + toolVersion '1.7' +} + // Inform IDEs like IntelliJ IDEA, Eclipse or NetBeans about the generated code. sourceSets { main { diff --git a/src/adservice/src/main/java/hipstershop/AdService.java b/src/adservice/src/main/java/hipstershop/AdService.java index 7320764..1c04f60 100644 --- a/src/adservice/src/main/java/hipstershop/AdService.java +++ b/src/adservice/src/main/java/hipstershop/AdService.java @@ -16,8 +16,8 @@ package hipstershop; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import hipstershop.Demo.Ad; import hipstershop.Demo.AdRequest; @@ -26,49 +26,50 @@ import io.grpc.Server; import io.grpc.ServerBuilder; import io.grpc.StatusRuntimeException; import io.grpc.health.v1.HealthCheckResponse.ServingStatus; -import io.grpc.stub.StreamObserver; import io.grpc.services.*; +import io.grpc.stub.StreamObserver; import io.opencensus.common.Duration; -import io.opencensus.common.Scope; import io.opencensus.contrib.grpc.metrics.RpcViews; -import io.opencensus.exporter.trace.jaeger.JaegerTraceExporter; -import io.opencensus.exporter.trace.logging.LoggingTraceExporter; import io.opencensus.exporter.stats.stackdriver.StackdriverStatsConfiguration; import io.opencensus.exporter.stats.stackdriver.StackdriverStatsExporter; +import io.opencensus.exporter.trace.jaeger.JaegerTraceExporter; import io.opencensus.exporter.trace.stackdriver.StackdriverTraceConfiguration; import io.opencensus.exporter.trace.stackdriver.StackdriverTraceExporter; import io.opencensus.trace.AttributeValue; import io.opencensus.trace.Span; -import io.opencensus.trace.SpanBuilder; import io.opencensus.trace.Tracer; import io.opencensus.trace.Tracing; -import io.opencensus.trace.samplers.Samplers; import java.io.IOException; -import java.util.Collection; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Random; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public final class AdService { -public class AdService { private static final Logger logger = LogManager.getLogger(AdService.class); - private static final Tracer tracer = Tracing.getTracer(); - private int MAX_ADS_TO_SERVE = 2; + private static int MAX_ADS_TO_SERVE = 2; private Server server; private HealthStatusManager healthMgr; - static final AdService service = new AdService(); + private static final AdService service = new AdService(); + private void start() throws IOException { int port = Integer.parseInt(System.getenv("PORT")); healthMgr = new HealthStatusManager(); - server = ServerBuilder.forPort(port).addService(new AdServiceImpl()) - .addService(healthMgr.getHealthService()).build().start(); + server = + ServerBuilder.forPort(port) + .addService(new AdServiceImpl()) + .addService(healthMgr.getHealthService()) + .build() + .start(); logger.info("Ad Service started, listening on " + port); Runtime.getRuntime() .addShutdownHook( @@ -91,26 +92,20 @@ public class AdService { } } - static class AdServiceImpl extends hipstershop.AdServiceGrpc.AdServiceImplBase { + private static class AdServiceImpl extends hipstershop.AdServiceGrpc.AdServiceImplBase { /** * Retrieves ads based on context provided in the request {@code AdRequest}. * * @param req the request containing context. - * @param responseObserver the stream observer which gets notified with the value of - * {@code AdResponse} + * @param responseObserver the stream observer which gets notified with the value of {@code + * AdResponse} */ @Override public void getAds(AdRequest req, StreamObserver responseObserver) { AdService service = AdService.getInstance(); - Span parentSpan = tracer.getCurrentSpan(); - SpanBuilder spanBuilder = - tracer - .spanBuilderWithExplicitParent("Retrieve Ads", parentSpan) - .setRecordEvents(true) - .setSampler(Samplers.alwaysSample()); - try (Scope scope = spanBuilder.startScopedSpan()) { - Span span = tracer.getCurrentSpan(); + Span span = tracer.getCurrentSpan(); + try { span.putAttribute("method", AttributeValue.stringAttributeValue("getAds")); List allAds = new ArrayList<>(); logger.info("received ad request (context_words=" + req.getContextKeysList() + ")"); @@ -140,29 +135,29 @@ public class AdService { responseObserver.onCompleted(); } catch (StatusRuntimeException e) { logger.log(Level.WARN, "GetAds Failed", e.getStatus()); - return; + responseObserver.onError(e); } } } - static final ImmutableListMultimap adsMap = createAdsMap(); + private static final ImmutableListMultimap adsMap = createAdsMap(); - Collection getAdsByCategory(String category) { + private Collection getAdsByCategory(String category) { return adsMap.get(category); } private static final Random random = new Random(); - public List getRandomAds() { + private List getRandomAds() { List ads = new ArrayList<>(MAX_ADS_TO_SERVE); Collection allAds = adsMap.values(); - for (int i=0; i createAdsMap() { - Ad camera = Ad.newBuilder().setRedirectUrl("/product/2ZYFJ3GM2N") - .setText("Film camera for sale. 50% off.").build(); - Ad lens = Ad.newBuilder().setRedirectUrl("/product/66VCHSJNUP") - .setText("Vintage camera lens for sale. 20% off.").build(); - Ad recordPlayer = Ad.newBuilder().setRedirectUrl("/product/0PUK6V6EV0") - .setText("Vintage record player for sale. 30% off.").build(); - Ad bike = Ad.newBuilder().setRedirectUrl("/product/9SIQT8TOJO") - .setText("City Bike for sale. 10% off.").build(); - Ad baristaKit = Ad.newBuilder().setRedirectUrl("/product/1YMWWN1N4O") - .setText("Home Barista kitchen kit for sale. Buy one, get second kit for free").build(); - Ad airPlant = Ad.newBuilder().setRedirectUrl("/product/6E92ZMYYFZ") - .setText("Air plants for sale. Buy two, get third one for free").build(); - Ad terrarium = Ad.newBuilder().setRedirectUrl("/product/L9ECAV7KIM") - .setText("Terrarium for sale. Buy one, get second one for free").build(); + private static ImmutableListMultimap createAdsMap() { + Ad camera = + Ad.newBuilder() + .setRedirectUrl("/product/2ZYFJ3GM2N") + .setText("Film camera for sale. 50% off.") + .build(); + Ad lens = + Ad.newBuilder() + .setRedirectUrl("/product/66VCHSJNUP") + .setText("Vintage camera lens for sale. 20% off.") + .build(); + Ad recordPlayer = + Ad.newBuilder() + .setRedirectUrl("/product/0PUK6V6EV0") + .setText("Vintage record player for sale. 30% off.") + .build(); + Ad bike = + Ad.newBuilder() + .setRedirectUrl("/product/9SIQT8TOJO") + .setText("City Bike for sale. 10% off.") + .build(); + Ad baristaKit = + Ad.newBuilder() + .setRedirectUrl("/product/1YMWWN1N4O") + .setText("Home Barista kitchen kit for sale. Buy one, get second kit for free") + .build(); + Ad airPlant = + Ad.newBuilder() + .setRedirectUrl("/product/6E92ZMYYFZ") + .setText("Air plants for sale. Buy two, get third one for free") + .build(); + Ad terrarium = + Ad.newBuilder() + .setRedirectUrl("/product/L9ECAV7KIM") + .setText("Terrarium for sale. Buy one, get second one for free") + .build(); return ImmutableListMultimap.builder() .putAll("photography", camera, lens) .putAll("vintage", camera, lens, recordPlayer) @@ -197,7 +213,7 @@ public class AdService { .build(); } - public static void initStackdriver() { + private static void initStackdriver() { logger.info("Initialize StackDriver"); long sleepTime = 10; /* seconds */ @@ -205,7 +221,7 @@ public class AdService { boolean statsExporterRegistered = false; boolean traceExporterRegistered = false; - for (int i=0; i Date: Thu, 31 Jan 2019 15:25:33 -0800 Subject: [PATCH 59/91] hack: compile istio manifests as well (#137) - compile k8s manifests to release/kubernetes-manifests.yaml - compile istio manifests to release/istio-manifests.yaml --- hack/make-release-artifacts.sh | 57 ++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/hack/make-release-artifacts.sh b/hack/make-release-artifacts.sh index aacb4b1..213472b 100755 --- a/hack/make-release-artifacts.sh +++ b/hack/make-release-artifacts.sh @@ -14,43 +14,60 @@ # See the License for the specific language governing permissions and # limitations under the License. -# injects new image/tag into the images in ./release/kubernetes-manifests/demo.yaml +# This script compiles manifest files with the image tags and places them in +# /release/... set -euo pipefail SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +[[ -n "${DEBUG:-}" ]] && set -x log() { echo "$1" >&2; } TAG="${TAG?TAG env variable must be specified}" REPO_PREFIX="${REPO_PREFIX?REPO_PREFIX env variable must be specified}" -out_file="${SCRIPTDIR}/../release/kubernetes-manifests/demo.yaml" +OUT_DIR="${OUT_DIR:-${SCRIPTDIR}/../release}" read_manifests() { - local src_manifest_dir - src_manifest_dir="${SCRIPTDIR}/../kubernetes-manifests" + local dir + dir="$1" while IFS= read -d $'\0' -r file; do cat "${file}" echo "---" - done < <(find "${src_manifest_dir}" -name '*.yaml' -type f -print0) + done < <(find "${dir}" -name '*.yaml' -type f -print0) } -# read and merge all manifests -out_manifest="$(read_manifests)" +mk_kubernetes_manifests() { + out_manifest="$(read_manifests "${SCRIPTDIR}/../kubernetes-manifests")" -# replace "image" repo, tag for each service -for dir in ./src/*/ -do - svcname="$(basename "${dir}")" - image="$REPO_PREFIX/$svcname:$TAG" + # replace "image" repo, tag for each service + for dir in ./src/*/ + do + svcname="$(basename "${dir}")" + image="$REPO_PREFIX/$svcname:$TAG" - pattern="^(\s*)image:\s.*$svcname(.*)(\s*)" - replace="\1image: $image\3" - out_manifest="$(gsed -r "s|$pattern|$replace|g" <(echo "${out_manifest}") )" -done + pattern="^(\s*)image:\s.*$svcname(.*)(\s*)" + replace="\1image: $image\3" + out_manifest="$(gsed -r "s|$pattern|$replace|g" <(echo "${out_manifest}") )" + done + echo "${out_manifest}" +} -rm -rf -- "${out_file}" -mkdir -p "$(dirname "${out_file}")" -echo "${out_manifest}" > "${out_file}" +mk_istio_manifests() { + read_manifests "${SCRIPTDIR}/../istio-manifests" +} -log "Successfully saved merged manifests to ${out_file}." +main() { + mkdir -p "${OUT_DIR}" + local k8s_manifests_file istio_manifests_file + + k8s_manifests_file="${OUT_DIR}/kubernetes-manifests.yaml" + mk_kubernetes_manifests > "${k8s_manifests_file}" + log "Written ${k8s_manifests_file}" + + istio_manifests_file="${OUT_DIR}/istio-manifests.yaml" + mk_istio_manifests > "${istio_manifests_file}" + log "Written ${istio_manifests_file}" +} + +main From bb31c3f15ec3f7a0bfee14566fdb151b0a53e12e Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Thu, 14 Feb 2019 09:37:08 -0800 Subject: [PATCH 60/91] Update README.md --- README.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a603b4c..4fa00fe 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,17 @@ This project contains a 10-tier microservices application. The application is a web-based e-commerce app called **“Hipster Shop”** where users can browse items, add them to the cart, and purchase them. -**Google uses this application to demonstrate Kubernetes, GKE, Istio, -Stackdriver, gRPC, OpenCensus** and similar cloud-native technologies. +**Google uses this application to demonstrate use of technologies like +Kubernetes/GKE, Istio, Stackdriver, gRPC and OpenCensus**. The demo app works +both locally on your machine, as well as a Kubernetes cluster on Google Cloud +Platform. It’s **easy to deploy with little to no configuration**. -> **Note to Googlers:** Please fill out the form at +If you’re using this demo, please **★Star** this repository to show your interest! + +> 👓**Note to Googlers:** Please fill out the form at [go/microservices-demo](http://go/microservices-demo) if you are using this application. - ## Screenshots | Home Page | Checkout Screen | @@ -34,9 +37,9 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). | [cartservice](./src/cartservice) | C# | Stores the items in the user's shipping cart in Redis and retrieves it. | | [productcatalogservice](./src/productcatalogservice) | Go | Provides the list of products from a JSON file and ability to search products and get individual products. | | [currencyservice](./src/currencyservice) | Node.js | Converts one money amount to another currency. Uses real values fetched from European Central Bank. It's the highest QPS service. | -| [paymentservice](./src/paymentservice) | Node.js | Charges the given credit card info (hypothetically😇) with the given amount and returns a transaction ID. | -| [shippingservice](./src/shippingservice) | Go | Gives shipping cost estimates based on the shopping cart. Ships items to the given address (hypothetically😇) | -| [emailservice](./src/emailservice) | Python | Sends users an order confirmation email (hypothetically😇). | +| [paymentservice](./src/paymentservice) | Node.js | Charges the given credit card info (mock) with the given amount and returns a transaction ID. | +| [shippingservice](./src/shippingservice) | Go | Gives shipping cost estimates based on the shopping cart. Ships items to the given address (mock) | +| [emailservice](./src/emailservice) | Python | Sends users an order confirmation email (mock). | | [checkoutservice](./src/checkoutservice) | Go | Retrieves user cart, prepares order and orchestrates the payment, shipping and the email notification. | | [recommendationservice](./src/recommendationservice) | Python | Recommends other products based on what's given in the cart. | | [adservice](./src/adservice) | Java | Provides text ads based on given context words. | @@ -220,4 +223,4 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). --- -This is not an official Google project. \ No newline at end of file +This is not an official Google project. From 09f5ce89da49c9e6566b12285160561d92dbae1e Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Thu, 14 Feb 2019 09:49:46 -0800 Subject: [PATCH 61/91] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4fa00fe..89a2d54 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ web-based e-commerce app called **“Hipster Shop”** where users can browse it add them to the cart, and purchase them. **Google uses this application to demonstrate use of technologies like -Kubernetes/GKE, Istio, Stackdriver, gRPC and OpenCensus**. The demo app works -both locally on your machine, as well as a Kubernetes cluster on Google Cloud -Platform. It’s **easy to deploy with little to no configuration**. +Kubernetes/GKE, Istio, Stackdriver, gRPC and OpenCensus**. This application +works on any Kubernetes cluster (such as a local one), as well as Google +Kubernetes Engine. It’s **easy to deploy with little to no configuration**. If you’re using this demo, please **★Star** this repository to show your interest! From 741c669c341ae5d0af2e3695fd3fd9c7dec556e2 Mon Sep 17 00:00:00 2001 From: rghetia Date: Thu, 14 Feb 2019 18:14:42 -0800 Subject: [PATCH 62/91] adservice: restore old grpc views until new grpc version is released. (#144) --- src/adservice/src/main/java/hipstershop/AdService.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/adservice/src/main/java/hipstershop/AdService.java b/src/adservice/src/main/java/hipstershop/AdService.java index 1c04f60..3c63c98 100644 --- a/src/adservice/src/main/java/hipstershop/AdService.java +++ b/src/adservice/src/main/java/hipstershop/AdService.java @@ -270,7 +270,14 @@ public final class AdService { /** Main launches the server from the command line. */ public static void main(String[] args) throws IOException, InterruptedException { // Registers all RPC views. - RpcViews.registerAllGrpcViews(); + /** + * [TODO:rghetia] replace registerAllViews with registerAllGrpcViews. + * registerAllGrpcViews registers new views using new measures however current grpc version records against + * old measures. When new version of grpc (0.19) is release revert back to new. After reverting + * back to new the new measure will not provide any tags (like method). This will create + * some discrepencies when compared grpc measurements in Go services. + */ + RpcViews.registerAllViews(); new Thread( new Runnable() { From e99d0808bfd2a30370489ad3548643a76b073bca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sel=C3=A7uk=20Usta?= Date: Fri, 15 Feb 2019 19:22:48 +0300 Subject: [PATCH 63/91] Fixing ./gradlew: Permission denied problem on Dockerfile (#146) --- src/adservice/Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/adservice/Dockerfile b/src/adservice/Dockerfile index f6810c8..34c6e33 100644 --- a/src/adservice/Dockerfile +++ b/src/adservice/Dockerfile @@ -4,16 +4,18 @@ WORKDIR /app COPY ["build.gradle", "gradlew", "./"] COPY gradle gradle +RUN chmod +x gradlew RUN ./gradlew downloadRepos COPY . . +RUN chmod +x gradlew RUN ./gradlew installDist FROM openjdk:8-alpine RUN apk add --no-cache libc6-compat -RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ +RUN GRPC_HEALTH_PROBE_VERSION=v0.2.1 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe From 7eb028d747bd7cb96d43fdf1b3ada4b140a56567 Mon Sep 17 00:00:00 2001 From: Alex Rebert Date: Fri, 15 Feb 2019 16:58:05 -0500 Subject: [PATCH 64/91] Fix typo in skaffold.yaml comment (#147) --- skaffold.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skaffold.yaml b/skaffold.yaml index d39d561..665f80a 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -49,7 +49,7 @@ deploy: manifests: - ./kubernetes-manifests/**.yaml profiles: -# "travis-ci" profile is used to build the images withou +# "travis-ci" profile is used to build the images without # pushing them. - name: travis-ci build: From 1c1c8b42ef106f8d0f3960bf95297f4e40dc4e14 Mon Sep 17 00:00:00 2001 From: Dennis Lumpkins Date: Fri, 15 Feb 2019 17:48:20 -0500 Subject: [PATCH 65/91] Fix small typo in installation section of README (#148) Fix typo in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 89a2d54..fefde71 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). 4. Run `skaffold run` (first time will be slow, it can take ~20-30 minutes). This will build and deploy the application. If you need to rebuild the images - automatically as you refactor he code, run `skaffold dev` command. + automatically as you refactor the code, run `skaffold dev` command. 5. Run `kubectl get pods` to verify the Pods are ready and running. The application frontend should be available at http://localhost:80 on your From 1605c21f69c0766022cf217e056adf98dd964fc4 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Mon, 18 Feb 2019 14:28:14 -0800 Subject: [PATCH 66/91] readme: hide option 3 Signed-off-by: Ahmet Alp Balkan --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fefde71..6247276 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,8 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). are seeing this, run `kubectl get service frontend-external -o=yaml | kubectl apply -f-` to trigger load balancer reconfiguration. -### Option 3: Using Static Images + ### (Optional) Deploying on a Istio-installed GKE cluster From 3b4c04fe6565d63fae5e5e9a1fb451068fb9357c Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Mon, 18 Feb 2019 15:54:01 -0800 Subject: [PATCH 67/91] loadgenerator: check curl install (#153) without &&, load generator startup was failing intermittently when it fails to install curl from apk-add. Signed-off-by: Ahmet Alp Balkan --- kubernetes-manifests/loadgenerator.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kubernetes-manifests/loadgenerator.yaml b/kubernetes-manifests/loadgenerator.yaml index 2032b8c..a53bdf8 100644 --- a/kubernetes-manifests/loadgenerator.yaml +++ b/kubernetes-manifests/loadgenerator.yaml @@ -28,7 +28,7 @@ spec: initContainers: - name: wait-frontend image: alpine:3.6 - command: ['sh', '-c', 'set -x; apk add --no-cache curl; + command: ['sh', '-c', 'set -x; apk add --no-cache curl && until timeout -t 2 curl -f "http://${FRONTEND_ADDR}"; do echo "waiting for http://${FRONTEND_ADDR}"; sleep 2; From cedf3ce8278e7da2d2c40a53150f3fa34cf2984c Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Wed, 20 Feb 2019 09:47:52 -0800 Subject: [PATCH 68/91] Release v0.1.0 --- release/istio-manifests.yaml | 135 ++++++ release/kubernetes-manifests.yaml | 774 ++++++++++++++++++++++++++++++ 2 files changed, 909 insertions(+) create mode 100644 release/istio-manifests.yaml create mode 100644 release/kubernetes-manifests.yaml diff --git a/release/istio-manifests.yaml b/release/istio-manifests.yaml new file mode 100644 index 0000000..f335d8a --- /dev/null +++ b/release/istio-manifests.yaml @@ -0,0 +1,135 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: frontend-gateway +spec: + selector: + istio: ingressgateway # use Istio default gateway implementation + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: frontend-ingress +spec: + hosts: + - "*" + gateways: + - frontend-gateway + http: + - route: + - destination: + host: frontend + port: + number: 80 +--- +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: currency-provider-external +spec: + hosts: + - www.ecb.europa.eu + ports: + - number: 80 + name: http + protocol: HTTP + - number: 443 + name: https + protocol: HTTPS +--- +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: frontend +spec: + hosts: + - "frontend.default.svc.cluster.local" + http: + - route: + - destination: + host: frontend + port: + number: 80 +--- +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: whitelist-egress-googleapis +spec: + hosts: + - "169.254.169.254" # GCE metadata server + - "metadata.google" # GCE metadata server + - "metadata.google.internal" # GCE metadata server + - "accounts.google.com" # Used to get token + - "*.googleapis.com" + ports: + - number: 80 + protocol: HTTP + name: http + - number: 443 + protocol: HTTPS + name: https +--- diff --git a/release/kubernetes-manifests.yaml b/release/kubernetes-manifests.yaml new file mode 100644 index 0000000..cd1a8be --- /dev/null +++ b/release/kubernetes-manifests.yaml @@ -0,0 +1,774 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: emailservice +spec: + template: + metadata: + labels: + app: emailservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: gcr.io/google-samples/microservices-demo/emailservice:v0.1.0 + ports: + - containerPort: 8080 + readinessProbe: + periodSeconds: 5 + exec: + command: ["/bin/grpc_health_probe", "-addr=:8080"] + livenessProbe: + periodSeconds: 5 + exec: + command: ["/bin/grpc_health_probe", "-addr=:8080"] + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: emailservice +spec: + type: ClusterIP + selector: + app: emailservice + ports: + - name: grpc + port: 5000 + targetPort: 8080 +--- +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: checkoutservice +spec: + template: + metadata: + labels: + app: checkoutservice + spec: + containers: + - name: server + image: gcr.io/google-samples/microservices-demo/checkoutservice:v0.1.0 + ports: + - containerPort: 5050 + readinessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:5050"] + livenessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:5050"] + env: + - name: PRODUCT_CATALOG_SERVICE_ADDR + value: "productcatalogservice:3550" + - name: SHIPPING_SERVICE_ADDR + value: "shippingservice:50051" + - name: PAYMENT_SERVICE_ADDR + value: "paymentservice:50051" + - name: EMAIL_SERVICE_ADDR + value: "emailservice:5000" + - name: CURRENCY_SERVICE_ADDR + value: "currencyservice:7000" + - name: CART_SERVICE_ADDR + value: "cartservice:7070" + # - name: JAEGER_SERVICE_ADDR + # value: "jaeger-collector:14268" + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: checkoutservice +spec: + type: ClusterIP + selector: + app: checkoutservice + ports: + - name: grpc + port: 5050 + targetPort: 5050 +--- +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: recommendationservice +spec: + template: + metadata: + labels: + app: recommendationservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: gcr.io/google-samples/microservices-demo/recommendationservice:v0.1.0 + ports: + - containerPort: 8080 + readinessProbe: + periodSeconds: 5 + exec: + command: ["/bin/grpc_health_probe", "-addr=:8080"] + livenessProbe: + periodSeconds: 5 + exec: + command: ["/bin/grpc_health_probe", "-addr=:8080"] + env: + - name: PRODUCT_CATALOG_SERVICE_ADDR + value: "productcatalogservice:3550" + resources: + requests: + cpu: 100m + memory: 220Mi + limits: + cpu: 200m + memory: 450Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: recommendationservice +spec: + type: ClusterIP + selector: + app: recommendationservice + ports: + - name: grpc + port: 8080 + targetPort: 8080 +--- +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: frontend +spec: + template: + metadata: + labels: + app: frontend + spec: + containers: + - name: server + image: gcr.io/google-samples/microservices-demo/frontend:v0.1.0 + ports: + - containerPort: 8080 + readinessProbe: + initialDelaySeconds: 10 + httpGet: + path: "/_healthz" + port: 8080 + httpHeaders: + - name: "Cookie" + value: "shop_session-id=x-readiness-probe" + livenessProbe: + initialDelaySeconds: 10 + httpGet: + path: "/_healthz" + port: 8080 + httpHeaders: + - name: "Cookie" + value: "shop_session-id=x-liveness-probe" + env: + - name: PRODUCT_CATALOG_SERVICE_ADDR + value: "productcatalogservice:3550" + - name: CURRENCY_SERVICE_ADDR + value: "currencyservice:7000" + - name: CART_SERVICE_ADDR + value: "cartservice:7070" + - name: RECOMMENDATION_SERVICE_ADDR + value: "recommendationservice:8080" + - name: SHIPPING_SERVICE_ADDR + value: "shippingservice:50051" + - name: CHECKOUT_SERVICE_ADDR + value: "checkoutservice:5050" + - name: AD_SERVICE_ADDR + value: "adservice:9555" + # - name: JAEGER_SERVICE_ADDR + # value: "jaeger-collector:14268" + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: frontend +spec: + type: ClusterIP + selector: + app: frontend + ports: + - name: http + port: 80 + targetPort: 8080 +--- +apiVersion: v1 +kind: Service +metadata: + name: frontend-external +spec: + type: LoadBalancer + selector: + app: frontend + ports: + - name: http + port: 80 + targetPort: 8080 +--- +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: paymentservice +spec: + template: + metadata: + labels: + app: paymentservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: gcr.io/google-samples/microservices-demo/paymentservice:v0.1.0 + ports: + - containerPort: 50051 + readinessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:50051"] + livenessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:50051"] + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: paymentservice +spec: + type: ClusterIP + selector: + app: paymentservice + ports: + - name: grpc + port: 50051 + targetPort: 50051 +--- +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: productcatalogservice +spec: + template: + metadata: + labels: + app: productcatalogservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: gcr.io/google-samples/microservices-demo/productcatalogservice:v0.1.0 + ports: + - containerPort: 3550 + readinessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:3550"] + livenessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:3550"] +# env: +# - name: JAEGER_SERVICE_ADDR +# value: "jaeger-collector:14268" + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: productcatalogservice +spec: + type: ClusterIP + selector: + app: productcatalogservice + ports: + - name: grpc + port: 3550 + targetPort: 3550 +--- +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: cartservice +spec: + template: + metadata: + labels: + app: cartservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: gcr.io/google-samples/microservices-demo/cartservice:v0.1.0 + ports: + - containerPort: 7070 + env: + - name: REDIS_ADDR + value: "redis-cart:6379" + - name: PORT + value: "7070" + - name: LISTEN_ADDR + value: "0.0.0.0" + resources: + requests: + cpu: 200m + memory: 64Mi + limits: + cpu: 300m + memory: 128Mi + readinessProbe: + initialDelaySeconds: 15 + exec: + command: ["/bin/grpc_health_probe", "-addr=:7070"] + livenessProbe: + initialDelaySeconds: 15 + periodSeconds: 10 + exec: + command: ["/bin/grpc_health_probe", "-addr=:7070"] +--- +apiVersion: v1 +kind: Service +metadata: + name: cartservice +spec: + type: ClusterIP + selector: + app: cartservice + ports: + - name: grpc + port: 7070 + targetPort: 7070 +--- +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: loadgenerator +spec: + replicas: 1 + template: + metadata: + labels: + app: loadgenerator + spec: + terminationGracePeriodSeconds: 5 + restartPolicy: Always + initContainers: + - name: wait-frontend + image: alpine:3.6 + command: ['sh', '-c', 'set -x; apk add --no-cache curl && + until timeout -t 2 curl -f "http://${FRONTEND_ADDR}"; do + echo "waiting for http://${FRONTEND_ADDR}"; + sleep 2; + done;'] + env: + - name: FRONTEND_ADDR + value: "frontend:80" + containers: + - name: main + image: gcr.io/google-samples/microservices-demo/loadgenerator:v0.1.0 + env: + - name: FRONTEND_ADDR + value: "frontend:80" + - name: USERS + value: "10" + resources: + requests: + cpu: 300m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi +--- +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: currencyservice +spec: + template: + metadata: + labels: + app: currencyservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: gcr.io/google-samples/microservices-demo/currencyservice:v0.1.0 + ports: + - name: grpc + containerPort: 7000 + readinessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:7000"] + livenessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:7000"] + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: currencyservice +spec: + type: ClusterIP + selector: + app: currencyservice + ports: + - name: grpc + port: 7000 + targetPort: 7000 +--- +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: shippingservice +spec: + template: + metadata: + labels: + app: shippingservice + spec: + containers: + - name: server + image: gcr.io/google-samples/microservices-demo/shippingservice:v0.1.0 + ports: + - containerPort: 50051 + readinessProbe: + periodSeconds: 5 + exec: + command: ["/bin/grpc_health_probe", "-addr=:50051"] + livenessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:50051"] +# env: +# - name: JAEGER_SERVICE_ADDR +# value: "jaeger-collector:14268" + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: shippingservice +spec: + type: ClusterIP + selector: + app: shippingservice + ports: + - name: grpc + port: 50051 + targetPort: 50051 +--- +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: redis-cart +spec: + template: + metadata: + labels: + app: redis-cart + spec: + containers: + - name: redis + image: redis:alpine + ports: + - containerPort: 6379 + readinessProbe: + periodSeconds: 5 + tcpSocket: + port: 6379 + livenessProbe: + periodSeconds: 5 + tcpSocket: + port: 6379 + volumeMounts: + - mountPath: /data + name: redis-data + resources: + limits: + memory: 256Mi + cpu: 125m + requests: + cpu: 70m + memory: 200Mi + volumes: + - name: redis-data + emptyDir: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: redis-cart +spec: + type: ClusterIP + selector: + app: redis-cart + ports: + - name: redis + port: 6379 + targetPort: 6379 +--- +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: adservice +spec: + template: + metadata: + labels: + app: adservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: gcr.io/google-samples/microservices-demo/adservice:v0.1.0 + ports: + - containerPort: 9555 + env: + - name: PORT + value: "9555" + #- name: JAEGER_SERVICE_ADDR + # value: "jaeger-collector:14268" + resources: + requests: + cpu: 200m + memory: 180Mi + limits: + cpu: 300m + memory: 300Mi + readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 15 + exec: + command: ["/bin/grpc_health_probe", "-addr=:9555"] + livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 15 + exec: + command: ["/bin/grpc_health_probe", "-addr=:9555"] +--- +apiVersion: v1 +kind: Service +metadata: + name: adservice +spec: + type: ClusterIP + selector: + app: adservice + ports: + - name: grpc + port: 9555 + targetPort: 9555 +--- From f3e29f7450ec41848058c09d0a2c3adb4f6f484a Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Wed, 20 Feb 2019 11:07:26 -0800 Subject: [PATCH 69/91] hack: fix release scripts (#157) Previous release script wasn't committing/tagging in the right order. Also made scripts resistant to: * empty env vars * current workdir the script is invoked from cc: @m-okeefe --- hack/make-docker-images.sh | 4 ++-- hack/make-release-artifacts.sh | 4 ++-- hack/make-release.sh | 25 +++++++++++++++++-------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/hack/make-docker-images.sh b/hack/make-docker-images.sh index cd4cc63..69afd0f 100755 --- a/hack/make-docker-images.sh +++ b/hack/make-docker-images.sh @@ -21,8 +21,8 @@ SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" log() { echo "$1" >&2; } -TAG="${TAG?TAG env variable must be specified}" -REPO_PREFIX="${REPO_PREFIX?REPO_PREFIX env variable must be specified}" +TAG="${TAG:?TAG env variable must be specified}" +REPO_PREFIX="${REPO_PREFIX:?REPO_PREFIX env variable must be specified}" while IFS= read -d $'\0' -r dir; do # build image diff --git a/hack/make-release-artifacts.sh b/hack/make-release-artifacts.sh index 213472b..2a14ae5 100755 --- a/hack/make-release-artifacts.sh +++ b/hack/make-release-artifacts.sh @@ -23,8 +23,8 @@ SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" log() { echo "$1" >&2; } -TAG="${TAG?TAG env variable must be specified}" -REPO_PREFIX="${REPO_PREFIX?REPO_PREFIX env variable must be specified}" +TAG="${TAG:?TAG env variable must be specified}" +REPO_PREFIX="${REPO_PREFIX:?REPO_PREFIX env variable must be specified}" OUT_DIR="${OUT_DIR:-${SCRIPTDIR}/../release}" read_manifests() { diff --git a/hack/make-release.sh b/hack/make-release.sh index ff49ff4..04fb276 100755 --- a/hack/make-release.sh +++ b/hack/make-release.sh @@ -14,28 +14,37 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Creates a new release by 1) building/pushing images, 2) injecting tag into YAML, -# 3) creating a new git tag, and 4) pushing tags/updated YAML to $BRANCH. +# This script creates a new release by: +# - 1. building/pushing images +# - 2. injecting tags into YAML manifests +# - 3. creating a new git tag +# - 4. pushing the tag/commit to master. set -euo pipefail +SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +[[ -n "${DEBUG:-}" ]] && set -x log() { echo "$1" >&2; } fail() { log "$1"; exit 1; } -TAG="${TAG?TAG env variable must be specified}" -REPO_PREFIX="${REPO_PREFIX?REPO_PREFIX env variable must be specified}" +TAG="${TAG:?TAG env variable must be specified}" +REPO_PREFIX="${REPO_PREFIX:?REPO_PREFIX env variable must be specified e.g. gcr.io\/google-samples\/microservices-demo}" + +if [[ "$TAG" != v* ]]; then + fail "\$TAG must start with 'v', e.g. v0.1.0 (got: $TAG)" +fi # build and push images -./hack/make-docker-images.sh +"${SCRIPTDIR}"/make-docker-images.sh # update yaml -./hack/make-release-artifacts.sh +"${SCRIPTDIR}"/make-release-artifacts.sh # create git release / push to master +git add "${SCRIPTDIR}/../release/" +git commit --allow-empty -m "Release $TAG" log "Pushing k8s manifests to master..." git tag "$TAG" -git add release/ -git commit --allow-empty -m "Release $TAG" git push --tags git push origin master From ef64fdae864dce3cc45ce77c3f5efb56c3b0e9ff Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Wed, 20 Feb 2019 11:07:37 -0800 Subject: [PATCH 70/91] Show option to use prebuilt images (#156) Signed-off-by: Ahmet Alp Balkan --- README.md | 54 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 6247276..7d2db13 100644 --- a/README.md +++ b/README.md @@ -69,12 +69,26 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). ## Installation -> **Note:** that the first build can take up to 20-30 minutes. Consequent builds -> will be faster. +We offer three installation methods: + +1. **Running locally with “Docker for Desktop”** (~20 minutes) You will build + and deploy microservices images to a single-node Kubernetes cluster running + on your development machine. + +2. **Running on Google Kubernetes Engine (GKE)”** (~30 minutes) You will build, + upload and deploy the container images to a Kubernetes cluster on Google + Cloud. + +3. **Using pre-built container images:** (~10 minutes, you will still need to + follow one of the steps above up until `skaffold run` command). With this + option, you will use pre-built container images that are available publicly, + instead of building them yourself, which takes a long time). + ### Option 1: Running locally with “Docker for Desktop” -> 💡 Recommended if you're planning to develop the application. +> 💡 Recommended if you're planning to develop the application or giving it a +> try on your local cluster. 1. Install tools to run a Kubernetes cluster locally: @@ -90,7 +104,7 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). 3. Run `kubectl get nodes` to verify you're connected to “Kubernetes on Docker”. -4. Run `skaffold run` (first time will be slow, it can take ~20-30 minutes). +4. Run `skaffold run` (first time will be slow, it can take ~20 minutes). This will build and deploy the application. If you need to rebuild the images automatically as you refactor the code, run `skaffold dev` command. @@ -100,7 +114,8 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). ### Option 2: Running on Google Kubernetes Engine (GKE) -> 💡 Recommended for demos and making it available publicly. +> 💡 Recommended if you're using Google Cloud Platform and want to try it on +> a realistic cluster. 1. Install tools specified in the previous section (Docker, kubectl, skaffold) @@ -125,6 +140,7 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). where [PROJECT_ID] is your GCP project ID. This command: + - builds the container images - pushes them to GCR - applies the `./kubernetes-manifests` deploying the application to @@ -147,28 +163,34 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). are seeing this, run `kubectl get service frontend-external -o=yaml | kubectl apply -f-` to trigger load balancer reconfiguration. - + kubectl get service/frontend-external + ### (Optional) Deploying on a Istio-installed GKE cluster > **Note:** you followed GKE deployment steps above, run `skaffold delete` first > to delete what's deployed. -1. Create a GKE cluster (described above). +1. Create a GKE cluster (described in "Option 2"). 2. Use [Istio on GKE add-on](https://cloud.google.com/istio/docs/istio-on-gke/installing) to install Istio to your existing GKE cluster. From bae651f7ea537d2676b38a04d89adacdd45c17bd Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Wed, 20 Feb 2019 11:17:45 -0800 Subject: [PATCH 71/91] Release v0.1.0 From 5f41e12b2f0631a6a0c462b326acf440156109ee Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Wed, 20 Feb 2019 14:34:12 -0800 Subject: [PATCH 72/91] README formatting (#158) Signed-off-by: Ahmet Alp Balkan --- README.md | 157 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 88 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 7d2db13..4045741 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ Kubernetes Engine. It’s **easy to deploy with little to no configuration**. If you’re using this demo, please **★Star** this repository to show your interest! > 👓**Note to Googlers:** Please fill out the form at -[go/microservices-demo](http://go/microservices-demo) if you are using this -application. +> [go/microservices-demo](http://go/microservices-demo) if you are using this +> application. ## Screenshots -| Home Page | Checkout Screen | -|-----------|-----------------| +| Home Page | Checkout Screen | +| ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | [![Screenshot of store homepage](./docs/img/hipster-shop-frontend-1.png)](./docs/img/hipster-shop-frontend-1.png) | [![Screenshot of checkout screen](./docs/img/hipster-shop-frontend-2.png)](./docs/img/hipster-shop-frontend-2.png) | ## Service Architecture @@ -31,20 +31,19 @@ microservices](./docs/img/architecture-diagram.png)](./docs/img/architecture-dia Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). -| Service | Language | Description | -|---------|----------|-------------| -| [frontend](./src/frontend) | Go | Exposes an HTTP server to serve the website. Does not require signup/login and generates session IDs for all users automatically. | -| [cartservice](./src/cartservice) | C# | Stores the items in the user's shipping cart in Redis and retrieves it. | -| [productcatalogservice](./src/productcatalogservice) | Go | Provides the list of products from a JSON file and ability to search products and get individual products. | -| [currencyservice](./src/currencyservice) | Node.js | Converts one money amount to another currency. Uses real values fetched from European Central Bank. It's the highest QPS service. | -| [paymentservice](./src/paymentservice) | Node.js | Charges the given credit card info (mock) with the given amount and returns a transaction ID. | -| [shippingservice](./src/shippingservice) | Go | Gives shipping cost estimates based on the shopping cart. Ships items to the given address (mock) | -| [emailservice](./src/emailservice) | Python | Sends users an order confirmation email (mock). | -| [checkoutservice](./src/checkoutservice) | Go | Retrieves user cart, prepares order and orchestrates the payment, shipping and the email notification. | -| [recommendationservice](./src/recommendationservice) | Python | Recommends other products based on what's given in the cart. | -| [adservice](./src/adservice) | Java | Provides text ads based on given context words. | -| [loadgenerator](./src/loadgenerator) | Python/Locust | Continuously sends requests imitating realistic user shopping flows to the frontend. | - +| Service | Language | Description | +| ---------------------------------------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------- | +| [frontend](./src/frontend) | Go | Exposes an HTTP server to serve the website. Does not require signup/login and generates session IDs for all users automatically. | +| [cartservice](./src/cartservice) | C# | Stores the items in the user's shipping cart in Redis and retrieves it. | +| [productcatalogservice](./src/productcatalogservice) | Go | Provides the list of products from a JSON file and ability to search products and get individual products. | +| [currencyservice](./src/currencyservice) | Node.js | Converts one money amount to another currency. Uses real values fetched from European Central Bank. It's the highest QPS service. | +| [paymentservice](./src/paymentservice) | Node.js | Charges the given credit card info (mock) with the given amount and returns a transaction ID. | +| [shippingservice](./src/shippingservice) | Go | Gives shipping cost estimates based on the shopping cart. Ships items to the given address (mock) | +| [emailservice](./src/emailservice) | Python | Sends users an order confirmation email (mock). | +| [checkoutservice](./src/checkoutservice) | Go | Retrieves user cart, prepares order and orchestrates the payment, shipping and the email notification. | +| [recommendationservice](./src/recommendationservice) | Python | Recommends other products based on what's given in the cart. | +| [adservice](./src/adservice) | Java | Provides text ads based on given context words. | +| [loadgenerator](./src/loadgenerator) | Python/Locust | Continuously sends requests imitating realistic user shopping flows to the frontend. | ## Features @@ -84,7 +83,6 @@ We offer three installation methods: option, you will use pre-built container images that are available publicly, instead of building them yourself, which takes a long time). - ### Option 1: Running locally with “Docker for Desktop” > 💡 Recommended if you're planning to develop the application or giving it a @@ -99,16 +97,17 @@ We offer three installation methods: (ensure version ≥v0.20) 1. Launch “Docker for Desktop”. Go to Preferences: + - choose “Enable Kubernetes”, - set CPUs to at least 3, and Memory to at least 6.0 GiB -3. Run `kubectl get nodes` to verify you're connected to “Kubernetes on Docker”. +1. Run `kubectl get nodes` to verify you're connected to “Kubernetes on Docker”. -4. Run `skaffold run` (first time will be slow, it can take ~20 minutes). +1. Run `skaffold run` (first time will be slow, it can take ~20 minutes). This will build and deploy the application. If you need to rebuild the images automatically as you refactor the code, run `skaffold dev` command. -5. Run `kubectl get pods` to verify the Pods are ready and running. The +1. Run `kubectl get pods` to verify the Pods are ready and running. The application frontend should be available at http://localhost:80 on your machine. @@ -117,40 +116,50 @@ We offer three installation methods: > 💡 Recommended if you're using Google Cloud Platform and want to try it on > a realistic cluster. -1. Install tools specified in the previous section (Docker, kubectl, skaffold) +1. Install tools specified in the previous section (Docker, kubectl, skaffold) -1. Create a Google Kubernetes Engine cluster and make sure `kubectl` is pointing - to the cluster. +1. Create a Google Kubernetes Engine cluster and make sure `kubectl` is pointing + to the cluster. - gcloud services enable container.googleapis.com + ```sh + gcloud services enable container.googleapis.com + ``` - gcloud container clusters create demo --enable-autoupgrade \ - --enable-autoscaling --min-nodes=3 --max-nodes=10 --num-nodes=5 --zone=us-central1-a + ```sh + gcloud container clusters create demo --enable-autoupgrade \ + --enable-autoscaling --min-nodes=3 --max-nodes=10 --num-nodes=5 --zone=us-central1-a + ``` - kubectl get nodes + ``` + kubectl get nodes + ``` -1. Enable Google Container Registry (GCR) on your GCP project and configure the - `docker` CLI to authenticate to GCR: +1. Enable Google Container Registry (GCR) on your GCP project and configure the + `docker` CLI to authenticate to GCR: - gcloud services enable containerregistry.googleapis.com + ```sh + gcloud services enable containerregistry.googleapis.com + ``` - gcloud auth configure-docker -q + ```sh + gcloud auth configure-docker -q + ``` -1. In the root of this repository, run `skaffold run --default-repo=gcr.io/[PROJECT_ID]`, - where [PROJECT_ID] is your GCP project ID. +1. In the root of this repository, run `skaffold run --default-repo=gcr.io/[PROJECT_ID]`, + where [PROJECT_ID] is your GCP project ID. - This command: + This command: - - builds the container images - - pushes them to GCR - - applies the `./kubernetes-manifests` deploying the application to - Kubernetes. + - builds the container images + - pushes them to GCR + - applies the `./kubernetes-manifests` deploying the application to + Kubernetes. - **Troubleshooting:** If you get "No space left on device" error on Google - Cloud Shell, you can build the images on Google Cloud Build: [Enable the - Cloud Build - API](https://console.cloud.google.com/flows/enableapi?apiid=cloudbuild.googleapis.com), - then run `skaffold run -p gcb --default-repo=gcr.io/[PROJECT_ID]` instead. + **Troubleshooting:** If you get "No space left on device" error on Google + Cloud Shell, you can build the images on Google Cloud Build: [Enable the + Cloud Build + API](https://console.cloud.google.com/flows/enableapi?apiid=cloudbuild.googleapis.com), + then run `skaffold run -p gcb --default-repo=gcr.io/[PROJECT_ID]` instead. 1. Find the IP address of your application, then visit the application on your browser to confirm installation. @@ -180,10 +189,11 @@ by deploying the [release manifest](./release) directly to an existing cluster. 1. Run `kubectl apply -f ./release/kubernetes-manifests` to deploy the app. 1. Run `kubectl get pods` to see pods are in a Ready state. 1. Find the IP address of your application, then visit the application on your - browser to confirm installation. - - kubectl get service/frontend-external + browser to confirm installation. + ```sh + kubectl get service/frontend-external + ``` ### (Optional) Deploying on a Istio-installed GKE cluster @@ -192,13 +202,15 @@ by deploying the [release manifest](./release) directly to an existing cluster. 1. Create a GKE cluster (described in "Option 2"). -2. Use [Istio on GKE add-on](https://cloud.google.com/istio/docs/istio-on-gke/installing) +1. Use [Istio on GKE add-on](https://cloud.google.com/istio/docs/istio-on-gke/installing) to install Istio to your existing GKE cluster. - gcloud beta container clusters update demo \ - --zone=us-central1-a \ - --update-addons=Istio=ENABLED \ - --istio-config=auth=MTLS_PERMISSIVE + ```sh + gcloud beta container clusters update demo \ + --zone=us-central1-a \ + --update-addons=Istio=ENABLED \ + --istio-config=auth=MTLS_PERMISSIVE + ``` > NOTE: If you need to enable `MTLS_STRICT` mode, you will need to update > several manifest files: @@ -207,43 +219,50 @@ by deploying the [release manifest](./release) directly to an existing cluster. > "readinessProbe" fields. > - `kubernetes-manifests/loadgenerator.yaml`: delete "initContainers" field. -3. (Optional) Enable Stackdriver Tracing/Logging with Istio Stackdriver Adapter +1. (Optional) Enable Stackdriver Tracing/Logging with Istio Stackdriver Adapter by [following this guide](https://cloud.google.com/istio/docs/istio-on-gke/installing#enabling_tracing_and_logging). -4. Install the automatic sidecar injection (annotate the `default` namespace +1. Install the automatic sidecar injection (annotate the `default` namespace with the label): - kubectl label namespace default istio-injection=enabled + ```sh + kubectl label namespace default istio-injection=enabled + ``` -5. Apply the manifests in [`./istio-manifests`](./istio-manifests) directory. +1. Apply the manifests in [`./istio-manifests`](./istio-manifests) directory. + (This is required only once.) - kubectl apply -f ./istio-manifests + ```sh + kubectl apply -f ./istio-manifests + ``` - This is required only once. +1. Deploy the application with `skaffold run --default-repo=gcr.io/[PROJECT_ID]`. -6. Deploy the application with `skaffold run --default-repo=gcr.io/[PROJECT_ID]`. +1. Run `kubectl get pods` to see pods are in a healthy and ready state. -7. Run `kubectl get pods` to see pods are in a healthy and ready state. - -8. Find the IP address of your istio gateway Ingress or Service, and visit the +1. Find the IP address of your Istio gateway Ingress or Service, and visit the application. - INGRESS_HOST="$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')" + ```sh + INGRESS_HOST="$(kubectl -n istio-system get service istio-ingressgateway \ + -o jsonpath='{.status.loadBalancer.ingress[0].ip}')" + echo "$INGRESS_HOST" + ``` - echo "$INGRESS_HOST" - - curl -v "http://$INGRESS_HOST" + ```sh + curl -v "http://$INGRESS_HOST" + ``` ## Conferences featuring Hipster Shop - [Google Cloud Next'18 London – Keynote](https://youtu.be/nIq2pkNcfEI?t=3071) showing Stackdriver Incident Response Management - Google Cloud Next'18 SF - - [Day 1 Keynote](https://youtu.be/vJ9OaAqfxo4?t=2416) showing GKE On-Prem + - [Day 1 Keynote](https://youtu.be/vJ9OaAqfxo4?t=2416) showing GKE On-Prem - [Day 3 – Keynote](https://youtu.be/JQPOPV_VH5w?t=815) showing Stackdriver APM (Tracing, Code Search, Profiler, Google Cloud Build) - [Introduction to Service Management with Istio](https://www.youtube.com/watch?v=wCJrdKdD6UM&feature=youtu.be&t=586) --- -This is not an official Google project. +This is not an official Google project. From b9792c94c8355a122197ebcd7e686f10dd975eb1 Mon Sep 17 00:00:00 2001 From: David Ebbo Date: Fri, 22 Feb 2019 09:55:40 -0800 Subject: [PATCH 73/91] Add missing extension to pre-built images instructions in readme (#160) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4045741..fc3101b 100644 --- a/README.md +++ b/README.md @@ -186,7 +186,7 @@ by deploying the [release manifest](./release) directly to an existing cluster. **Prerequisite**: a running Kubernetes cluster (either local or on cloud). 1. Clone this repository, and go to the repository directory -1. Run `kubectl apply -f ./release/kubernetes-manifests` to deploy the app. +1. Run `kubectl apply -f ./release/kubernetes-manifests.yaml` to deploy the app. 1. Run `kubectl get pods` to see pods are in a Ready state. 1. Find the IP address of your application, then visit the application on your browser to confirm installation. From 458bf50b95b3cf367f43dc87bf430f8159076760 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Wed, 27 Feb 2019 09:54:18 -0700 Subject: [PATCH 74/91] credit card expired (#167) fixes #164 Signed-off-by: Ahmet Alp Balkan --- src/loadgenerator/locustfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loadgenerator/locustfile.py b/src/loadgenerator/locustfile.py index 997b3b3..f1f98ea 100644 --- a/src/loadgenerator/locustfile.py +++ b/src/loadgenerator/locustfile.py @@ -60,7 +60,7 @@ def checkout(l): 'country': 'United States', 'credit_card_number': '4432-8015-6152-0454', 'credit_card_expiration_month': '1', - 'credit_card_expiration_year': '2019', + 'credit_card_expiration_year': '2039', 'credit_card_cvv': '672', }) From d08d419a943d21ed6ab359b236167f98b5b5d1a6 Mon Sep 17 00:00:00 2001 From: sebright Date: Thu, 28 Feb 2019 21:34:57 -0800 Subject: [PATCH 75/91] adservice: use Stackdriver special field to set sampling decision in log entries (#168) This commit sets the new sampling decision field that is recognized by the Stackdriver Logging agent, "logging.googleapis.com/traceSampled". The sampling decision field was added in https://github.com/GoogleCloudPlatform/fluent-plugin-google-cloud/pull/297, and it won't be available until the new version of fluent-plugin-google-cloud is used in GKE. --- src/adservice/src/main/resources/log4j2.xml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/adservice/src/main/resources/log4j2.xml b/src/adservice/src/main/resources/log4j2.xml index 9d85f97..dbb8cb1 100644 --- a/src/adservice/src/main/resources/log4j2.xml +++ b/src/adservice/src/main/resources/log4j2.xml @@ -4,12 +4,15 @@ + span ID, sampling decision, and timestamp are interpreted by Stackdriver. It uses the + special JSON keys that the Stackdriver Logging agent converts to "trace", "spanId", + "traceSampled", and "timestamp" in the Stackdriver LogEntry + (https://cloud.google.com/logging/docs/agent/configuration#special-fields). --> + - + From d5db0247638840cdb6ed6684c7582f82ac7597b0 Mon Sep 17 00:00:00 2001 From: Mehdi El Gueddari Date: Mon, 4 Mar 2019 18:52:55 +0000 Subject: [PATCH 76/91] kubernetes: use apps/v1 for Deployment (#166) In certain situations (see details below), the deployment to Kubernetes fails with: > "The Deployment [DEPLOYMENT_OBJECT] is invalid: [...] `selector` does not match template `labels`". This is caused by the K8S Deployment manifests missing an explicit `selector` value. This commit: * adds explicit `selector` values for all Deployment objects. * bumps the K8S API from the deprecated `extensions/v1beta1` version to the stable `apps/v1` version. This version made the `selector` property of the Deployment a required value, preventing any issues with missing selectors in the future. This change is backwards compatible with existing deployments of the microservices demo app. I.e. you should be able to pull this change and run `skaffold run` against an existing deployment of the app without issues. This will not however resolve the issue for existing deployments. Selectors are immutable and will therefore retain their current defaulted value. You should run `skaffold delete` followed by `skaffold run` after having pulled this change to do a clean re-deployment of the app, which will resolve the issue. **The nitty-gritty details** In the `extensions/v1beta1` version of K8S API (the version that was used by this project), the `selector` property of a Deployment object is optional and is defaulted to the labels used in the pod template. This can cause subtle issues leading to deployment failures. This project, where Deployment selectors were omitted, is a good example of what can go wrong with defaulted selectors. Consider this: 1. Run `skaffold run` to build locally with Docker and deploy. Since the Deployment specs don't have explict selectors, they will be defaulted to the pod template labels. And since skaffold adds additional labels to the pod template like `skaffold-builder` and `skaffold-deployer`, the end-result will be a selector that looks like this: > app=cartservice,cleanup=true,docker-api-version=1.39,skaffold-builder=local,skaffold-deployer=kubectl,skaffold-tag-policy=git-commit,tail=true So far, so good. 2. Now run `skaffold run -p gcb --default-repo=your-gcr-repo` to build on Google Cloud Build instead of building locally. This will blow up when attempting to deploy to Kubernetes with an error similar to: > The Deployment "cartservice" is invalid: spec.template.metadata.labels: Invalid value: map[string]string{"skaffold-builder":"google-cloud-build", "profiles"="gcb", "skaffold-deployer":"kubectl", "skaffold-tag-policy":"git-commit", "docker-api-version":"1.39", "tail":"true", "app":"cartservice", "cleanup":"true"}: `selector` does not match template `labels` (and the same error for every other deployment object) This is because the skaffold labels that were automatically added to the pod template have changed to include references to Google Cloud Build. That normally shouldn't be an issue. But without explicit Deployment selectors, this results in the defaulted selectors for our Deployment objects to have also changed. Which means that the new version of our Deployment objects are now managing different sets of Pods. Which is thankfully caught by kubectl before the deployment happens (otherwise this would have resulted in orphaned pods). In this commit, we explicitely set the `selector` value of all Deployment objects, which fixes this issue. We also bump the K8S API version to the stable `apps/v1`, which makes the `selector` property a required value and will avoid accidently forgetting selectors in the future. More details if you're curious: * Why defaulted Deployment selectors cause problems: https://github.com/kubernetes/kubernetes/issues/26202 * Why Deployment selectors should be (and were made) immutable: https://github.com/kubernetes/kubernetes/issues/50808 --- kubernetes-manifests/adservice.yaml | 5 ++++- kubernetes-manifests/cartservice.yaml | 5 ++++- kubernetes-manifests/checkoutservice.yaml | 5 ++++- kubernetes-manifests/currencyservice.yaml | 5 ++++- kubernetes-manifests/emailservice.yaml | 5 ++++- kubernetes-manifests/frontend.yaml | 5 ++++- kubernetes-manifests/loadgenerator.yaml | 5 ++++- kubernetes-manifests/paymentservice.yaml | 5 ++++- kubernetes-manifests/productcatalogservice.yaml | 5 ++++- kubernetes-manifests/recommendationservice.yaml | 5 ++++- kubernetes-manifests/redis.yaml | 5 ++++- kubernetes-manifests/shippingservice.yaml | 5 ++++- 12 files changed, 48 insertions(+), 12 deletions(-) diff --git a/kubernetes-manifests/adservice.yaml b/kubernetes-manifests/adservice.yaml index 76f35ae..713ebcd 100644 --- a/kubernetes-manifests/adservice.yaml +++ b/kubernetes-manifests/adservice.yaml @@ -12,11 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: adservice spec: + selector: + matchLabels: + app: adservice template: metadata: labels: diff --git a/kubernetes-manifests/cartservice.yaml b/kubernetes-manifests/cartservice.yaml index 5484017..fcfe0f5 100644 --- a/kubernetes-manifests/cartservice.yaml +++ b/kubernetes-manifests/cartservice.yaml @@ -12,11 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: cartservice spec: + selector: + matchLabels: + app: cartservice template: metadata: labels: diff --git a/kubernetes-manifests/checkoutservice.yaml b/kubernetes-manifests/checkoutservice.yaml index 1b537df..6b99656 100644 --- a/kubernetes-manifests/checkoutservice.yaml +++ b/kubernetes-manifests/checkoutservice.yaml @@ -12,11 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: checkoutservice spec: + selector: + matchLabels: + app: checkoutservice template: metadata: labels: diff --git a/kubernetes-manifests/currencyservice.yaml b/kubernetes-manifests/currencyservice.yaml index 6e38247..2d6d76a 100644 --- a/kubernetes-manifests/currencyservice.yaml +++ b/kubernetes-manifests/currencyservice.yaml @@ -12,11 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: currencyservice spec: + selector: + matchLabels: + app: currencyservice template: metadata: labels: diff --git a/kubernetes-manifests/emailservice.yaml b/kubernetes-manifests/emailservice.yaml index 4a5363d..c5dd7d8 100644 --- a/kubernetes-manifests/emailservice.yaml +++ b/kubernetes-manifests/emailservice.yaml @@ -12,11 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: emailservice spec: + selector: + matchLabels: + app: emailservice template: metadata: labels: diff --git a/kubernetes-manifests/frontend.yaml b/kubernetes-manifests/frontend.yaml index c83a1a7..cc7b1cc 100644 --- a/kubernetes-manifests/frontend.yaml +++ b/kubernetes-manifests/frontend.yaml @@ -12,11 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: frontend spec: + selector: + matchLabels: + app: frontend template: metadata: labels: diff --git a/kubernetes-manifests/loadgenerator.yaml b/kubernetes-manifests/loadgenerator.yaml index a53bdf8..c2aeb98 100644 --- a/kubernetes-manifests/loadgenerator.yaml +++ b/kubernetes-manifests/loadgenerator.yaml @@ -12,11 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: loadgenerator spec: + selector: + matchLabels: + app: loadgenerator replicas: 1 template: metadata: diff --git a/kubernetes-manifests/paymentservice.yaml b/kubernetes-manifests/paymentservice.yaml index a3c2e31..47523a9 100644 --- a/kubernetes-manifests/paymentservice.yaml +++ b/kubernetes-manifests/paymentservice.yaml @@ -12,11 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: paymentservice spec: + selector: + matchLabels: + app: paymentservice template: metadata: labels: diff --git a/kubernetes-manifests/productcatalogservice.yaml b/kubernetes-manifests/productcatalogservice.yaml index 54416d6..9161a54 100644 --- a/kubernetes-manifests/productcatalogservice.yaml +++ b/kubernetes-manifests/productcatalogservice.yaml @@ -12,11 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: productcatalogservice spec: + selector: + matchLabels: + app: productcatalogservice template: metadata: labels: diff --git a/kubernetes-manifests/recommendationservice.yaml b/kubernetes-manifests/recommendationservice.yaml index 20a85d1..07d4c27 100644 --- a/kubernetes-manifests/recommendationservice.yaml +++ b/kubernetes-manifests/recommendationservice.yaml @@ -12,11 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: recommendationservice spec: + selector: + matchLabels: + app: recommendationservice template: metadata: labels: diff --git a/kubernetes-manifests/redis.yaml b/kubernetes-manifests/redis.yaml index e690d66..b67649b 100644 --- a/kubernetes-manifests/redis.yaml +++ b/kubernetes-manifests/redis.yaml @@ -12,11 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: redis-cart spec: + selector: + matchLabels: + app: redis-cart template: metadata: labels: diff --git a/kubernetes-manifests/shippingservice.yaml b/kubernetes-manifests/shippingservice.yaml index 9213e58..5daf5ef 100644 --- a/kubernetes-manifests/shippingservice.yaml +++ b/kubernetes-manifests/shippingservice.yaml @@ -12,11 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: shippingservice spec: + selector: + matchLabels: + app: shippingservice template: metadata: labels: From f7580958cc670c778daca1cb29d139213737eac2 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Wed, 6 Mar 2019 16:42:08 -0800 Subject: [PATCH 77/91] Switch currencyservice to static JSON file (#173) --- .../data/currency_conversion.json | 35 +++++++++++++++++++ src/currencyservice/server.js | 33 ++--------------- 2 files changed, 38 insertions(+), 30 deletions(-) create mode 100644 src/currencyservice/data/currency_conversion.json diff --git a/src/currencyservice/data/currency_conversion.json b/src/currencyservice/data/currency_conversion.json new file mode 100644 index 0000000..bd28709 --- /dev/null +++ b/src/currencyservice/data/currency_conversion.json @@ -0,0 +1,35 @@ +{ + "EUR": "1.0", + "USD": "1.1305", + "JPY": "126.40", + "BGN": "1.9558", + "CZK": "25.592", + "DKK": "7.4609", + "GBP": "0.85970", + "HUF": "315.51", + "PLN": "4.2996", + "RON": "4.7463", + "SEK": "10.5375", + "CHF": "1.1360", + "ISK": "136.80", + "NOK": "9.8040", + "HRK": "7.4210", + "RUB": "74.4208", + "TRY": "6.1247", + "AUD": "1.6072", + "BRL": "4.2682", + "CAD": "1.5128", + "CNY": "7.5857", + "HKD": "8.8743", + "IDR": "15999.40", + "ILS": "4.0875", + "INR": "79.4320", + "KRW": "1275.05", + "MXN": "21.7999", + "MYR": "4.6289", + "NZD": "1.6679", + "PHP": "59.083", + "SGD": "1.5349", + "THB": "36.012", + "ZAR": "16.0583" +} \ No newline at end of file diff --git a/src/currencyservice/server.js b/src/currencyservice/server.js index 633078c..0b231b0 100644 --- a/src/currencyservice/server.js +++ b/src/currencyservice/server.js @@ -30,8 +30,6 @@ require('@google-cloud/debug-agent').start({ const path = require('path'); const grpc = require('grpc'); -const request = require('request'); -const xml2js = require('xml2js'); const pino = require('pino'); const protoLoader = require('@grpc/proto-loader'); @@ -39,7 +37,6 @@ const MAIN_PROTO_PATH = path.join(__dirname, './proto/demo.proto'); const HEALTH_PROTO_PATH = path.join(__dirname, './proto/grpc/health/v1/health.proto'); const PORT = 7000; -const DATA_URL = 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml'; const shopProto = _loadProto(MAIN_PROTO_PATH).hipstershop; const healthProto = _loadProto(HEALTH_PROTO_PATH).grpc.health.v1; @@ -69,36 +66,12 @@ function _loadProto (path) { } /** - * Helper function that gets currency data from an XML webpage + * Helper function that gets currency data from a stored JSON file * Uses public data from European Central Bank */ -let _data; function _getCurrencyData (callback) { - if (!_data) { - logger.info('Fetching currency data...'); - request(DATA_URL, (err, res) => { - if (err) { - throw new Error(`Error getting data: ${err}`); - } - - const body = res.body.split('\n').slice(7, -2).join('\n'); - xml2js.parseString(body, (err, resJs) => { - if (err) { - throw new Error(`Error parsing HTML: ${err}`); - } - - const array = resJs['Cube']['Cube'].map(x => x['$']); - const results = array.reduce((acc, x) => { - acc[x['currency']] = x['rate']; - return acc; - }, { 'EUR': '1.0' }); - _data = results; - callback(_data); - }); - }); - } else { - callback(_data); - } + const data = require('./data/currency_conversion.json'); + callback(data); } /** From b72f32d66d5c6cca839078e96d83b234bb9b7a9d Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Wed, 6 Mar 2019 23:23:28 -0800 Subject: [PATCH 78/91] istio-manifests: remove external currency api (#175) this is not unused per #173. Signed-off-by: Ahmet Alp Balkan --- .../whitelist-egress-currencyprovider.yaml | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 istio-manifests/whitelist-egress-currencyprovider.yaml diff --git a/istio-manifests/whitelist-egress-currencyprovider.yaml b/istio-manifests/whitelist-egress-currencyprovider.yaml deleted file mode 100644 index 8523fc0..0000000 --- a/istio-manifests/whitelist-egress-currencyprovider.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2018 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -apiVersion: networking.istio.io/v1alpha3 -kind: ServiceEntry -metadata: - name: currency-provider-external -spec: - hosts: - - www.ecb.europa.eu - ports: - - number: 80 - name: http - protocol: HTTP - - number: 443 - name: https - protocol: HTTPS From d23fe9cf33f0445f50f35f1927293c03c6ecd537 Mon Sep 17 00:00:00 2001 From: Heechul Ryu Date: Fri, 8 Mar 2019 02:54:40 +0900 Subject: [PATCH 79/91] Fix the half-broken url for skaffold installation (#178) * Fix the half-broken url for skaffold installation * fix install skaffold link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fc3101b..b5cd317 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ We offer three installation methods: - kubectl (can be installed via `gcloud components install kubectl`) - Docker for Desktop (Mac/Windows): It provides Kubernetes support as [noted here](https://docs.docker.com/docker-for-mac/kubernetes/). - - [skaffold](https://github.com/GoogleContainerTools/skaffold/#installation) + - [skaffold](https://skaffold.dev/docs/getting-started/#installing-skaffold) (ensure version ≥v0.20) 1. Launch “Docker for Desktop”. Go to Preferences: From 342318a9aef7514c91c08a61eb42fde414976c29 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Thu, 7 Mar 2019 09:54:56 -0800 Subject: [PATCH 80/91] hack: remove redundant license headers in release (#171) * remove per-yaml license headers in release manifests * manually insert a license header in release manifests * add README.md to /kubernetes-manifests indicating they're not ready to use (and refer to /release instead). * regenerate manifests Signed-off-by: Ahmet Alp Balkan --- hack/license_header.txt | 13 ++ hack/make-release-artifacts.sh | 24 +++- kubernetes-manifests/README.md | 8 ++ release/istio-manifests.yaml | 56 -------- release/kubernetes-manifests.yaml | 218 +++++++----------------------- 5 files changed, 96 insertions(+), 223 deletions(-) create mode 100644 hack/license_header.txt create mode 100644 kubernetes-manifests/README.md diff --git a/hack/license_header.txt b/hack/license_header.txt new file mode 100644 index 0000000..2e94f3e --- /dev/null +++ b/hack/license_header.txt @@ -0,0 +1,13 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/hack/make-release-artifacts.sh b/hack/make-release-artifacts.sh index 2a14ae5..2f412e7 100755 --- a/hack/make-release-artifacts.sh +++ b/hack/make-release-artifacts.sh @@ -27,12 +27,31 @@ TAG="${TAG:?TAG env variable must be specified}" REPO_PREFIX="${REPO_PREFIX:?REPO_PREFIX env variable must be specified}" OUT_DIR="${OUT_DIR:-${SCRIPTDIR}/../release}" +print_license_header() { + cat "${SCRIPTDIR}/license_header.txt" + echo +} + +print_autogenerated_warning() { + cat< Date: Thu, 7 Mar 2019 12:12:26 -0800 Subject: [PATCH 81/91] update the architecture diagram (#179) - remove external service call of currencyservice - add a dependency to productcatalog from checkout service. --- docs/img/architecture-diagram.png | Bin 79591 -> 72467 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/img/architecture-diagram.png b/docs/img/architecture-diagram.png index 91a8a18f29737d802fec3ff4c91867bbe150bb0e..c95d84b3c6636582ae469595a4ae7c754e70ef9a 100644 GIT binary patch literal 72467 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�DKUjCXc4A!(M0603w@kFA6pnYlxI{D5 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 From a0a9852afe969ff6d70e59f5ea75942b971eea78 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Thu, 7 Mar 2019 23:29:18 -0800 Subject: [PATCH 82/91] hack: comment out autogenerated warning (#182) Fixes #181. --- hack/make-release-artifacts.sh | 8 +++++--- release/istio-manifests.yaml | 18 ++++++++++++++++++ release/kubernetes-manifests.yaml | 6 +++--- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/hack/make-release-artifacts.sh b/hack/make-release-artifacts.sh index 2f412e7..507277c 100755 --- a/hack/make-release-artifacts.sh +++ b/hack/make-release-artifacts.sh @@ -34,9 +34,9 @@ print_license_header() { print_autogenerated_warning() { cat< Date: Mon, 11 Mar 2019 07:49:27 -0700 Subject: [PATCH 83/91] Update ServiceEntries for Istio 1.1 (#183) --- .../whitelist-egress-googleapis.yaml | 20 ++++++++++++++++--- release/istio-manifests.yaml | 20 ++++++++++++++++--- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/istio-manifests/whitelist-egress-googleapis.yaml b/istio-manifests/whitelist-egress-googleapis.yaml index 92ead32..60e0221 100644 --- a/istio-manifests/whitelist-egress-googleapis.yaml +++ b/istio-manifests/whitelist-egress-googleapis.yaml @@ -18,9 +18,6 @@ metadata: name: whitelist-egress-googleapis spec: hosts: - - "169.254.169.254" # GCE metadata server - - "metadata.google" # GCE metadata server - - "metadata.google.internal" # GCE metadata server - "accounts.google.com" # Used to get token - "*.googleapis.com" ports: @@ -30,3 +27,20 @@ spec: - number: 443 protocol: HTTPS name: https +--- +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: whitelist-egress-google-metadata +spec: + hosts: + - metadata.google.internal + addresses: + - 169.254.169.254 # GCE metadata server + ports: + - number: 80 + name: http + protocol: HTTP + - number: 443 + name: https + protocol: HTTPS diff --git a/release/istio-manifests.yaml b/release/istio-manifests.yaml index fb89f70..284131d 100644 --- a/release/istio-manifests.yaml +++ b/release/istio-manifests.yaml @@ -82,9 +82,6 @@ metadata: name: whitelist-egress-googleapis spec: hosts: - - "169.254.169.254" # GCE metadata server - - "metadata.google" # GCE metadata server - - "metadata.google.internal" # GCE metadata server - "accounts.google.com" # Used to get token - "*.googleapis.com" ports: @@ -95,3 +92,20 @@ spec: protocol: HTTPS name: https --- +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: whitelist-egress-google-metadata +spec: + hosts: + - metadata.google.internal + addresses: + - 169.254.169.254 # GCE metadata server + ports: + - number: 80 + name: http + protocol: HTTP + - number: 443 + name: https + protocol: HTTPS +--- From 9d95e4ce15d8911543c9c2c53e3c47b744496ae1 Mon Sep 17 00:00:00 2001 From: Ahmet Alp Balkan Date: Thu, 14 Mar 2019 00:02:32 -0700 Subject: [PATCH 84/91] Add min disk space for docker-for-desktop --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b5cd317..d0c00c6 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ We offer three installation methods: - choose “Enable Kubernetes”, - set CPUs to at least 3, and Memory to at least 6.0 GiB + - on the "Disk" tab, set at least 32 GB disk space 1. Run `kubectl get nodes` to verify you're connected to “Kubernetes on Docker”. From 0cccf586a41b0b39f91aaf2ccbd0e721c5d73a74 Mon Sep 17 00:00:00 2001 From: Mohamed Shahat Date: Thu, 14 Mar 2019 22:29:37 +0000 Subject: [PATCH 85/91] Update development-principles.md (#195) correct wording --- docs/development-principles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/development-principles.md b/docs/development-principles.md index 0deae0c..2e840f2 100644 --- a/docs/development-principles.md +++ b/docs/development-principles.md @@ -5,7 +5,7 @@ ### Minimal configuration -Running the demo locally or on GCP should not require minimal to no +Running the demo locally or on GCP should require minimal to no configuration unless absolutely necessary to run critical parts of the demo. Configuration that takes multiple steps, especially such as creating service From a84331eda142178eef8115b4a2708cfbde6b29d5 Mon Sep 17 00:00:00 2001 From: "Riccardo M. Cefala" Date: Wed, 27 Mar 2019 15:54:56 +0000 Subject: [PATCH 86/91] make hack/make-release-artifacts.sh work on Linux (#201) --- hack/make-release-artifacts.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hack/make-release-artifacts.sh b/hack/make-release-artifacts.sh index 507277c..10fcb25 100755 --- a/hack/make-release-artifacts.sh +++ b/hack/make-release-artifacts.sh @@ -41,6 +41,10 @@ print_autogenerated_warning() { EOF } +# define gsed as a function on Linux for compatibility +[ "$(uname -s)" == "Linux" ] && gsed() { + sed "$@" +} read_manifests() { local dir From 3f9dc859657cd0652e88d440946331c8c58f0565 Mon Sep 17 00:00:00 2001 From: Ihor Dvoretskyi Date: Fri, 29 Mar 2019 18:25:34 +0200 Subject: [PATCH 87/91] Cleanup instructions added (#202) * Cleanup instrucions added Signed-off-by: Ihor Dvoretskyi * Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index d0c00c6..7a14baf 100644 --- a/README.md +++ b/README.md @@ -254,6 +254,15 @@ by deploying the [release manifest](./release) directly to an existing cluster. curl -v "http://$INGRESS_HOST" ``` +### Cleanup + +If you've deployed the application with `skaffold run` command, you can run +`skaffold delete` to clean up the deployed resources. + +If you've deployed the application with `kubectl apply -f [...]`, you can +run `kubectl delete -f [...]` with the same argument to clean up the deployed +resources. + ## Conferences featuring Hipster Shop - [Google Cloud Next'18 London – Keynote](https://youtu.be/nIq2pkNcfEI?t=3071) From 57b316c0455f69d314f9e80d59b88493c3ea508e Mon Sep 17 00:00:00 2001 From: Pradip Caulagi Date: Mon, 1 Apr 2019 19:50:44 +0200 Subject: [PATCH 88/91] Update docker images for go to 1.12 (#203) --- src/checkoutservice/Dockerfile | 2 +- src/frontend/Dockerfile | 2 +- src/productcatalogservice/Dockerfile | 2 +- src/shippingservice/Dockerfile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/checkoutservice/Dockerfile b/src/checkoutservice/Dockerfile index 6099109..8f0ea6d 100644 --- a/src/checkoutservice/Dockerfile +++ b/src/checkoutservice/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.10-alpine as builder +FROM golang:1.12-alpine as builder RUN apk add --no-cache ca-certificates git && \ wget -qO/go/bin/dep https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 && \ chmod +x /go/bin/dep diff --git a/src/frontend/Dockerfile b/src/frontend/Dockerfile index b7d5c92..591a3ae 100644 --- a/src/frontend/Dockerfile +++ b/src/frontend/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.10-alpine as builder +FROM golang:1.12-alpine as builder RUN apk add --no-cache ca-certificates git && \ wget -qO/go/bin/dep https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 && \ chmod +x /go/bin/dep diff --git a/src/productcatalogservice/Dockerfile b/src/productcatalogservice/Dockerfile index 82deb04..b8f60dd 100644 --- a/src/productcatalogservice/Dockerfile +++ b/src/productcatalogservice/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.10-alpine AS builder +FROM golang:1.12-alpine AS builder RUN apk add --no-cache ca-certificates git && \ wget -qO/go/bin/dep https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 && \ chmod +x /go/bin/dep diff --git a/src/shippingservice/Dockerfile b/src/shippingservice/Dockerfile index 2b80a7e..80ac159 100644 --- a/src/shippingservice/Dockerfile +++ b/src/shippingservice/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.10-alpine as builder +FROM golang:1.12-alpine as builder RUN apk add --no-cache ca-certificates git && \ wget -qO/go/bin/dep https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 && \ chmod +x /go/bin/dep From f2f382f6bb8b205fce90a8744739f9399ba56dbd Mon Sep 17 00:00:00 2001 From: Dinesh Bolkensteyn Date: Wed, 17 Apr 2019 18:00:38 +0200 Subject: [PATCH 89/91] README: Point to Skaffold's website rather than repo (#208) All mentioned projects (Kubernetes, Istio, etc.) point to their websites expect for Skaffold that points to its source code repository. The website should be a better entry point to understand the big picture, access the quickstart guides and more in-depth howtos. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a14baf..5d375fb 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Find **Protocol Buffers Descriptions** at the [`./pb` directory](./pb). addition to these, using Istio enables features like Request/Response **Metrics** and **Context Graph** out of the box. When it is running out of Google Cloud, this code path remains inactive. -- **[Skaffold](https://github.com/GoogleContainerTools/skaffold):** Application +- **[Skaffold](https://skaffold.dev):** Application is deployed to Kubernetes with a single command using Skaffold. - **Synthetic Load Generation:** The application demo comes with a background job that creates realistic usage patterns on the website using From f276995585251b7b88554ff563b41e857a12d2dd Mon Sep 17 00:00:00 2001 From: Chris Proto Date: Tue, 30 Apr 2019 12:46:50 -0400 Subject: [PATCH 90/91] Follow OWASP best practices on CC presentation on checkout form (#207) * Follow OWASP best practices on CC presentation on checkout form See OWASP recommendations here: * Use `input type=password` * Set `autocomplete="off"` * Change credit_card_number input type back to "text" --- src/frontend/templates/cart.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontend/templates/cart.html b/src/frontend/templates/cart.html index 938d45d..9bd53d6 100644 --- a/src/frontend/templates/cart.html +++ b/src/frontend/templates/cart.html @@ -132,7 +132,8 @@
-
From 86fb1662a39d9b819f7203bf8feede041d8d4489 Mon Sep 17 00:00:00 2001 From: Kalyana Chadalavada Date: Fri, 3 May 2019 10:29:34 -0700 Subject: [PATCH 91/91] Add Stackdriver Profiler Python agent (#176) * Add Stackdriver Profiler Python agent to EmailService and RecommendationService * Update recommendation_server.py * Moved Profiler init to a function * Moved Profiler init to a function * Delete key.json * Delete key.json * Delete key.json --- kubernetes-manifests/emailservice.yaml | 3 ++ .../recommendationservice.yaml | 2 ++ src/emailservice/Dockerfile | 6 +++- src/emailservice/email_server.py | 35 +++++++++++++++++++ src/emailservice/requirements.in | 1 + src/emailservice/requirements.txt | 13 ++++--- src/recommendationservice/Dockerfile | 2 +- .../recommendation_server.py | 34 ++++++++++++++++++ src/recommendationservice/requirements.in | 1 + src/recommendationservice/requirements.txt | 13 ++++--- 10 files changed, 97 insertions(+), 13 deletions(-) diff --git a/kubernetes-manifests/emailservice.yaml b/kubernetes-manifests/emailservice.yaml index c5dd7d8..179db0e 100644 --- a/kubernetes-manifests/emailservice.yaml +++ b/kubernetes-manifests/emailservice.yaml @@ -39,6 +39,9 @@ spec: periodSeconds: 5 exec: command: ["/bin/grpc_health_probe", "-addr=:8080"] + env: + - name: ENABLE_PROFILER + value: "0" resources: requests: cpu: 100m diff --git a/kubernetes-manifests/recommendationservice.yaml b/kubernetes-manifests/recommendationservice.yaml index 07d4c27..eeb7782 100644 --- a/kubernetes-manifests/recommendationservice.yaml +++ b/kubernetes-manifests/recommendationservice.yaml @@ -42,6 +42,8 @@ spec: env: - name: PRODUCT_CATALOG_SERVICE_ADDR value: "productcatalogservice:3550" + - name: ENABLE_PROFILER + value: "0" resources: requests: cpu: 100m diff --git a/src/emailservice/Dockerfile b/src/emailservice/Dockerfile index b4b2a94..3d649a5 100644 --- a/src/emailservice/Dockerfile +++ b/src/emailservice/Dockerfile @@ -2,12 +2,16 @@ FROM python:3-slim as base FROM base as builder +RUN apt-get -qq update \ + && apt-get install -y --no-install-recommends \ + g++ \ + && rm -rf /var/lib/apt/lists/* + # get packages COPY requirements.txt . RUN pip install -r requirements.txt FROM base as final - # Enable unbuffered logging ENV PYTHONUNBUFFERED=1 diff --git a/src/emailservice/email_server.py b/src/emailservice/email_server.py index f4a2162..5af5ff9 100644 --- a/src/emailservice/email_server.py +++ b/src/emailservice/email_server.py @@ -33,6 +33,7 @@ from opencensus.trace.ext.grpc import server_interceptor from opencensus.trace.samplers import always_on # import googleclouddebugger +import googlecloudprofiler try: sampler = always_on.AlwaysOnSampler() @@ -143,7 +144,41 @@ def start(dummy_mode): except KeyboardInterrupt: server.stop(0) +def initStackdriverProfiling(): + project_id = None + try: + project_id = os.environ["GCP_PROJECT_ID"] + except KeyError: + # Environment variable not set + pass + + for retry in range(1,4): + try: + if project_id: + googlecloudprofiler.start(service='email_server', service_version='1.0.0', verbose=0, project_id=project_id) + else: + googlecloudprofiler.start(service='email_server', service_version='1.0.0', verbose=0) + logger.info("Successfully started Stackdriver Profiler.") + return + except (BaseException) as exc: + logger.info("Unable to start Stackdriver Profiler Python agent. " + str(exc)) + if (retry < 4): + logger.info("Sleeping %d to retry initializing Stackdriver Profiler"%(retry*10)) + time.sleep (1) + else: + logger.warning("Could not initialize Stackdriver Profiler after retrying, giving up") + return if __name__ == '__main__': logger.info('starting the email service in dummy mode.') + try: + enable_profiler = os.environ["ENABLE_PROFILER"] + if enable_profiler != "1": + raise KeyError() + else: + initStackdriverProfiling() + except KeyError: + logger.info("Skipping Stackdriver Profiler Python agent initialization. Set environment variable ENABLE_PROFILER=1 to enable.") + + start(dummy_mode = True) diff --git a/src/emailservice/requirements.in b/src/emailservice/requirements.in index fa3f39c..bb60d5a 100644 --- a/src/emailservice/requirements.in +++ b/src/emailservice/requirements.in @@ -4,3 +4,4 @@ grpcio==1.16.1 jinja2==2.10 opencensus[stackdriver]==0.1.10 python-json-logger==0.1.9 +google-cloud-profiler==1.0.8 diff --git a/src/emailservice/requirements.txt b/src/emailservice/requirements.txt index 6a763b2..c0d5346 100644 --- a/src/emailservice/requirements.txt +++ b/src/emailservice/requirements.txt @@ -8,22 +8,27 @@ cachetools==3.0.0 # via google-auth certifi==2018.11.29 # via requests chardet==3.0.4 # via requests google-api-core[grpc]==1.6.0 -google-auth==1.6.2 # via google-api-core +google-api-python-client==1.7.8 # via google-cloud-profiler +google-auth-httplib2==0.0.3 # via google-api-python-client, google-cloud-profiler +google-auth==1.6.2 # via google-api-core, google-api-python-client, google-auth-httplib2, google-cloud-profiler google-cloud-core==0.29.1 # via google-cloud-trace +google-cloud-profiler==1.0.8 google-cloud-trace==0.20.2 # via opencensus googleapis-common-protos==1.5.5 # via google-api-core grpcio-health-checking==1.12.1 grpcio==1.16.1 +httplib2==0.12.1 # via google-api-python-client, google-auth-httplib2 idna==2.8 # via requests jinja2==2.10 markupsafe==1.1.0 # via jinja2 opencensus[stackdriver]==0.1.10 -protobuf==3.6.1 # via google-api-core, googleapis-common-protos, grpcio-health-checking +protobuf==3.6.1 # via google-api-core, google-cloud-profiler, googleapis-common-protos, grpcio-health-checking pyasn1-modules==0.2.3 # via google-auth pyasn1==0.4.5 # via pyasn1-modules, rsa python-json-logger==0.1.9 pytz==2018.9 # via google-api-core -requests==2.21.0 # via google-api-core +requests==2.21.0 # via google-api-core, google-cloud-profiler rsa==4.0 # via google-auth -six==1.12.0 # via google-api-core, google-auth, grpcio, protobuf +six==1.12.0 # via google-api-core, google-api-python-client, google-auth, grpcio, protobuf +uritemplate==3.0.0 # via google-api-python-client urllib3==1.24.1 # via requests diff --git a/src/recommendationservice/Dockerfile b/src/recommendationservice/Dockerfile index 3faff32..fc70bec 100644 --- a/src/recommendationservice/Dockerfile +++ b/src/recommendationservice/Dockerfile @@ -1,6 +1,6 @@ FROM python:2.7-slim RUN apt-get update -qqy && \ - apt-get -qqy install wget && \ + apt-get -qqy install wget g++ && \ rm -rf /var/lib/apt/lists/* # show python logs as they occur ENV PYTHONUNBUFFERED=0 diff --git a/src/recommendationservice/recommendation_server.py b/src/recommendationservice/recommendation_server.py index eb24f96..357f25f 100644 --- a/src/recommendationservice/recommendation_server.py +++ b/src/recommendationservice/recommendation_server.py @@ -21,6 +21,7 @@ import traceback from concurrent import futures import googleclouddebugger +import googlecloudprofiler import grpc from opencensus.trace.exporters import print_exporter from opencensus.trace.exporters import stackdriver_exporter @@ -35,6 +36,30 @@ from grpc_health.v1 import health_pb2_grpc from logger import getJSONLogger logger = getJSONLogger('recommendationservice-server') +def initStackdriverProfiling(): + project_id = None + try: + project_id = os.environ["GCP_PROJECT_ID"] + except KeyError: + # Environment variable not set + pass + + for retry in xrange(1,4): + try: + if project_id: + googlecloudprofiler.start(service='recommendation_server', service_version='1.0.0', verbose=0, project_id=project_id) + else: + googlecloudprofiler.start(service='recommendation_server', service_version='1.0.0', verbose=0) + logger.info("Successfully started Stackdriver Profiler.") + return + except (BaseException) as exc: + logger.info("Unable to start Stackdriver Profiler Python agent. " + str(exc)) + if (retry < 4): + logger.info("Sleeping %d seconds to retry Stackdriver Profiler agent initialization"%(retry*10)) + time.sleep (1) + else: + logger.warning("Could not initialize Stackdriver Profiler after retrying, giving up") + return class RecommendationService(demo_pb2_grpc.RecommendationServiceServicer): def ListRecommendations(self, request, context): @@ -63,6 +88,15 @@ class RecommendationService(demo_pb2_grpc.RecommendationServiceServicer): if __name__ == "__main__": logger.info("initializing recommendationservice") + try: + enable_profiler = os.environ["ENABLE_PROFILER"] + if enable_profiler != "1": + raise KeyError() + else: + initStackdriverProfiling() + except KeyError: + logger.info("Skipping Stackdriver Profiler Python agent initialization. Set environment variable ENABLE_PROFILER=1 to enable.") + try: sampler = always_on.AlwaysOnSampler() exporter = stackdriver_exporter.StackdriverExporter() diff --git a/src/recommendationservice/requirements.in b/src/recommendationservice/requirements.in index 10d437d..bfc28a5 100644 --- a/src/recommendationservice/requirements.in +++ b/src/recommendationservice/requirements.in @@ -4,3 +4,4 @@ grpcio-health-checking==1.13.0 grpcio==1.16.1 opencensus[stackdriver]==0.1.10 python-json-logger==0.1.9 +google-cloud-profiler==1.0.8 diff --git a/src/recommendationservice/requirements.txt b/src/recommendationservice/requirements.txt index 50114b2..b504fff 100644 --- a/src/recommendationservice/requirements.txt +++ b/src/recommendationservice/requirements.txt @@ -7,13 +7,12 @@ cachetools==3.1.0 # via google-auth certifi==2018.11.29 # via requests chardet==3.0.4 # via requests -enum34==1.1.6 # via grpcio -futures==3.2.0 # via google-api-core, grpcio google-api-core[grpc]==1.6.0 -google-api-python-client==1.7.8 # via google-python-cloud-debugger -google-auth-httplib2==0.0.3 # via google-api-python-client, google-python-cloud-debugger -google-auth==1.6.2 # via google-api-core, google-api-python-client, google-auth-httplib2, google-python-cloud-debugger +google-api-python-client==1.7.8 # via google-cloud-profiler, google-python-cloud-debugger +google-auth-httplib2==0.0.3 # via google-api-python-client, google-cloud-profiler, google-python-cloud-debugger +google-auth==1.6.2 # via google-api-core, google-api-python-client, google-auth-httplib2, google-cloud-profiler, google-python-cloud-debugger google-cloud-core==0.29.1 # via google-cloud-trace +google-cloud-profiler==1.0.8 google-cloud-trace==0.20.2 # via opencensus google-python-cloud-debugger==2.9 googleapis-common-protos==1.5.6 # via google-api-core @@ -22,13 +21,13 @@ grpcio==1.16.1 httplib2==0.12.0 # via google-api-python-client, google-auth-httplib2 idna==2.8 # via requests opencensus[stackdriver]==0.1.10 -protobuf==3.6.1 # via google-api-core, googleapis-common-protos, grpcio-health-checking +protobuf==3.6.1 # via google-api-core, google-cloud-profiler, googleapis-common-protos, grpcio-health-checking pyasn1-modules==0.2.4 # via google-auth pyasn1==0.4.5 # via pyasn1-modules, rsa python-json-logger==0.1.9 pytz==2018.9 # via google-api-core pyyaml==3.13 # via google-python-cloud-debugger -requests==2.21.0 # via google-api-core +requests==2.21.0 # via google-api-core, google-cloud-profiler rsa==4.0 # via google-auth six==1.12.0 # via google-api-core, google-api-python-client, google-auth, google-python-cloud-debugger, grpcio, protobuf uritemplate==3.0.0 # via google-api-python-client