From f68768e284f3a6663fefd37978fbe0dc57b69cab Mon Sep 17 00:00:00 2001 From: mdmuminul Date: Fri, 27 Feb 2026 03:57:25 +0200 Subject: [PATCH 01/18] Check --- orchestrator/src/app.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/orchestrator/src/app.py b/orchestrator/src/app.py index 62d5d0662..9d8e24d4d 100644 --- a/orchestrator/src/app.py +++ b/orchestrator/src/app.py @@ -73,3 +73,6 @@ def checkout(): # This is useful for development. # The default port is 5000. app.run(host='0.0.0.0') + + +# Hello \ No newline at end of file From 6c41ef952ccab6ba727ec5eddeeb1df0012b8eb7 Mon Sep 17 00:00:00 2001 From: Qun Yan Li Date: Sat, 28 Feb 2026 09:20:42 +0200 Subject: [PATCH 02/18] https://chatgpt.com/s/t_69a2965bcc808191906e28d9aee7299c --- orchestrator/src/app.py | 26 ++++++++++++++++++++------ test_checkout.json | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 test_checkout.json diff --git a/orchestrator/src/app.py b/orchestrator/src/app.py index 62d5d0662..421232c11 100644 --- a/orchestrator/src/app.py +++ b/orchestrator/src/app.py @@ -50,12 +50,26 @@ def checkout(): """ Responds with a JSON object containing the order ID, status, and suggested books. """ - # Get request object data to json - request_data = json.loads(request.data) - # Print request object data - print("Request Data:", request_data.get('items')) + # Read the JSON body from the POST request + request_data = request.get_json(silent=True) - # Dummy response following the provided YAML specification for the bookstore + # If the request body is missing or invalid JSON, return a 400 error + if request_data is None: + return { + "error": { + "code": "BAD_REQUEST", + "message": "Request body must be valid JSON." + } + }, 400 + + # Print the full request and a few important parts + print("FULL REQUEST DATA:", request_data) + print("USER:", request_data.get("user")) + print("ITEMS:", request_data.get("items")) + print("SHIPPING METHOD:", request_data.get("shippingMethod")) + print("TERMS ACCEPTED:", request_data.get("termsAndConditionsAccepted")) + + # Still a dummy response for now order_status_response = { 'orderId': '12345', 'status': 'Order Approved', @@ -65,7 +79,7 @@ def checkout(): ] } - return order_status_response + return order_status_response, 200 if __name__ == '__main__': diff --git a/test_checkout.json b/test_checkout.json new file mode 100644 index 000000000..a78ba6f7a --- /dev/null +++ b/test_checkout.json @@ -0,0 +1,20 @@ +{ + "user": { + "name": "Test User", + "contact": "test@example.com", + "creditCard": { + "number": "4111111111111111", + "expirationDate": "12/30", + "cvv": "123" + }, + "userComment": "Please handle with care." + }, + "items": [ + { + "name": "Book A", + "quantity": 1 + } + ], + "shippingMethod": "Standard", + "termsAndConditionsAccepted": true +} From 419b9f203112b7cf1ed169a89024d282a12547af Mon Sep 17 00:00:00 2001 From: Qun Yan Li Date: Sat, 28 Feb 2026 09:37:21 +0200 Subject: [PATCH 03/18] Improve checkout parsing, logging, and basic validation --- orchestrator/src/app.py | 88 ++++++++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 18 deletions(-) diff --git a/orchestrator/src/app.py b/orchestrator/src/app.py index 421232c11..8d23bc7d5 100644 --- a/orchestrator/src/app.py +++ b/orchestrator/src/app.py @@ -50,10 +50,8 @@ def checkout(): """ Responds with a JSON object containing the order ID, status, and suggested books. """ - # Read the JSON body from the POST request request_data = request.get_json(silent=True) - # If the request body is missing or invalid JSON, return a 400 error if request_data is None: return { "error": { @@ -62,24 +60,78 @@ def checkout(): } }, 400 - # Print the full request and a few important parts + user = request_data.get("user", {}) + items = request_data.get("items", []) + shipping_method = request_data.get("shippingMethod") + terms_accepted = request_data.get("termsAndConditionsAccepted", False) + + user_name = user.get("name") + user_contact = user.get("contact") + user_comment = user.get("userComment", "") + + credit_card = user.get("creditCard", {}) + card_number = credit_card.get("number") + expiration_date = credit_card.get("expirationDate") + cvv = credit_card.get("cvv") + print("FULL REQUEST DATA:", request_data) - print("USER:", request_data.get("user")) - print("ITEMS:", request_data.get("items")) - print("SHIPPING METHOD:", request_data.get("shippingMethod")) - print("TERMS ACCEPTED:", request_data.get("termsAndConditionsAccepted")) - - # Still a dummy response for now - order_status_response = { - 'orderId': '12345', - 'status': 'Order Approved', - 'suggestedBooks': [ - {'bookId': '123', 'title': 'The Best Book', 'author': 'Author 1'}, - {'bookId': '456', 'title': 'The Second Best Book', 'author': 'Author 2'} - ] - } + print("USER NAME:", user_name) + print("USER CONTACT:", user_contact) + print("USER COMMENT:", user_comment) + print("ITEMS:", items) + print("SHIPPING METHOD:", shipping_method) + print("TERMS ACCEPTED:", terms_accepted) + print("CARD NUMBER:", card_number) + print("EXPIRATION DATE:", expiration_date) + print("CVV:", cvv) + + # Basic validation + if not user_name: + return { + "error": { + "code": "BAD_REQUEST", + "message": "User name is required." + } + }, 400 - return order_status_response, 200 + if not user_contact: + return { + "error": { + "code": "BAD_REQUEST", + "message": "User contact is required." + } + }, 400 + + if not items: + return { + "orderId": "12345", + "status": "Order Rejected", + "suggestedBooks": [] + }, 200 + + if not terms_accepted: + return { + "orderId": "12345", + "status": "Order Rejected", + "suggestedBooks": [] + }, 200 + + if not card_number or not expiration_date or not cvv: + return { + "orderId": "12345", + "status": "Order Rejected", + "suggestedBooks": [] + }, 200 + + # Dummy success response for now + return { + "orderId": "12345", + "status": "Order Approved", + "suggestedBooks": [ + {"bookId": "123", "title": "The Best Book", "author": "Author 1"}, + {"bookId": "456", "title": "The Second Best Book", "author": "Author 2"} + ] + }, 200 if __name__ == '__main__': From e38851effe80c2e2eecf900e31ec86e14a1a6777 Mon Sep 17 00:00:00 2001 From: Qun Yan Li Date: Sat, 28 Feb 2026 09:47:17 +0200 Subject: [PATCH 04/18] Add checkout validation tests and scaffold transaction_verification service --- test_checkout_empty_items.json | 15 +++++++++++++++ test_checkout_terms_false.json | 20 ++++++++++++++++++++ transaction_verification/Dockerfile | 0 transaction_verification/requirements.txt | 0 transaction_verification/src/app.py | 0 5 files changed, 35 insertions(+) create mode 100644 test_checkout_empty_items.json create mode 100644 test_checkout_terms_false.json create mode 100644 transaction_verification/Dockerfile create mode 100644 transaction_verification/requirements.txt create mode 100644 transaction_verification/src/app.py diff --git a/test_checkout_empty_items.json b/test_checkout_empty_items.json new file mode 100644 index 000000000..df39e004d --- /dev/null +++ b/test_checkout_empty_items.json @@ -0,0 +1,15 @@ +{ + "user": { + "name": "Test User", + "contact": "test@example.com", + "creditCard": { + "number": "4111111111111111", + "expirationDate": "12/30", + "cvv": "123" + }, + "userComment": "Please handle with care." + }, + "items": [], + "shippingMethod": "Standard", + "termsAndConditionsAccepted": true +} diff --git a/test_checkout_terms_false.json b/test_checkout_terms_false.json new file mode 100644 index 000000000..82087d4b1 --- /dev/null +++ b/test_checkout_terms_false.json @@ -0,0 +1,20 @@ +{ + "user": { + "name": "Test User", + "contact": "test@example.com", + "creditCard": { + "number": "4111111111111111", + "expirationDate": "12/30", + "cvv": "123" + }, + "userComment": "Please handle with care." + }, + "items": [ + { + "name": "Book A", + "quantity": 1 + } + ], + "shippingMethod": "Standard", + "termsAndConditionsAccepted": false +} diff --git a/transaction_verification/Dockerfile b/transaction_verification/Dockerfile new file mode 100644 index 000000000..e69de29bb diff --git a/transaction_verification/requirements.txt b/transaction_verification/requirements.txt new file mode 100644 index 000000000..e69de29bb diff --git a/transaction_verification/src/app.py b/transaction_verification/src/app.py new file mode 100644 index 000000000..e69de29bb From 8491cc9cb8b1622aff59727f17167d32ec79814e Mon Sep 17 00:00:00 2001 From: Qun Yan Li Date: Sat, 28 Feb 2026 10:12:05 +0200 Subject: [PATCH 05/18] Add transaction_verification gRPC service and Docker Compose setup --- docker-compose.yaml | 26 ++++++- transaction_verification/Dockerfile | 8 +++ transaction_verification/requirements.txt | 4 ++ transaction_verification/src/app.py | 67 +++++++++++++++++++ utils/pb/transaction_verification/__init__.py | 0 .../transaction_verification.proto | 22 ++++++ .../transaction_verification_pb2.py | 30 +++++++++ .../transaction_verification_pb2.pyi | 31 +++++++++ .../transaction_verification_pb2_grpc.py | 66 ++++++++++++++++++ 9 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 utils/pb/transaction_verification/__init__.py create mode 100644 utils/pb/transaction_verification/transaction_verification.proto create mode 100644 utils/pb/transaction_verification/transaction_verification_pb2.py create mode 100644 utils/pb/transaction_verification/transaction_verification_pb2.pyi create mode 100644 utils/pb/transaction_verification/transaction_verification_pb2_grpc.py diff --git a/docker-compose.yaml b/docker-compose.yaml index b4a60a537..a4ea5c994 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -13,6 +13,7 @@ services: volumes: # Mount the frontend directory - ./frontend/src:/usr/share/nginx/html + orchestrator: build: # Use the current directory as the build context @@ -35,12 +36,13 @@ services: - ./utils:/app/utils # Mount the orchestrator/src directory in the current directory to the /app/orchestrator/src directory in the container - ./orchestrator/src:/app/orchestrator/src + fraud_detection: build: # Use the current directory as the build context # This allows us to access the files in the current directory inside the Dockerfile context: ./ - # Use the Dockerfile in the fraud_detection directorys + # Use the Dockerfile in the fraud_detection directory dockerfile: ./fraud_detection/Dockerfile ports: # Expose port 50051 on the host, and map port 50051 of the container to port 50051 on the host @@ -56,4 +58,24 @@ services: # Mount the utils directory in the current directory to the /app/utils directory in the container - ./utils:/app/utils # Mount the fraud_detection/src directory in the current directory to the /app/fraud_detection/src directory in the container - - ./fraud_detection/src:/app/fraud_detection/src \ No newline at end of file + - ./fraud_detection/src:/app/fraud_detection/src + + transaction_verification: + build: + # Use the current directory as the build context + context: ./ + # Use the Dockerfile in the transaction_verification directory + dockerfile: ./transaction_verification/Dockerfile + ports: + # Expose port 50052 on the host, and map port 50052 of the container to port 50052 on the host + - 50052:50052 + environment: + # Pass the environment variables to the container + - PYTHONUNBUFFERED=TRUE + # The PYTHONFILE environment variable specifies the absolute entry point of the application + - PYTHONFILE=/app/transaction_verification/src/app.py + volumes: + # Mount the utils directory in the current directory to the /app/utils directory in the container + - ./utils:/app/utils + # Mount the transaction_verification/src directory in the current directory to the container + - ./transaction_verification/src:/app/transaction_verification/src \ No newline at end of file diff --git a/transaction_verification/Dockerfile b/transaction_verification/Dockerfile index e69de29bb..ad4936c4a 100644 --- a/transaction_verification/Dockerfile +++ b/transaction_verification/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.11 + +WORKDIR /app + +COPY ./transaction_verification/requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +CMD python utils/other/hotreload.py "transaction_verification/src/app.py" \ No newline at end of file diff --git a/transaction_verification/requirements.txt b/transaction_verification/requirements.txt index e69de29bb..43fdaf26f 100644 --- a/transaction_verification/requirements.txt +++ b/transaction_verification/requirements.txt @@ -0,0 +1,4 @@ +grpcio==1.60.0 +grpcio-tools==1.60.0 +protobuf==4.25.2 +watchdog==6.0.0 \ No newline at end of file diff --git a/transaction_verification/src/app.py b/transaction_verification/src/app.py index e69de29bb..36f592052 100644 --- a/transaction_verification/src/app.py +++ b/transaction_verification/src/app.py @@ -0,0 +1,67 @@ +import sys +import os +from concurrent import futures + +FILE = __file__ if '__file__' in globals() else os.getenv("PYTHONFILE", "") +transaction_verification_grpc_path = os.path.abspath( + os.path.join(FILE, '../../../utils/pb/transaction_verification') +) +sys.path.insert(0, transaction_verification_grpc_path) + +import grpc +import transaction_verification_pb2 as transaction_verification +import transaction_verification_pb2_grpc as transaction_verification_grpc + + +class TransactionVerificationService( + transaction_verification_grpc.TransactionVerificationServiceServicer +): + def VerifyTransaction(self, request, context): + print("Received transaction verification request") + print("user_name:", request.user_name) + print("user_contact:", request.user_contact) + print("item_count:", request.item_count) + print("terms_accepted:", request.terms_accepted) + + is_valid = True + message = "Transaction is valid." + + if not request.user_name: + is_valid = False + message = "Missing user name." + elif not request.user_contact: + is_valid = False + message = "Missing user contact." + elif request.item_count <= 0: + is_valid = False + message = "No items in order." + elif not request.terms_accepted: + is_valid = False + message = "Terms and conditions not accepted." + elif not request.card_number or not request.expiration_date or not request.cvv: + is_valid = False + message = "Missing credit card information." + + response = transaction_verification.TransactionVerificationResponse() + response.is_valid = is_valid + response.message = message + + print("Returning verification result:", response.is_valid, response.message) + return response + + +def serve(): + server = grpc.server(futures.ThreadPoolExecutor()) + transaction_verification_grpc.add_TransactionVerificationServiceServicer_to_server( + TransactionVerificationService(), server + ) + + port = "50052" + server.add_insecure_port("[::]:" + port) + server.start() + print("Transaction verification server started. Listening on port 50052.") + server.wait_for_termination() + + +if __name__ == '__main__': + serve() \ No newline at end of file diff --git a/utils/pb/transaction_verification/__init__.py b/utils/pb/transaction_verification/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/utils/pb/transaction_verification/transaction_verification.proto b/utils/pb/transaction_verification/transaction_verification.proto new file mode 100644 index 000000000..44ba9cec7 --- /dev/null +++ b/utils/pb/transaction_verification/transaction_verification.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +package transaction_verification; + +service TransactionVerificationService { + rpc VerifyTransaction (TransactionVerificationRequest) returns (TransactionVerificationResponse); +} + +message TransactionVerificationRequest { + string user_name = 1; + string user_contact = 2; + string card_number = 3; + string expiration_date = 4; + string cvv = 5; + int32 item_count = 6; + bool terms_accepted = 7; +} + +message TransactionVerificationResponse { + bool is_valid = 1; + string message = 2; +} \ No newline at end of file diff --git a/utils/pb/transaction_verification/transaction_verification_pb2.py b/utils/pb/transaction_verification/transaction_verification_pb2.py new file mode 100644 index 000000000..447731158 --- /dev/null +++ b/utils/pb/transaction_verification/transaction_verification_pb2.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: transaction_verification.proto +# Protobuf Python Version: 4.25.0 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1etransaction_verification.proto\x12\x18transaction_verification\"\xb0\x01\n\x1eTransactionVerificationRequest\x12\x11\n\tuser_name\x18\x01 \x01(\t\x12\x14\n\x0cuser_contact\x18\x02 \x01(\t\x12\x13\n\x0b\x63\x61rd_number\x18\x03 \x01(\t\x12\x17\n\x0f\x65xpiration_date\x18\x04 \x01(\t\x12\x0b\n\x03\x63vv\x18\x05 \x01(\t\x12\x12\n\nitem_count\x18\x06 \x01(\x05\x12\x16\n\x0eterms_accepted\x18\x07 \x01(\x08\"D\n\x1fTransactionVerificationResponse\x12\x10\n\x08is_valid\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t2\xab\x01\n\x1eTransactionVerificationService\x12\x88\x01\n\x11VerifyTransaction\x12\x38.transaction_verification.TransactionVerificationRequest\x1a\x39.transaction_verification.TransactionVerificationResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'transaction_verification_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_TRANSACTIONVERIFICATIONREQUEST']._serialized_start=61 + _globals['_TRANSACTIONVERIFICATIONREQUEST']._serialized_end=237 + _globals['_TRANSACTIONVERIFICATIONRESPONSE']._serialized_start=239 + _globals['_TRANSACTIONVERIFICATIONRESPONSE']._serialized_end=307 + _globals['_TRANSACTIONVERIFICATIONSERVICE']._serialized_start=310 + _globals['_TRANSACTIONVERIFICATIONSERVICE']._serialized_end=481 +# @@protoc_insertion_point(module_scope) diff --git a/utils/pb/transaction_verification/transaction_verification_pb2.pyi b/utils/pb/transaction_verification/transaction_verification_pb2.pyi new file mode 100644 index 000000000..5bb457074 --- /dev/null +++ b/utils/pb/transaction_verification/transaction_verification_pb2.pyi @@ -0,0 +1,31 @@ +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from typing import ClassVar as _ClassVar, Optional as _Optional + +DESCRIPTOR: _descriptor.FileDescriptor + +class TransactionVerificationRequest(_message.Message): + __slots__ = ("user_name", "user_contact", "card_number", "expiration_date", "cvv", "item_count", "terms_accepted") + USER_NAME_FIELD_NUMBER: _ClassVar[int] + USER_CONTACT_FIELD_NUMBER: _ClassVar[int] + CARD_NUMBER_FIELD_NUMBER: _ClassVar[int] + EXPIRATION_DATE_FIELD_NUMBER: _ClassVar[int] + CVV_FIELD_NUMBER: _ClassVar[int] + ITEM_COUNT_FIELD_NUMBER: _ClassVar[int] + TERMS_ACCEPTED_FIELD_NUMBER: _ClassVar[int] + user_name: str + user_contact: str + card_number: str + expiration_date: str + cvv: str + item_count: int + terms_accepted: bool + def __init__(self, user_name: _Optional[str] = ..., user_contact: _Optional[str] = ..., card_number: _Optional[str] = ..., expiration_date: _Optional[str] = ..., cvv: _Optional[str] = ..., item_count: _Optional[int] = ..., terms_accepted: bool = ...) -> None: ... + +class TransactionVerificationResponse(_message.Message): + __slots__ = ("is_valid", "message") + IS_VALID_FIELD_NUMBER: _ClassVar[int] + MESSAGE_FIELD_NUMBER: _ClassVar[int] + is_valid: bool + message: str + def __init__(self, is_valid: bool = ..., message: _Optional[str] = ...) -> None: ... diff --git a/utils/pb/transaction_verification/transaction_verification_pb2_grpc.py b/utils/pb/transaction_verification/transaction_verification_pb2_grpc.py new file mode 100644 index 000000000..32d7e091c --- /dev/null +++ b/utils/pb/transaction_verification/transaction_verification_pb2_grpc.py @@ -0,0 +1,66 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +import transaction_verification_pb2 as transaction__verification__pb2 + + +class TransactionVerificationServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.VerifyTransaction = channel.unary_unary( + '/transaction_verification.TransactionVerificationService/VerifyTransaction', + request_serializer=transaction__verification__pb2.TransactionVerificationRequest.SerializeToString, + response_deserializer=transaction__verification__pb2.TransactionVerificationResponse.FromString, + ) + + +class TransactionVerificationServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + + def VerifyTransaction(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_TransactionVerificationServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'VerifyTransaction': grpc.unary_unary_rpc_method_handler( + servicer.VerifyTransaction, + request_deserializer=transaction__verification__pb2.TransactionVerificationRequest.FromString, + response_serializer=transaction__verification__pb2.TransactionVerificationResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'transaction_verification.TransactionVerificationService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class TransactionVerificationService(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod + def VerifyTransaction(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/transaction_verification.TransactionVerificationService/VerifyTransaction', + transaction__verification__pb2.TransactionVerificationRequest.SerializeToString, + transaction__verification__pb2.TransactionVerificationResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) From 606456c4304a8f119f0ff9113dcc7da396d9e0d1 Mon Sep 17 00:00:00 2001 From: Qun Yan Li Date: Sat, 28 Feb 2026 10:30:05 +0200 Subject: [PATCH 06/18] Connect orchestrator to transaction_verification via gRPC --- orchestrator/src/app.py | 84 +++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 25 deletions(-) diff --git a/orchestrator/src/app.py b/orchestrator/src/app.py index 8d23bc7d5..67e48007f 100644 --- a/orchestrator/src/app.py +++ b/orchestrator/src/app.py @@ -5,13 +5,28 @@ # The path of the stubs is relative to the current file, or absolute inside the container. # Change these lines only if strictly needed. FILE = __file__ if '__file__' in globals() else os.getenv("PYTHONFILE", "") -fraud_detection_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/fraud_detection')) + +fraud_detection_grpc_path = os.path.abspath( + os.path.join(FILE, '../../../utils/pb/fraud_detection') +) sys.path.insert(0, fraud_detection_grpc_path) import fraud_detection_pb2 as fraud_detection import fraud_detection_pb2_grpc as fraud_detection_grpc +transaction_verification_grpc_path = os.path.abspath( + os.path.join(FILE, '../../../utils/pb/transaction_verification') +) +sys.path.insert(0, transaction_verification_grpc_path) +import transaction_verification_pb2 as transaction_verification +import transaction_verification_pb2_grpc as transaction_verification_grpc + import grpc +# Import Flask. +from flask import Flask, request +from flask_cors import CORS + + def greet(name='you'): # Establish a connection with the fraud-detection gRPC service. with grpc.insecure_channel('fraud_detection:50051') as channel: @@ -21,19 +36,33 @@ def greet(name='you'): response = stub.SayHello(fraud_detection.HelloRequest(name=name)) return response.greeting -# Import Flask. -# Flask is a web framework for Python. -# It allows you to build a web application quickly. -# For more information, see https://flask.palletsprojects.com/en/latest/ -from flask import Flask, request -from flask_cors import CORS -import json + +def verify_transaction(user_name, user_contact, card_number, expiration_date, cvv, item_count, terms_accepted): + # Establish a connection with the transaction_verification gRPC service. + with grpc.insecure_channel('transaction_verification:50052') as channel: + # Create a stub object. + stub = transaction_verification_grpc.TransactionVerificationServiceStub(channel) + # Call the service through the stub object. + response = stub.VerifyTransaction( + transaction_verification.TransactionVerificationRequest( + user_name=user_name or "", + user_contact=user_contact or "", + card_number=card_number or "", + expiration_date=expiration_date or "", + cvv=cvv or "", + item_count=item_count, + terms_accepted=terms_accepted + ) + ) + return response + # Create a simple Flask app. app = Flask(__name__) # Enable CORS for the app. CORS(app, resources={r'/*': {'origins': '*'}}) + # Define a GET endpoint. @app.route('/', methods=['GET']) def index(): @@ -45,6 +74,7 @@ def index(): # Return the response. return response + @app.route('/checkout', methods=['POST']) def checkout(): """ @@ -85,7 +115,7 @@ def checkout(): print("EXPIRATION DATE:", expiration_date) print("CVV:", cvv) - # Basic validation + # Keep these simple bad-request checks locally if not user_name: return { "error": { @@ -102,21 +132,25 @@ def checkout(): } }, 400 - if not items: - return { - "orderId": "12345", - "status": "Order Rejected", - "suggestedBooks": [] - }, 200 - - if not terms_accepted: - return { - "orderId": "12345", - "status": "Order Rejected", - "suggestedBooks": [] - }, 200 - - if not card_number or not expiration_date or not cvv: + item_count = len(items) + + print("Calling transaction_verification service...") + verification_response = verify_transaction( + user_name=user_name, + user_contact=user_contact, + card_number=card_number, + expiration_date=expiration_date, + cvv=cvv, + item_count=item_count, + terms_accepted=terms_accepted + ) + print( + "transaction_verification result:", + verification_response.is_valid, + verification_response.message + ) + + if not verification_response.is_valid: return { "orderId": "12345", "status": "Order Rejected", @@ -138,4 +172,4 @@ def checkout(): # Run the app in debug mode to enable hot reloading. # This is useful for development. # The default port is 5000. - app.run(host='0.0.0.0') + app.run(host='0.0.0.0') \ No newline at end of file From f8c3e61eb49e4de85d2b93be701d76faa83aee00 Mon Sep 17 00:00:00 2001 From: Qun Yan Li Date: Sat, 28 Feb 2026 10:51:50 +0200 Subject: [PATCH 07/18] Add suggestions gRPC service and connect it to orchestrator --- docker-compose.yaml | 15 ++++- orchestrator/src/app.py | 43 +++++++++++-- suggestions/Dockerfile | 8 +++ suggestions/requirements.txt | 4 ++ suggestions/src/app.py | 60 ++++++++++++++++++ utils/pb/suggestions/__init__.py | 0 utils/pb/suggestions/suggestions.proto | 22 +++++++ utils/pb/suggestions/suggestions_pb2.py | 32 ++++++++++ utils/pb/suggestions/suggestions_pb2.pyi | 30 +++++++++ utils/pb/suggestions/suggestions_pb2_grpc.py | 66 ++++++++++++++++++++ 10 files changed, 274 insertions(+), 6 deletions(-) create mode 100644 suggestions/Dockerfile create mode 100644 suggestions/requirements.txt create mode 100644 suggestions/src/app.py create mode 100644 utils/pb/suggestions/__init__.py create mode 100644 utils/pb/suggestions/suggestions.proto create mode 100644 utils/pb/suggestions/suggestions_pb2.py create mode 100644 utils/pb/suggestions/suggestions_pb2.pyi create mode 100644 utils/pb/suggestions/suggestions_pb2_grpc.py diff --git a/docker-compose.yaml b/docker-compose.yaml index a4ea5c994..e4818a9c8 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -78,4 +78,17 @@ services: # Mount the utils directory in the current directory to the /app/utils directory in the container - ./utils:/app/utils # Mount the transaction_verification/src directory in the current directory to the container - - ./transaction_verification/src:/app/transaction_verification/src \ No newline at end of file + - ./transaction_verification/src:/app/transaction_verification/src + + suggestions: + build: + context: ./ + dockerfile: ./suggestions/Dockerfile + ports: + - 50053:50053 + environment: + - PYTHONUNBUFFERED=TRUE + - PYTHONFILE=/app/suggestions/src/app.py + volumes: + - ./utils:/app/utils + - ./suggestions/src:/app/suggestions/src \ No newline at end of file diff --git a/orchestrator/src/app.py b/orchestrator/src/app.py index 67e48007f..94d5e8949 100644 --- a/orchestrator/src/app.py +++ b/orchestrator/src/app.py @@ -20,6 +20,13 @@ import transaction_verification_pb2 as transaction_verification import transaction_verification_pb2_grpc as transaction_verification_grpc +suggestions_grpc_path = os.path.abspath( + os.path.join(FILE, '../../../utils/pb/suggestions') +) +sys.path.insert(0, suggestions_grpc_path) +import suggestions_pb2 as suggestions +import suggestions_pb2_grpc as suggestions_grpc + import grpc # Import Flask. @@ -57,6 +64,21 @@ def verify_transaction(user_name, user_contact, card_number, expiration_date, cv return response +def get_suggestions(user_name, item_count): + # Establish a connection with the suggestions gRPC service. + with grpc.insecure_channel('suggestions:50053') as channel: + # Create a stub object. + stub = suggestions_grpc.SuggestionsServiceStub(channel) + # Call the service through the stub object. + response = stub.GetSuggestions( + suggestions.SuggestionsRequest( + user_name=user_name or "", + item_count=item_count + ) + ) + return response + + # Create a simple Flask app. app = Flask(__name__) # Enable CORS for the app. @@ -157,14 +179,25 @@ def checkout(): "suggestedBooks": [] }, 200 - # Dummy success response for now + print("Calling suggestions service...") + suggestions_response = get_suggestions( + user_name=user_name, + item_count=item_count + ) + print("suggestions returned:", len(suggestions_response.books), "books") + + suggested_books = [] + for book in suggestions_response.books: + suggested_books.append({ + "bookId": book.bookId, + "title": book.title, + "author": book.author + }) + return { "orderId": "12345", "status": "Order Approved", - "suggestedBooks": [ - {"bookId": "123", "title": "The Best Book", "author": "Author 1"}, - {"bookId": "456", "title": "The Second Best Book", "author": "Author 2"} - ] + "suggestedBooks": suggested_books }, 200 diff --git a/suggestions/Dockerfile b/suggestions/Dockerfile new file mode 100644 index 000000000..1c35664df --- /dev/null +++ b/suggestions/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.11 + +WORKDIR /app + +COPY ./suggestions/requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +CMD python utils/other/hotreload.py "suggestions/src/app.py" \ No newline at end of file diff --git a/suggestions/requirements.txt b/suggestions/requirements.txt new file mode 100644 index 000000000..43fdaf26f --- /dev/null +++ b/suggestions/requirements.txt @@ -0,0 +1,4 @@ +grpcio==1.60.0 +grpcio-tools==1.60.0 +protobuf==4.25.2 +watchdog==6.0.0 \ No newline at end of file diff --git a/suggestions/src/app.py b/suggestions/src/app.py new file mode 100644 index 000000000..258c2fb0c --- /dev/null +++ b/suggestions/src/app.py @@ -0,0 +1,60 @@ +import sys +import os +from concurrent import futures + +FILE = __file__ if '__file__' in globals() else os.getenv("PYTHONFILE", "") +suggestions_grpc_path = os.path.abspath( + os.path.join(FILE, '../../../utils/pb/suggestions') +) +sys.path.insert(0, suggestions_grpc_path) + +import grpc +import suggestions_pb2 as suggestions +import suggestions_pb2_grpc as suggestions_grpc + + +class SuggestionsService(suggestions_grpc.SuggestionsServiceServicer): + def GetSuggestions(self, request, context): + print("Received suggestions request") + print("user_name:", request.user_name) + print("item_count:", request.item_count) + + static_books = [ + {"bookId": "101", "title": "Distributed Systems Basics", "author": "A. Author"}, + {"bookId": "102", "title": "Designing Data-Intensive Applications", "author": "Martin Kleppmann"}, + {"bookId": "103", "title": "Clean Code", "author": "Robert C. Martin"}, + {"bookId": "104", "title": "The Pragmatic Programmer", "author": "Andrew Hunt"}, + ] + + response = suggestions.SuggestionsResponse() + + if request.item_count > 0: + chosen = static_books[:2] + else: + chosen = [] + + for book in chosen: + b = response.books.add() + b.bookId = book["bookId"] + b.title = book["title"] + b.author = book["author"] + + print("Returning", len(response.books), "suggested books") + return response + + +def serve(): + server = grpc.server(futures.ThreadPoolExecutor()) + suggestions_grpc.add_SuggestionsServiceServicer_to_server( + SuggestionsService(), server + ) + + port = "50053" + server.add_insecure_port("[::]:" + port) + server.start() + print("Suggestions server started. Listening on port 50053.") + server.wait_for_termination() + + +if __name__ == '__main__': + serve() \ No newline at end of file diff --git a/utils/pb/suggestions/__init__.py b/utils/pb/suggestions/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/utils/pb/suggestions/suggestions.proto b/utils/pb/suggestions/suggestions.proto new file mode 100644 index 000000000..12f15f4cb --- /dev/null +++ b/utils/pb/suggestions/suggestions.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +package suggestions; + +service SuggestionsService { + rpc GetSuggestions (SuggestionsRequest) returns (SuggestionsResponse); +} + +message SuggestionsRequest { + string user_name = 1; + int32 item_count = 2; +} + +message SuggestedBook { + string bookId = 1; + string title = 2; + string author = 3; +} + +message SuggestionsResponse { + repeated SuggestedBook books = 1; +} \ No newline at end of file diff --git a/utils/pb/suggestions/suggestions_pb2.py b/utils/pb/suggestions/suggestions_pb2.py new file mode 100644 index 000000000..550a4d48e --- /dev/null +++ b/utils/pb/suggestions/suggestions_pb2.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: suggestions.proto +# Protobuf Python Version: 4.25.0 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11suggestions.proto\x12\x0bsuggestions\";\n\x12SuggestionsRequest\x12\x11\n\tuser_name\x18\x01 \x01(\t\x12\x12\n\nitem_count\x18\x02 \x01(\x05\">\n\rSuggestedBook\x12\x0e\n\x06\x62ookId\x18\x01 \x01(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12\x0e\n\x06\x61uthor\x18\x03 \x01(\t\"@\n\x13SuggestionsResponse\x12)\n\x05\x62ooks\x18\x01 \x03(\x0b\x32\x1a.suggestions.SuggestedBook2i\n\x12SuggestionsService\x12S\n\x0eGetSuggestions\x12\x1f.suggestions.SuggestionsRequest\x1a .suggestions.SuggestionsResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'suggestions_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_SUGGESTIONSREQUEST']._serialized_start=34 + _globals['_SUGGESTIONSREQUEST']._serialized_end=93 + _globals['_SUGGESTEDBOOK']._serialized_start=95 + _globals['_SUGGESTEDBOOK']._serialized_end=157 + _globals['_SUGGESTIONSRESPONSE']._serialized_start=159 + _globals['_SUGGESTIONSRESPONSE']._serialized_end=223 + _globals['_SUGGESTIONSSERVICE']._serialized_start=225 + _globals['_SUGGESTIONSSERVICE']._serialized_end=330 +# @@protoc_insertion_point(module_scope) diff --git a/utils/pb/suggestions/suggestions_pb2.pyi b/utils/pb/suggestions/suggestions_pb2.pyi new file mode 100644 index 000000000..d3d31c343 --- /dev/null +++ b/utils/pb/suggestions/suggestions_pb2.pyi @@ -0,0 +1,30 @@ +from google.protobuf.internal import containers as _containers +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union + +DESCRIPTOR: _descriptor.FileDescriptor + +class SuggestionsRequest(_message.Message): + __slots__ = ("user_name", "item_count") + USER_NAME_FIELD_NUMBER: _ClassVar[int] + ITEM_COUNT_FIELD_NUMBER: _ClassVar[int] + user_name: str + item_count: int + def __init__(self, user_name: _Optional[str] = ..., item_count: _Optional[int] = ...) -> None: ... + +class SuggestedBook(_message.Message): + __slots__ = ("bookId", "title", "author") + BOOKID_FIELD_NUMBER: _ClassVar[int] + TITLE_FIELD_NUMBER: _ClassVar[int] + AUTHOR_FIELD_NUMBER: _ClassVar[int] + bookId: str + title: str + author: str + def __init__(self, bookId: _Optional[str] = ..., title: _Optional[str] = ..., author: _Optional[str] = ...) -> None: ... + +class SuggestionsResponse(_message.Message): + __slots__ = ("books",) + BOOKS_FIELD_NUMBER: _ClassVar[int] + books: _containers.RepeatedCompositeFieldContainer[SuggestedBook] + def __init__(self, books: _Optional[_Iterable[_Union[SuggestedBook, _Mapping]]] = ...) -> None: ... diff --git a/utils/pb/suggestions/suggestions_pb2_grpc.py b/utils/pb/suggestions/suggestions_pb2_grpc.py new file mode 100644 index 000000000..ca1154a0b --- /dev/null +++ b/utils/pb/suggestions/suggestions_pb2_grpc.py @@ -0,0 +1,66 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +import suggestions_pb2 as suggestions__pb2 + + +class SuggestionsServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetSuggestions = channel.unary_unary( + '/suggestions.SuggestionsService/GetSuggestions', + request_serializer=suggestions__pb2.SuggestionsRequest.SerializeToString, + response_deserializer=suggestions__pb2.SuggestionsResponse.FromString, + ) + + +class SuggestionsServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + + def GetSuggestions(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_SuggestionsServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetSuggestions': grpc.unary_unary_rpc_method_handler( + servicer.GetSuggestions, + request_deserializer=suggestions__pb2.SuggestionsRequest.FromString, + response_serializer=suggestions__pb2.SuggestionsResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'suggestions.SuggestionsService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class SuggestionsService(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod + def GetSuggestions(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/suggestions.SuggestionsService/GetSuggestions', + suggestions__pb2.SuggestionsRequest.SerializeToString, + suggestions__pb2.SuggestionsResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) From b9c7581477b76ffd3a97af35743c7c3260f8c2e9 Mon Sep 17 00:00:00 2001 From: Qun Yan Li Date: Sat, 28 Feb 2026 11:11:27 +0200 Subject: [PATCH 08/18] Add fraud detection gRPC check to checkout flow --- fraud_detection/src/app.py | 55 +++++++++++++------ orchestrator/src/app.py | 31 +++++++++++ test_checkout_fraud.json | 20 +++++++ .../pb/fraud_detection/fraud_detection.proto | 18 +++++- .../pb/fraud_detection/fraud_detection_pb2.py | 10 +++- .../fraud_detection/fraud_detection_pb2.pyi | 18 ++++++ .../fraud_detection_pb2_grpc.py | 33 +++++++++++ 7 files changed, 161 insertions(+), 24 deletions(-) create mode 100644 test_checkout_fraud.json diff --git a/fraud_detection/src/app.py b/fraud_detection/src/app.py index b2f1d2fce..d932ef47d 100644 --- a/fraud_detection/src/app.py +++ b/fraud_detection/src/app.py @@ -1,45 +1,64 @@ import sys import os +from concurrent import futures # This set of lines are needed to import the gRPC stubs. -# The path of the stubs is relative to the current file, or absolute inside the container. -# Change these lines only if strictly needed. FILE = __file__ if '__file__' in globals() else os.getenv("PYTHONFILE", "") -fraud_detection_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/fraud_detection')) +fraud_detection_grpc_path = os.path.abspath( + os.path.join(FILE, '../../../utils/pb/fraud_detection') +) sys.path.insert(0, fraud_detection_grpc_path) + +import grpc import fraud_detection_pb2 as fraud_detection import fraud_detection_pb2_grpc as fraud_detection_grpc -import grpc -from concurrent import futures -# Create a class to define the server functions, derived from -# fraud_detection_pb2_grpc.HelloServiceServicer class HelloService(fraud_detection_grpc.HelloServiceServicer): - # Create an RPC function to say hello def SayHello(self, request, context): - # Create a HelloResponse object response = fraud_detection.HelloResponse() - # Set the greeting field of the response object response.greeting = "Hello, " + request.name - # Print the greeting message print(response.greeting) - # Return the response object return response + def CheckFraud(self, request, context): + print("Received fraud check request") + print("user_name:", request.user_name) + print("card_number:", request.card_number) + print("item_count:", request.item_count) + + is_fraud = False + message = "No fraud detected." + + # Very simple dummy rules for now + if request.item_count > 10: + is_fraud = True + message = "Too many items in order." + elif request.card_number.endswith("0000"): + is_fraud = True + message = "Suspicious card number pattern." + elif "fraud" in request.user_name.lower(): + is_fraud = True + message = "Suspicious user name." + + response = fraud_detection.FraudCheckResponse() + response.is_fraud = is_fraud + response.message = message + + print("Returning fraud result:", response.is_fraud, response.message) + return response + + def serve(): - # Create a gRPC server server = grpc.server(futures.ThreadPoolExecutor()) - # Add HelloService fraud_detection_grpc.add_HelloServiceServicer_to_server(HelloService(), server) - # Listen on port 50051 + port = "50051" server.add_insecure_port("[::]:" + port) - # Start the server server.start() - print("Server started. Listening on port 50051.") - # Keep thread alive + print("Fraud detection server started. Listening on port 50051.") server.wait_for_termination() + if __name__ == '__main__': serve() \ No newline at end of file diff --git a/orchestrator/src/app.py b/orchestrator/src/app.py index 94d5e8949..2b5045787 100644 --- a/orchestrator/src/app.py +++ b/orchestrator/src/app.py @@ -44,6 +44,22 @@ def greet(name='you'): return response.greeting +def detect_fraud(user_name, card_number, item_count): + # Establish a connection with the fraud-detection gRPC service. + with grpc.insecure_channel('fraud_detection:50051') as channel: + # Create a stub object. + stub = fraud_detection_grpc.HelloServiceStub(channel) + # Call the service through the stub object. + response = stub.CheckFraud( + fraud_detection.FraudCheckRequest( + user_name=user_name or "", + card_number=card_number or "", + item_count=item_count + ) + ) + return response + + def verify_transaction(user_name, user_contact, card_number, expiration_date, cvv, item_count, terms_accepted): # Establish a connection with the transaction_verification gRPC service. with grpc.insecure_channel('transaction_verification:50052') as channel: @@ -156,6 +172,21 @@ def checkout(): item_count = len(items) + print("Calling fraud_detection service...") + fraud_response = detect_fraud( + user_name=user_name, + card_number=card_number, + item_count=item_count + ) + print("fraud_detection result:", fraud_response.is_fraud, fraud_response.message) + + if fraud_response.is_fraud: + return { + "orderId": "12345", + "status": "Order Rejected", + "suggestedBooks": [] + }, 200 + print("Calling transaction_verification service...") verification_response = verify_transaction( user_name=user_name, diff --git a/test_checkout_fraud.json b/test_checkout_fraud.json new file mode 100644 index 000000000..8c7677348 --- /dev/null +++ b/test_checkout_fraud.json @@ -0,0 +1,20 @@ +{ + "user": { + "name": "Test User", + "contact": "test@example.com", + "creditCard": { + "number": "4111111111110000", + "expirationDate": "12/30", + "cvv": "123" + }, + "userComment": "Please handle with care." + }, + "items": [ + { + "name": "Book A", + "quantity": 1 + } + ], + "shippingMethod": "Standard", + "termsAndConditionsAccepted": true +} diff --git a/utils/pb/fraud_detection/fraud_detection.proto b/utils/pb/fraud_detection/fraud_detection.proto index db20211d7..d575366b1 100644 --- a/utils/pb/fraud_detection/fraud_detection.proto +++ b/utils/pb/fraud_detection/fraud_detection.proto @@ -3,13 +3,25 @@ syntax = "proto3"; package hello; service HelloService { - rpc SayHello (HelloRequest) returns (HelloResponse); + rpc SayHello (HelloRequest) returns (HelloResponse); + rpc CheckFraud (FraudCheckRequest) returns (FraudCheckResponse); } message HelloRequest { - string name = 1; + string name = 1; } message HelloResponse { - string greeting = 1; + string greeting = 1; } + +message FraudCheckRequest { + string user_name = 1; + string card_number = 2; + int32 item_count = 3; +} + +message FraudCheckResponse { + bool is_fraud = 1; + string message = 2; +} \ No newline at end of file diff --git a/utils/pb/fraud_detection/fraud_detection_pb2.py b/utils/pb/fraud_detection/fraud_detection_pb2.py index cdd0bcae8..d405d9cf5 100644 --- a/utils/pb/fraud_detection/fraud_detection_pb2.py +++ b/utils/pb/fraud_detection/fraud_detection_pb2.py @@ -14,7 +14,7 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66raud_detection.proto\x12\x05hello\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"!\n\rHelloResponse\x12\x10\n\x08greeting\x18\x01 \x01(\t2E\n\x0cHelloService\x12\x35\n\x08SayHello\x12\x13.hello.HelloRequest\x1a\x14.hello.HelloResponseb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66raud_detection.proto\x12\x05hello\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"!\n\rHelloResponse\x12\x10\n\x08greeting\x18\x01 \x01(\t\"O\n\x11\x46raudCheckRequest\x12\x11\n\tuser_name\x18\x01 \x01(\t\x12\x13\n\x0b\x63\x61rd_number\x18\x02 \x01(\t\x12\x12\n\nitem_count\x18\x03 \x01(\x05\"7\n\x12\x46raudCheckResponse\x12\x10\n\x08is_fraud\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t2\x88\x01\n\x0cHelloService\x12\x35\n\x08SayHello\x12\x13.hello.HelloRequest\x1a\x14.hello.HelloResponse\x12\x41\n\nCheckFraud\x12\x18.hello.FraudCheckRequest\x1a\x19.hello.FraudCheckResponseb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -25,6 +25,10 @@ _globals['_HELLOREQUEST']._serialized_end=60 _globals['_HELLORESPONSE']._serialized_start=62 _globals['_HELLORESPONSE']._serialized_end=95 - _globals['_HELLOSERVICE']._serialized_start=97 - _globals['_HELLOSERVICE']._serialized_end=166 + _globals['_FRAUDCHECKREQUEST']._serialized_start=97 + _globals['_FRAUDCHECKREQUEST']._serialized_end=176 + _globals['_FRAUDCHECKRESPONSE']._serialized_start=178 + _globals['_FRAUDCHECKRESPONSE']._serialized_end=233 + _globals['_HELLOSERVICE']._serialized_start=236 + _globals['_HELLOSERVICE']._serialized_end=372 # @@protoc_insertion_point(module_scope) diff --git a/utils/pb/fraud_detection/fraud_detection_pb2.pyi b/utils/pb/fraud_detection/fraud_detection_pb2.pyi index 30a263856..fe3863b06 100644 --- a/utils/pb/fraud_detection/fraud_detection_pb2.pyi +++ b/utils/pb/fraud_detection/fraud_detection_pb2.pyi @@ -15,3 +15,21 @@ class HelloResponse(_message.Message): GREETING_FIELD_NUMBER: _ClassVar[int] greeting: str def __init__(self, greeting: _Optional[str] = ...) -> None: ... + +class FraudCheckRequest(_message.Message): + __slots__ = ("user_name", "card_number", "item_count") + USER_NAME_FIELD_NUMBER: _ClassVar[int] + CARD_NUMBER_FIELD_NUMBER: _ClassVar[int] + ITEM_COUNT_FIELD_NUMBER: _ClassVar[int] + user_name: str + card_number: str + item_count: int + def __init__(self, user_name: _Optional[str] = ..., card_number: _Optional[str] = ..., item_count: _Optional[int] = ...) -> None: ... + +class FraudCheckResponse(_message.Message): + __slots__ = ("is_fraud", "message") + IS_FRAUD_FIELD_NUMBER: _ClassVar[int] + MESSAGE_FIELD_NUMBER: _ClassVar[int] + is_fraud: bool + message: str + def __init__(self, is_fraud: bool = ..., message: _Optional[str] = ...) -> None: ... diff --git a/utils/pb/fraud_detection/fraud_detection_pb2_grpc.py b/utils/pb/fraud_detection/fraud_detection_pb2_grpc.py index 4e7a27975..3ada2e86e 100644 --- a/utils/pb/fraud_detection/fraud_detection_pb2_grpc.py +++ b/utils/pb/fraud_detection/fraud_detection_pb2_grpc.py @@ -19,6 +19,11 @@ def __init__(self, channel): request_serializer=fraud__detection__pb2.HelloRequest.SerializeToString, response_deserializer=fraud__detection__pb2.HelloResponse.FromString, ) + self.CheckFraud = channel.unary_unary( + '/hello.HelloService/CheckFraud', + request_serializer=fraud__detection__pb2.FraudCheckRequest.SerializeToString, + response_deserializer=fraud__detection__pb2.FraudCheckResponse.FromString, + ) class HelloServiceServicer(object): @@ -30,6 +35,12 @@ def SayHello(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def CheckFraud(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def add_HelloServiceServicer_to_server(servicer, server): rpc_method_handlers = { @@ -38,6 +49,11 @@ def add_HelloServiceServicer_to_server(servicer, server): request_deserializer=fraud__detection__pb2.HelloRequest.FromString, response_serializer=fraud__detection__pb2.HelloResponse.SerializeToString, ), + 'CheckFraud': grpc.unary_unary_rpc_method_handler( + servicer.CheckFraud, + request_deserializer=fraud__detection__pb2.FraudCheckRequest.FromString, + response_serializer=fraud__detection__pb2.FraudCheckResponse.SerializeToString, + ), } generic_handler = grpc.method_handlers_generic_handler( 'hello.HelloService', rpc_method_handlers) @@ -64,3 +80,20 @@ def SayHello(request, fraud__detection__pb2.HelloResponse.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def CheckFraud(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hello.HelloService/CheckFraud', + fraud__detection__pb2.FraudCheckRequest.SerializeToString, + fraud__detection__pb2.FraudCheckResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) From 0cb5ee217cec1296e99db1fec5375a7647adf863 Mon Sep 17 00:00:00 2001 From: Qun Yan Li Date: Sat, 28 Feb 2026 11:20:27 +0200 Subject: [PATCH 09/18] Add threaded orchestration for backend gRPC services --- orchestrator/src/app.py | 160 ++++++++++++++++++++++++---------------- 1 file changed, 95 insertions(+), 65 deletions(-) diff --git a/orchestrator/src/app.py b/orchestrator/src/app.py index 2b5045787..64341eb19 100644 --- a/orchestrator/src/app.py +++ b/orchestrator/src/app.py @@ -1,5 +1,6 @@ import sys import os +import threading # This set of lines are needed to import the gRPC stubs. # The path of the stubs is relative to the current file, or absolute inside the container. @@ -29,27 +30,20 @@ import grpc -# Import Flask. from flask import Flask, request from flask_cors import CORS def greet(name='you'): - # Establish a connection with the fraud-detection gRPC service. with grpc.insecure_channel('fraud_detection:50051') as channel: - # Create a stub object. stub = fraud_detection_grpc.HelloServiceStub(channel) - # Call the service through the stub object. response = stub.SayHello(fraud_detection.HelloRequest(name=name)) return response.greeting def detect_fraud(user_name, card_number, item_count): - # Establish a connection with the fraud-detection gRPC service. with grpc.insecure_channel('fraud_detection:50051') as channel: - # Create a stub object. stub = fraud_detection_grpc.HelloServiceStub(channel) - # Call the service through the stub object. response = stub.CheckFraud( fraud_detection.FraudCheckRequest( user_name=user_name or "", @@ -61,11 +55,8 @@ def detect_fraud(user_name, card_number, item_count): def verify_transaction(user_name, user_contact, card_number, expiration_date, cvv, item_count, terms_accepted): - # Establish a connection with the transaction_verification gRPC service. with grpc.insecure_channel('transaction_verification:50052') as channel: - # Create a stub object. stub = transaction_verification_grpc.TransactionVerificationServiceStub(channel) - # Call the service through the stub object. response = stub.VerifyTransaction( transaction_verification.TransactionVerificationRequest( user_name=user_name or "", @@ -81,11 +72,8 @@ def verify_transaction(user_name, user_contact, card_number, expiration_date, cv def get_suggestions(user_name, item_count): - # Establish a connection with the suggestions gRPC service. with grpc.insecure_channel('suggestions:50053') as channel: - # Create a stub object. stub = suggestions_grpc.SuggestionsServiceStub(channel) - # Call the service through the stub object. response = stub.GetSuggestions( suggestions.SuggestionsRequest( user_name=user_name or "", @@ -95,29 +83,18 @@ def get_suggestions(user_name, item_count): return response -# Create a simple Flask app. app = Flask(__name__) -# Enable CORS for the app. CORS(app, resources={r'/*': {'origins': '*'}}) -# Define a GET endpoint. @app.route('/', methods=['GET']) def index(): - """ - Responds with 'Hello, [name]' when a GET request is made to '/' endpoint. - """ - # Test the fraud-detection gRPC service. response = greet(name='orchestrator') - # Return the response. return response @app.route('/checkout', methods=['POST']) def checkout(): - """ - Responds with a JSON object containing the order ID, status, and suggested books. - """ request_data = request.get_json(silent=True) if request_data is None: @@ -172,58 +149,114 @@ def checkout(): item_count = len(items) - print("Calling fraud_detection service...") - fraud_response = detect_fraud( - user_name=user_name, - card_number=card_number, - item_count=item_count - ) - print("fraud_detection result:", fraud_response.is_fraud, fraud_response.message) + results = { + "fraud": None, + "verification": None, + "suggestions": None, + "errors": [] + } + + def fraud_worker(): + try: + print("Calling fraud_detection service...") + results["fraud"] = detect_fraud( + user_name=user_name, + card_number=card_number, + item_count=item_count + ) + print( + "fraud_detection result:", + results["fraud"].is_fraud, + results["fraud"].message + ) + except Exception as e: + error_msg = f"fraud_detection failed: {e}" + print(error_msg) + results["errors"].append(error_msg) + + def verification_worker(): + try: + print("Calling transaction_verification service...") + results["verification"] = verify_transaction( + user_name=user_name, + user_contact=user_contact, + card_number=card_number, + expiration_date=expiration_date, + cvv=cvv, + item_count=item_count, + terms_accepted=terms_accepted + ) + print( + "transaction_verification result:", + results["verification"].is_valid, + results["verification"].message + ) + except Exception as e: + error_msg = f"transaction_verification failed: {e}" + print(error_msg) + results["errors"].append(error_msg) + + def suggestions_worker(): + try: + print("Calling suggestions service...") + results["suggestions"] = get_suggestions( + user_name=user_name, + item_count=item_count + ) + print( + "suggestions returned:", + len(results["suggestions"].books), + "books" + ) + except Exception as e: + error_msg = f"suggestions failed: {e}" + print(error_msg) + results["errors"].append(error_msg) + + fraud_thread = threading.Thread(target=fraud_worker) + verification_thread = threading.Thread(target=verification_worker) + suggestions_thread = threading.Thread(target=suggestions_worker) + + print("Starting worker threads...") + fraud_thread.start() + verification_thread.start() + suggestions_thread.start() + + fraud_thread.join() + verification_thread.join() + suggestions_thread.join() + print("All worker threads finished.") + + if results["errors"]: + return { + "error": { + "code": "INTERNAL_ERROR", + "message": "; ".join(results["errors"]) + } + }, 500 - if fraud_response.is_fraud: + if results["fraud"] and results["fraud"].is_fraud: return { "orderId": "12345", "status": "Order Rejected", "suggestedBooks": [] }, 200 - print("Calling transaction_verification service...") - verification_response = verify_transaction( - user_name=user_name, - user_contact=user_contact, - card_number=card_number, - expiration_date=expiration_date, - cvv=cvv, - item_count=item_count, - terms_accepted=terms_accepted - ) - print( - "transaction_verification result:", - verification_response.is_valid, - verification_response.message - ) - - if not verification_response.is_valid: + if results["verification"] and not results["verification"].is_valid: return { "orderId": "12345", "status": "Order Rejected", "suggestedBooks": [] }, 200 - print("Calling suggestions service...") - suggestions_response = get_suggestions( - user_name=user_name, - item_count=item_count - ) - print("suggestions returned:", len(suggestions_response.books), "books") - suggested_books = [] - for book in suggestions_response.books: - suggested_books.append({ - "bookId": book.bookId, - "title": book.title, - "author": book.author - }) + if results["suggestions"]: + for book in results["suggestions"].books: + suggested_books.append({ + "bookId": book.bookId, + "title": book.title, + "author": book.author + }) return { "orderId": "12345", @@ -233,7 +266,4 @@ def checkout(): if __name__ == '__main__': - # Run the app in debug mode to enable hot reloading. - # This is useful for development. - # The default port is 5000. app.run(host='0.0.0.0') \ No newline at end of file From 4cd2062cf4f07e3e354643595a91ca2a6ec97177 Mon Sep 17 00:00:00 2001 From: mdmuminul Date: Sat, 28 Feb 2026 11:23:01 +0200 Subject: [PATCH 10/18] Fraud Detection --- fraud_detection/src/app.py | 24 +++++----- orchestrator/src/app.py | 91 ++++++++++++++++++++------------------ 2 files changed, 62 insertions(+), 53 deletions(-) diff --git a/fraud_detection/src/app.py b/fraud_detection/src/app.py index b2f1d2fce..b85b64b9d 100644 --- a/fraud_detection/src/app.py +++ b/fraud_detection/src/app.py @@ -15,23 +15,25 @@ # Create a class to define the server functions, derived from # fraud_detection_pb2_grpc.HelloServiceServicer -class HelloService(fraud_detection_grpc.HelloServiceServicer): +class FraudService(fraud_detection_grpc.FraudDetectionServiceServicer): # Create an RPC function to say hello - def SayHello(self, request, context): - # Create a HelloResponse object - response = fraud_detection.HelloResponse() - # Set the greeting field of the response object - response.greeting = "Hello, " + request.name - # Print the greeting message - print(response.greeting) - # Return the response object - return response + def CheckFraud(self, request, context): + card_number = request.card_number + order_amount = request.order_amount + + print(f"Checking fraud for card number: {card_number} and order amount: {order_amount}") + # Dummy Logic if amount > 1000 or card_number starts with 999 then it is fraud + is_fraud = False + if order_amount > 1000 or card_number.startswith("999"): + is_fraud = True + + return fraud_detection.FraudResponse(is_fraud=is_fraud) def serve(): # Create a gRPC server server = grpc.server(futures.ThreadPoolExecutor()) # Add HelloService - fraud_detection_grpc.add_HelloServiceServicer_to_server(HelloService(), server) + fraud_detection_grpc.add_FraudDetectionServiceServicer_to_server(FraudService(), server) # Listen on port 50051 port = "50051" server.add_insecure_port("[::]:" + port) diff --git a/orchestrator/src/app.py b/orchestrator/src/app.py index 9d8e24d4d..89bdf0a12 100644 --- a/orchestrator/src/app.py +++ b/orchestrator/src/app.py @@ -1,9 +1,8 @@ import sys import os +import logging +logging.basicConfig(level=logging.INFO) -# This set of lines are needed to import the gRPC stubs. -# The path of the stubs is relative to the current file, or absolute inside the container. -# Change these lines only if strictly needed. FILE = __file__ if '__file__' in globals() else os.getenv("PYTHONFILE", "") fraud_detection_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/fraud_detection')) sys.path.insert(0, fraud_detection_grpc_path) @@ -13,66 +12,74 @@ import grpc def greet(name='you'): - # Establish a connection with the fraud-detection gRPC service. with grpc.insecure_channel('fraud_detection:50051') as channel: - # Create a stub object. stub = fraud_detection_grpc.HelloServiceStub(channel) - # Call the service through the stub object. response = stub.SayHello(fraud_detection.HelloRequest(name=name)) return response.greeting -# Import Flask. -# Flask is a web framework for Python. -# It allows you to build a web application quickly. -# For more information, see https://flask.palletsprojects.com/en/latest/ +def call_fraud_detection(card_number, order_amount): + try: + with grpc.insecure_channel('fraud_detection:50051') as channel: + stub = fraud_detection_grpc.FraudDetectionServiceStub(channel) + request_obj = fraud_detection.FraudRequest(card_number=card_number, order_amount=order_amount) + response = stub.CheckFraud(request_obj) + return response.is_fraud + except Exception as e: + logging.error(f"gRPC call failed: {e}") + return True + from flask import Flask, request from flask_cors import CORS -import json -# Create a simple Flask app. app = Flask(__name__) -# Enable CORS for the app. CORS(app, resources={r'/*': {'origins': '*'}}) -# Define a GET endpoint. @app.route('/', methods=['GET']) def index(): - """ - Responds with 'Hello, [name]' when a GET request is made to '/' endpoint. - """ - # Test the fraud-detection gRPC service. response = greet(name='orchestrator') - # Return the response. return response @app.route('/checkout', methods=['POST']) def checkout(): - """ - Responds with a JSON object containing the order ID, status, and suggested books. - """ - # Get request object data to json - request_data = json.loads(request.data) - # Print request object data - print("Request Data:", request_data.get('items')) + from concurrent.futures import ThreadPoolExecutor + try: + # force=True parses JSON regardless of Content-Type header + # silent=True returns None instead of error if parsing fails + request_data = request.get_json(force=True, silent=True) or {} + logging.info(f"Checkout request received: {request_data}") - # Dummy response following the provided YAML specification for the bookstore - order_status_response = { - 'orderId': '12345', - 'status': 'Order Approved', - 'suggestedBooks': [ - {'bookId': '123', 'title': 'The Best Book', 'author': 'Author 1'}, - {'bookId': '456', 'title': 'The Second Best Book', 'author': 'Author 2'} - ] - } + card_info = request_data.get("creditCard", {}) + card_number = card_info.get("number", "") + order_amount = request_data.get("totalAmount", 0.0) - return order_status_response + with ThreadPoolExecutor(max_workers=3) as executor: + fraud_future = executor.submit(call_fraud_detection, card_number, order_amount) + is_fraud = fraud_future.result() + logging.info(f"Fraud detection result: {is_fraud}") + if is_fraud: + order_status_response = { + "orderId": "1234567890", + "status": "Order Rejected", + "suggestedBooks": [] + } + else: + order_status_response = { + "orderId": "1234567890", + "status": "Order Approved", + "suggestedBooks": [ + {'bookId': '123', 'title': 'Book 1', 'author': 'Author 1'}, + {'bookId': '456', 'title': 'Book 2', 'author': 'Author 2'}, + {'bookId': '789', 'title': 'Book 3', 'author': 'Author 3'} + ] + } -if __name__ == '__main__': - # Run the app in debug mode to enable hot reloading. - # This is useful for development. - # The default port is 5000. - app.run(host='0.0.0.0') + logging.info(f"Checkout completed: {order_status_response}") + return order_status_response + except Exception as e: + logging.error(f"Checkout failed: {e}") + return {"error": {"message": str(e)}}, 500 -# Hello \ No newline at end of file +if __name__ == '__main__': + app.run(host='0.0.0.0') \ No newline at end of file From 702d31fa07fb894feeffdc1810176c248897f59f Mon Sep 17 00:00:00 2001 From: mdmuminul Date: Sat, 28 Feb 2026 11:27:58 +0200 Subject: [PATCH 11/18] protobuf version Update --- fraud_detection/requirements.txt | 2 +- orchestrator/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fraud_detection/requirements.txt b/fraud_detection/requirements.txt index a80eedef7..b20ca4bc3 100644 --- a/fraud_detection/requirements.txt +++ b/fraud_detection/requirements.txt @@ -1,4 +1,4 @@ grpcio==1.60.0 grpcio-tools==1.60.0 -protobuf==4.25.2 +protobuf==4.25.0 watchdog==6.0.0 diff --git a/orchestrator/requirements.txt b/orchestrator/requirements.txt index 5ba8e254b..f8c1ab8cb 100644 --- a/orchestrator/requirements.txt +++ b/orchestrator/requirements.txt @@ -6,7 +6,7 @@ grpcio-tools==1.60.0 itsdangerous==2.1.2 Jinja2==3.1.3 MarkupSafe==2.1.3 -protobuf==4.25.2 +protobuf>=4.25.0 Werkzeug==3.0.1 Flask-CORS==4.0.0 watchdog==6.0.0 \ No newline at end of file From 06c1f459f157ba435e3d55f3eb90d8f73131e50c Mon Sep 17 00:00:00 2001 From: Qun Yan Li Date: Sat, 28 Feb 2026 12:12:19 +0200 Subject: [PATCH 12/18] Fix frontend checkout JSON request and response handling --- frontend/src/index.html | 54 ++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/frontend/src/index.html b/frontend/src/index.html index 15c47351f..2ace91b7d 100644 --- a/frontend/src/index.html +++ b/frontend/src/index.html @@ -22,26 +22,32 @@

Items

+
+
+
+
+
+
@@ -50,6 +56,7 @@

Items

+
+
+
- + + @@ -90,17 +102,18 @@

Items

event.preventDefault(); const formData = new FormData(event.target); + const data = { user: { name: formData.get('name'), contact: formData.get('contact'), + creditCard: { + number: formData.get('creditCard'), + expirationDate: formData.get('expirationDate'), + cvv: formData.get('cvv'), + }, + userComment: formData.get('userComment'), }, - creditCard: { - number: formData.get('creditCard'), - expirationDate: formData.get('expirationDate'), - cvv: formData.get('cvv'), - }, - userComment: formData.get('userComment'), items: items, billingAddress: { street: formData.get('billingStreet'), @@ -111,12 +124,15 @@

Items

}, shippingMethod: formData.get('shippingMethod'), giftWrapping: formData.get('giftWrapping') === 'on', - termsAccepted: formData.get('terms') === 'on', + termsAndConditionsAccepted: formData.get('terms') === 'on', }; try { const response = await fetch('http://localhost:8081/checkout', { method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, body: JSON.stringify(data), }); @@ -124,25 +140,29 @@

Items

const responseDiv = document.getElementById('response'); if (response.ok) { - const suggestedBooks = result.suggestedBooks.map(book => `
  • ${book.title} by ${book.author}
  • `).join(''); + const suggestedBooks = (result.suggestedBooks || []) + .map(book => `
  • ${book.title} by ${book.author}
  • `) + .join(''); + responseDiv.innerHTML = ` Order status: ${result.status}
    Order ID: ${result.orderId}
    - ${result.status === "Order Approved" ? - `Suggested Books: -
      ${suggestedBooks}
    ` - : `` + ${result.status === "Order Approved" + ? `Suggested Books: +
      ${suggestedBooks}
    ` + : `` } `; - color = result.status === 'Order Approved' ? 'green' : 'red'; + + const color = result.status === 'Order Approved' ? 'green' : 'red'; responseDiv.className = `mt-6 p-4 border rounded-lg bg-${color}-100 text-${color}-700`; } else { - responseDiv.textContent = `Error: ${result.error.message}`; + const message = result?.error?.message || 'Unknown error'; + responseDiv.textContent = `Error: ${message}`; responseDiv.className = "mt-6 p-4 border rounded-lg bg-red-100 text-red-700"; } responseDiv.style.display = 'block'; - // scroll to the bottom of the page window.scrollTo(0, document.body.scrollHeight); } catch (error) { const responseDiv = document.getElementById('response'); @@ -153,4 +173,4 @@

    Items

    }); - + \ No newline at end of file From ccba99c5bd72406f5b1a64027b1e53cfae70b004 Mon Sep 17 00:00:00 2001 From: mdmuminul Date: Sat, 28 Feb 2026 12:14:32 +0200 Subject: [PATCH 13/18] Creating Proto file for Transaction Verification --- docker-compose.yaml | 25 ++++- transaction_verification/Dockerfile | 15 +++ transaction_verification/requirements.txt | 4 + transaction_verification/src/app.py | 88 +++++++++++++++++ .../transaction_verification.proto | 26 +++++ .../transaction_verification_pb2.py | 42 ++++++++ .../transaction_verification_pb2.pyi | 39 ++++++++ .../transaction_verification_pb2_grpc.py | 97 +++++++++++++++++++ 8 files changed, 335 insertions(+), 1 deletion(-) create mode 100644 transaction_verification/Dockerfile create mode 100644 transaction_verification/requirements.txt create mode 100644 transaction_verification/src/app.py create mode 100644 utils/pb/transaction_verification/transaction_verification.proto create mode 100644 utils/pb/transaction_verification/transaction_verification_pb2.py create mode 100644 utils/pb/transaction_verification/transaction_verification_pb2.pyi create mode 100644 utils/pb/transaction_verification/transaction_verification_pb2_grpc.py diff --git a/docker-compose.yaml b/docker-compose.yaml index b4a60a537..dfa6d438b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -56,4 +56,27 @@ services: # Mount the utils directory in the current directory to the /app/utils directory in the container - ./utils:/app/utils # Mount the fraud_detection/src directory in the current directory to the /app/fraud_detection/src directory in the container - - ./fraud_detection/src:/app/fraud_detection/src \ No newline at end of file + - ./fraud_detection/src:/app/fraud_detection/src + + transaction_verification: + build: + # Use the current directory as the build context + # This allows us to access the files in the current directory inside the Dockerfile + context: ./ + # Use the Dockerfile in the transaction_verification directory + dockerfile: ./transaction_verification/Dockerfile + ports: + # Expose port 50052 on the host, and map port 50052 of the container to port 50052 on the host + - 50052:50052 + environment: + # Pass the environment variables to the container + # The PYTHONUNBUFFERED environment variable ensures that the output from the application is logged to the console + - PYTHONUNBUFFERED=TRUE + # The PYTHONFILE environment variable specifies the absolute entry point of the application + # Check app.py in the transaction_verification directory to see how this is used + - PYTHONFILE=/app/transaction_verification/src/app.py + volumes: + # Mount the utils directory in the current directory to the /app/utils directory in the container + - ./utils:/app/utils + # Mount the transaction_verification/src directory in the current directory to the /app/transaction_verification/src directory in the container + - ./transaction_verification/src:/app/transaction_verification/src diff --git a/transaction_verification/Dockerfile b/transaction_verification/Dockerfile new file mode 100644 index 000000000..341df7f6f --- /dev/null +++ b/transaction_verification/Dockerfile @@ -0,0 +1,15 @@ +# Use an official Python runtime as the base image +FROM python:3.11 + +# Set the working directory in the container +# Both the utils and src folders will be mounted as volumes, please see docker-compose.yaml +WORKDIR /app + +# Copy the requirements file to the working directory +COPY ./fraud_detection/requirements.txt . + +# Install the Python dependencies +RUN pip install --no-cache-dir -r requirements.txt + +# Set the command to run the application +CMD python utils/other/hotreload.py "fraud_detection/src/app.py" \ No newline at end of file diff --git a/transaction_verification/requirements.txt b/transaction_verification/requirements.txt new file mode 100644 index 000000000..2c6bbca24 --- /dev/null +++ b/transaction_verification/requirements.txt @@ -0,0 +1,4 @@ +grpcio==1.60.0 +grpcio-tools==1.60.0 +protobuf>=4.25.0 +watchdog==6.0.0 diff --git a/transaction_verification/src/app.py b/transaction_verification/src/app.py new file mode 100644 index 000000000..b3c8eda1d --- /dev/null +++ b/transaction_verification/src/app.py @@ -0,0 +1,88 @@ +import sys +import os + +# This set of lines are needed to import the gRPC stubs. +# The path of the stubs is relative to the current file, or absolute inside the container. +# Change these lines only if strictly needed. +FILE = __file__ if '__file__' in globals() else os.getenv("PYTHONFILE", "") +fraud_detection_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/transaction_verification')) +sys.path.insert(0, fraud_detection_grpc_path) +import transaction_verification_pb2 as transaction_verification +import transaction_verification_pb2_grpc as transaction_verification_grpc + +import grpc +from concurrent import futures + +class TransactionVerificationService(transaction_verification_grpc.TransactionVerificationServiceServicer): + def VerifyTransaction(self, request, context): + print(f"Verifying transaction for card number: {request.card_number}") + + #Check 1: items list must not be empty + if len(request.items) == 0: + return transaction_verification.TransactionResponse( + is_valid=False, + reason="Order must contain at least one item" + ) + #Check 2: user data must be filled in + if not request.user_name or not request.user_contact: + return transaction_verification.TransactionResponse( + is_valid=False, + reason="User name and contact are required" + ) + + #Check 3: card number must be 16 digits + card_number = request.card_number.replace(" ", "") + if not card_number.isdigit() or len(card_number) != 16: + return transaction_verification.TransactionResponse( + is_valid=False, + reason="Invalid card number format" + ) + + #Check 4: CVV must be 3 digits + if not request.cvv.isdigit() or len(request.cvv) != 3: + return transaction_verification.TransactionResponse( + is_valid=False, + reason="Invalid CVV format" + ) + + # Check 5: expiration date format MM/YY + expiration = request.card_expiration + if len(expiration) != 5 or expiration[2] != '/' or \ + not expiration[:2].isdigit() or not expiration[3:].isdigit(): + return transaction_verification.TransactionResponse( + is_valid=False, + reason="Invalid expiration date format. Use MM/YY" + ) + + # Check 6: expiration date must be in the future + month = int(expiration[:2]) + year = int(expiration[3:]) + + current_year = datetime.now().year % 100 + current_month = datetime.now().month + + if year < current_year or (year == current_year and month < current_month): + return transaction_verification.TransactionResponse( + is_valid=False, + reason="Card has expired" + ) + + print("Transaction verified successfully") + return transaction_verification.TransactionResponse( + is_valid=True, + reason="Transaction is valid" + ) + +def serve(): + server = grpc.server(futures.ThreadPoolExecutor()) + transaction_verification_grpc.add_TransactionVerificationServiceServicer_to_server( + TransactionVerificationService(), server + ) + port = "50052" + server.add_insecure_port("[::]:" + port) + server.start() + print("Server started. Listening on port 50052.") + server.wait_for_termination() + +if __name__ == '__main__': + serve() \ No newline at end of file diff --git a/utils/pb/transaction_verification/transaction_verification.proto b/utils/pb/transaction_verification/transaction_verification.proto new file mode 100644 index 000000000..bfe033a8e --- /dev/null +++ b/utils/pb/transaction_verification/transaction_verification.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package transaction_verification; + +service TransactionVerificationService { + rpc VerifyTransaction (TransactionRequest) returns (TransactionResponse); +} + +message TransactionRequest { + string card_number = 1; + string card_expiration = 2; + string card_cvv = 3; + repeated Item items = 4; + string user_name = 5; + string user_contact = 6; +} + +message Item { + string name = 1; + int32 quantity = 2; +} + +message TransactionResponse { + bool is_valid = 1; + string reason = 2; +} \ No newline at end of file diff --git a/utils/pb/transaction_verification/transaction_verification_pb2.py b/utils/pb/transaction_verification/transaction_verification_pb2.py new file mode 100644 index 000000000..9441e2d5b --- /dev/null +++ b/utils/pb/transaction_verification/transaction_verification_pb2.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: transaction_verification.proto +# Protobuf Python Version: 6.31.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 31, + 1, + '', + 'transaction_verification.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1etransaction_verification.proto\x12\x18transaction_verification\"\xac\x01\n\x12TransactionRequest\x12\x13\n\x0b\x63\x61rd_number\x18\x01 \x01(\t\x12\x17\n\x0f\x63\x61rd_expiration\x18\x02 \x01(\t\x12\x10\n\x08\x63\x61rd_cvv\x18\x03 \x01(\t\x12-\n\x05items\x18\x04 \x03(\x0b\x32\x1e.transaction_verification.Item\x12\x11\n\tuser_name\x18\x05 \x01(\t\x12\x14\n\x0cuser_contact\x18\x06 \x01(\t\"&\n\x04Item\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x10\n\x08quantity\x18\x02 \x01(\x05\"7\n\x13TransactionResponse\x12\x10\n\x08is_valid\x18\x01 \x01(\x08\x12\x0e\n\x06reason\x18\x02 \x01(\t2\x92\x01\n\x1eTransactionVerificationService\x12p\n\x11VerifyTransaction\x12,.transaction_verification.TransactionRequest\x1a-.transaction_verification.TransactionResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'transaction_verification_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + DESCRIPTOR._loaded_options = None + _globals['_TRANSACTIONREQUEST']._serialized_start=61 + _globals['_TRANSACTIONREQUEST']._serialized_end=233 + _globals['_ITEM']._serialized_start=235 + _globals['_ITEM']._serialized_end=273 + _globals['_TRANSACTIONRESPONSE']._serialized_start=275 + _globals['_TRANSACTIONRESPONSE']._serialized_end=330 + _globals['_TRANSACTIONVERIFICATIONSERVICE']._serialized_start=333 + _globals['_TRANSACTIONVERIFICATIONSERVICE']._serialized_end=479 +# @@protoc_insertion_point(module_scope) diff --git a/utils/pb/transaction_verification/transaction_verification_pb2.pyi b/utils/pb/transaction_verification/transaction_verification_pb2.pyi new file mode 100644 index 000000000..03f9d43be --- /dev/null +++ b/utils/pb/transaction_verification/transaction_verification_pb2.pyi @@ -0,0 +1,39 @@ +from google.protobuf.internal import containers as _containers +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from collections.abc import Iterable as _Iterable, Mapping as _Mapping +from typing import ClassVar as _ClassVar, Optional as _Optional, Union as _Union + +DESCRIPTOR: _descriptor.FileDescriptor + +class TransactionRequest(_message.Message): + __slots__ = ("card_number", "card_expiration", "card_cvv", "items", "user_name", "user_contact") + CARD_NUMBER_FIELD_NUMBER: _ClassVar[int] + CARD_EXPIRATION_FIELD_NUMBER: _ClassVar[int] + CARD_CVV_FIELD_NUMBER: _ClassVar[int] + ITEMS_FIELD_NUMBER: _ClassVar[int] + USER_NAME_FIELD_NUMBER: _ClassVar[int] + USER_CONTACT_FIELD_NUMBER: _ClassVar[int] + card_number: str + card_expiration: str + card_cvv: str + items: _containers.RepeatedCompositeFieldContainer[Item] + user_name: str + user_contact: str + def __init__(self, card_number: _Optional[str] = ..., card_expiration: _Optional[str] = ..., card_cvv: _Optional[str] = ..., items: _Optional[_Iterable[_Union[Item, _Mapping]]] = ..., user_name: _Optional[str] = ..., user_contact: _Optional[str] = ...) -> None: ... + +class Item(_message.Message): + __slots__ = ("name", "quantity") + NAME_FIELD_NUMBER: _ClassVar[int] + QUANTITY_FIELD_NUMBER: _ClassVar[int] + name: str + quantity: int + def __init__(self, name: _Optional[str] = ..., quantity: _Optional[int] = ...) -> None: ... + +class TransactionResponse(_message.Message): + __slots__ = ("is_valid", "reason") + IS_VALID_FIELD_NUMBER: _ClassVar[int] + REASON_FIELD_NUMBER: _ClassVar[int] + is_valid: bool + reason: str + def __init__(self, is_valid: bool = ..., reason: _Optional[str] = ...) -> None: ... diff --git a/utils/pb/transaction_verification/transaction_verification_pb2_grpc.py b/utils/pb/transaction_verification/transaction_verification_pb2_grpc.py new file mode 100644 index 000000000..1219fd0a7 --- /dev/null +++ b/utils/pb/transaction_verification/transaction_verification_pb2_grpc.py @@ -0,0 +1,97 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +import transaction_verification_pb2 as transaction__verification__pb2 + +GRPC_GENERATED_VERSION = '1.78.0' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + ' but the generated code in transaction_verification_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class TransactionVerificationServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.VerifyTransaction = channel.unary_unary( + '/transaction_verification.TransactionVerificationService/VerifyTransaction', + request_serializer=transaction__verification__pb2.TransactionRequest.SerializeToString, + response_deserializer=transaction__verification__pb2.TransactionResponse.FromString, + _registered_method=True) + + +class TransactionVerificationServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + + def VerifyTransaction(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_TransactionVerificationServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'VerifyTransaction': grpc.unary_unary_rpc_method_handler( + servicer.VerifyTransaction, + request_deserializer=transaction__verification__pb2.TransactionRequest.FromString, + response_serializer=transaction__verification__pb2.TransactionResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'transaction_verification.TransactionVerificationService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('transaction_verification.TransactionVerificationService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class TransactionVerificationService(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod + def VerifyTransaction(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/transaction_verification.TransactionVerificationService/VerifyTransaction', + transaction__verification__pb2.TransactionRequest.SerializeToString, + transaction__verification__pb2.TransactionResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) From ca7831f5cfa4eb4257565de5510a931f9d1066a0 Mon Sep 17 00:00:00 2001 From: mdmuminul Date: Mon, 2 Mar 2026 10:19:41 +0200 Subject: [PATCH 14/18] transaction_verification --- orchestrator/src/app.py | 84 ++++++++++++++----- test_path.py | 8 ++ transaction_verification/Dockerfile | 4 +- transaction_verification/src/app.py | 55 ++++++------ .../pb/fraud_detection/fraud_detection.proto | 15 ++-- .../pb/fraud_detection/fraud_detection_pb2.py | 14 ++-- .../fraud_detection/fraud_detection_pb2.pyi | 22 ++--- .../fraud_detection_pb2_grpc.py | 36 ++++---- .../transaction_verification_pb2.py | 16 +--- .../transaction_verification_pb2_grpc.py | 39 +-------- 10 files changed, 152 insertions(+), 141 deletions(-) create mode 100644 test_path.py diff --git a/orchestrator/src/app.py b/orchestrator/src/app.py index 89bdf0a12..bb6e43330 100644 --- a/orchestrator/src/app.py +++ b/orchestrator/src/app.py @@ -1,15 +1,23 @@ import sys import os -import logging -logging.basicConfig(level=logging.INFO) FILE = __file__ if '__file__' in globals() else os.getenv("PYTHONFILE", "") + +# Import fraud detection stubs fraud_detection_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/fraud_detection')) sys.path.insert(0, fraud_detection_grpc_path) import fraud_detection_pb2 as fraud_detection import fraud_detection_pb2_grpc as fraud_detection_grpc +# Import transaction verification stubs +transaction_verification_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/transaction_verification')) +sys.path.insert(0, transaction_verification_grpc_path) +import transaction_verification_pb2 as transaction_verification +import transaction_verification_pb2_grpc as transaction_verification_grpc + import grpc +from flask import Flask, request +from flask_cors import CORS def greet(name='you'): with grpc.insecure_channel('fraud_detection:50051') as channel: @@ -21,15 +29,45 @@ def call_fraud_detection(card_number, order_amount): try: with grpc.insecure_channel('fraud_detection:50051') as channel: stub = fraud_detection_grpc.FraudDetectionServiceStub(channel) - request_obj = fraud_detection.FraudRequest(card_number=card_number, order_amount=order_amount) + request_obj = fraud_detection.FraudRequest( + card_number=card_number, + order_amount=order_amount + ) response = stub.CheckFraud(request_obj) return response.is_fraud except Exception as e: - logging.error(f"gRPC call failed: {e}") + print(f"Fraud detection gRPC call failed: {e}") return True -from flask import Flask, request -from flask_cors import CORS +def call_transaction_verification(request_data): + try: + with grpc.insecure_channel('transaction_verification:50052') as channel: + stub = transaction_verification_grpc.TransactionVerificationServiceStub(channel) + + card_info = request_data.get("creditCard", {}) + user_info = request_data.get("user", {}) + items = request_data.get("items", []) + + grpc_items = [ + transaction_verification.Item( + name=item.get("name", ""), + quantity=item.get("quantity", 0) + ) for item in items + ] + + request_obj = transaction_verification.TransactionRequest( + card_number=card_info.get("number", ""), + card_expiration=card_info.get("expirationDate", ""), + card_cvv=card_info.get("cvv", ""), + items=grpc_items, + user_name=user_info.get("name", ""), + user_contact=user_info.get("contact", "") + ) + response = stub.VerifyTransaction(request_obj) + return response.is_valid + except Exception as e: + print(f"Transaction verification gRPC call failed: {e}") + return False app = Flask(__name__) CORS(app, resources={r'/*': {'origins': '*'}}) @@ -43,42 +81,44 @@ def index(): def checkout(): from concurrent.futures import ThreadPoolExecutor try: - # force=True parses JSON regardless of Content-Type header - # silent=True returns None instead of error if parsing fails request_data = request.get_json(force=True, silent=True) or {} - logging.info(f"Checkout request received: {request_data}") + print("Request Data:", request_data.get('items')) card_info = request_data.get("creditCard", {}) card_number = card_info.get("number", "") order_amount = request_data.get("totalAmount", 0.0) + # Run fraud detection and transaction verification in parallel with ThreadPoolExecutor(max_workers=3) as executor: fraud_future = executor.submit(call_fraud_detection, card_number, order_amount) + verify_future = executor.submit(call_transaction_verification, request_data) + is_fraud = fraud_future.result() - logging.info(f"Fraud detection result: {is_fraud}") + is_valid = verify_future.result() + + print(f"Fraud: {is_fraud}, Valid: {is_valid}") - if is_fraud: + # Consolidate results + if is_fraud or not is_valid: order_status_response = { - "orderId": "1234567890", - "status": "Order Rejected", - "suggestedBooks": [] + 'orderId': '12345', + 'status': 'Order Rejected', + 'suggestedBooks': [] } else: order_status_response = { - "orderId": "1234567890", - "status": "Order Approved", - "suggestedBooks": [ - {'bookId': '123', 'title': 'Book 1', 'author': 'Author 1'}, - {'bookId': '456', 'title': 'Book 2', 'author': 'Author 2'}, - {'bookId': '789', 'title': 'Book 3', 'author': 'Author 3'} + 'orderId': '12345', + 'status': 'Order Approved', + 'suggestedBooks': [ + {'bookId': '123', 'title': 'The Best Book', 'author': 'Author 1'}, + {'bookId': '456', 'title': 'The Second Best Book', 'author': 'Author 2'} ] } - logging.info(f"Checkout completed: {order_status_response}") return order_status_response except Exception as e: - logging.error(f"Checkout failed: {e}") + print(f"Checkout failed: {e}") return {"error": {"message": str(e)}}, 500 if __name__ == '__main__': diff --git a/test_path.py b/test_path.py new file mode 100644 index 000000000..6154cafa5 --- /dev/null +++ b/test_path.py @@ -0,0 +1,8 @@ +import os +import sys + +FILE = __file__ +print(f"FILE: {FILE}") +path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/fraud_detection')) +print(f"Path: {path}") +print(f"Directory exists: {os.path.exists(path)}") diff --git a/transaction_verification/Dockerfile b/transaction_verification/Dockerfile index 341df7f6f..2adbd4e7d 100644 --- a/transaction_verification/Dockerfile +++ b/transaction_verification/Dockerfile @@ -6,10 +6,10 @@ FROM python:3.11 WORKDIR /app # Copy the requirements file to the working directory -COPY ./fraud_detection/requirements.txt . +COPY ./transaction_verification/requirements.txt . # Install the Python dependencies RUN pip install --no-cache-dir -r requirements.txt # Set the command to run the application -CMD python utils/other/hotreload.py "fraud_detection/src/app.py" \ No newline at end of file +CMD python utils/other/hotreload.py "transaction_verification/src/app.py" \ No newline at end of file diff --git a/transaction_verification/src/app.py b/transaction_verification/src/app.py index b3c8eda1d..ad0d9158b 100644 --- a/transaction_verification/src/app.py +++ b/transaction_verification/src/app.py @@ -5,68 +5,64 @@ # The path of the stubs is relative to the current file, or absolute inside the container. # Change these lines only if strictly needed. FILE = __file__ if '__file__' in globals() else os.getenv("PYTHONFILE", "") -fraud_detection_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/transaction_verification')) -sys.path.insert(0, fraud_detection_grpc_path) +transaction_verification_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/transaction_verification')) +sys.path.insert(0, transaction_verification_grpc_path) import transaction_verification_pb2 as transaction_verification import transaction_verification_pb2_grpc as transaction_verification_grpc import grpc from concurrent import futures +# Create a class to define the server functions, derived from +# transaction_verification_pb2_grpc.TransactionVerificationServiceServicer class TransactionVerificationService(transaction_verification_grpc.TransactionVerificationServiceServicer): + # Create an RPC function to verify transaction def VerifyTransaction(self, request, context): - print(f"Verifying transaction for card number: {request.card_number}") + print(f"Verifying transaction for card: {request.card_number}") - #Check 1: items list must not be empty + # Check 1: items list must not be empty if len(request.items) == 0: + print("Verification failed: No items in order") return transaction_verification.TransactionResponse( is_valid=False, reason="Order must contain at least one item" ) - #Check 2: user data must be filled in + + # Check 2: user data must be filled in if not request.user_name or not request.user_contact: + print("Verification failed: Missing user data") return transaction_verification.TransactionResponse( is_valid=False, reason="User name and contact are required" ) - #Check 3: card number must be 16 digits + # Check 3: card number must be 16 digits card_number = request.card_number.replace(" ", "") if not card_number.isdigit() or len(card_number) != 16: + print("Verification failed: Invalid card number") return transaction_verification.TransactionResponse( is_valid=False, - reason="Invalid card number format" + reason="Invalid card number format, must be 16 digits" ) - #Check 4: CVV must be 3 digits - if not request.cvv.isdigit() or len(request.cvv) != 3: + # Check 4: CVV must be 3 digits + if not request.card_cvv.isdigit() or len(request.card_cvv) != 3: + print("Verification failed: Invalid CVV") return transaction_verification.TransactionResponse( is_valid=False, - reason="Invalid CVV format" + reason="Invalid CVV, must be 3 digits" ) # Check 5: expiration date format MM/YY expiration = request.card_expiration if len(expiration) != 5 or expiration[2] != '/' or \ not expiration[:2].isdigit() or not expiration[3:].isdigit(): + print("Verification failed: Invalid expiration date") return transaction_verification.TransactionResponse( is_valid=False, - reason="Invalid expiration date format. Use MM/YY" - ) - - # Check 6: expiration date must be in the future - month = int(expiration[:2]) - year = int(expiration[3:]) - - current_year = datetime.now().year % 100 - current_month = datetime.now().month - - if year < current_year or (year == current_year and month < current_month): - return transaction_verification.TransactionResponse( - is_valid=False, - reason="Card has expired" + reason="Invalid expiration date, use MM/YY format" ) - + print("Transaction verified successfully") return transaction_verification.TransactionResponse( is_valid=True, @@ -74,15 +70,20 @@ def VerifyTransaction(self, request, context): ) def serve(): + # Create a gRPC server server = grpc.server(futures.ThreadPoolExecutor()) + # Add TransactionVerificationService transaction_verification_grpc.add_TransactionVerificationServiceServicer_to_server( TransactionVerificationService(), server ) + # Listen on port 50052 port = "50052" server.add_insecure_port("[::]:" + port) + # Start the server server.start() - print("Server started. Listening on port 50052.") + print("Transaction verification server started. Listening on port 50052.") + # Keep thread alive server.wait_for_termination() - + if __name__ == '__main__': serve() \ No newline at end of file diff --git a/utils/pb/fraud_detection/fraud_detection.proto b/utils/pb/fraud_detection/fraud_detection.proto index db20211d7..54bdcb878 100644 --- a/utils/pb/fraud_detection/fraud_detection.proto +++ b/utils/pb/fraud_detection/fraud_detection.proto @@ -1,15 +1,16 @@ syntax = "proto3"; -package hello; +package fraud_detection; -service HelloService { - rpc SayHello (HelloRequest) returns (HelloResponse); +service FraudDetectionService { + rpc CheckFraud (FraudRequest) returns (FraudResponse); } -message HelloRequest { - string name = 1; +message FraudRequest { + string card_number = 1; + float order_amount = 2; } -message HelloResponse { - string greeting = 1; +message FraudResponse { + bool is_fraud = 1; } diff --git a/utils/pb/fraud_detection/fraud_detection_pb2.py b/utils/pb/fraud_detection/fraud_detection_pb2.py index cdd0bcae8..4bb850ad5 100644 --- a/utils/pb/fraud_detection/fraud_detection_pb2.py +++ b/utils/pb/fraud_detection/fraud_detection_pb2.py @@ -14,17 +14,17 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66raud_detection.proto\x12\x05hello\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"!\n\rHelloResponse\x12\x10\n\x08greeting\x18\x01 \x01(\t2E\n\x0cHelloService\x12\x35\n\x08SayHello\x12\x13.hello.HelloRequest\x1a\x14.hello.HelloResponseb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66raud_detection.proto\x12\x0f\x66raud_detection\"9\n\x0c\x46raudRequest\x12\x13\n\x0b\x63\x61rd_number\x18\x01 \x01(\t\x12\x14\n\x0corder_amount\x18\x02 \x01(\x02\"!\n\rFraudResponse\x12\x10\n\x08is_fraud\x18\x01 \x01(\x08\x32\x64\n\x15\x46raudDetectionService\x12K\n\nCheckFraud\x12\x1d.fraud_detection.FraudRequest\x1a\x1e.fraud_detection.FraudResponseb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'fraud_detection_pb2', _globals) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None - _globals['_HELLOREQUEST']._serialized_start=32 - _globals['_HELLOREQUEST']._serialized_end=60 - _globals['_HELLORESPONSE']._serialized_start=62 - _globals['_HELLORESPONSE']._serialized_end=95 - _globals['_HELLOSERVICE']._serialized_start=97 - _globals['_HELLOSERVICE']._serialized_end=166 + _globals['_FRAUDREQUEST']._serialized_start=42 + _globals['_FRAUDREQUEST']._serialized_end=99 + _globals['_FRAUDRESPONSE']._serialized_start=101 + _globals['_FRAUDRESPONSE']._serialized_end=134 + _globals['_FRAUDDETECTIONSERVICE']._serialized_start=136 + _globals['_FRAUDDETECTIONSERVICE']._serialized_end=236 # @@protoc_insertion_point(module_scope) diff --git a/utils/pb/fraud_detection/fraud_detection_pb2.pyi b/utils/pb/fraud_detection/fraud_detection_pb2.pyi index 30a263856..08a4f9a0f 100644 --- a/utils/pb/fraud_detection/fraud_detection_pb2.pyi +++ b/utils/pb/fraud_detection/fraud_detection_pb2.pyi @@ -4,14 +4,16 @@ from typing import ClassVar as _ClassVar, Optional as _Optional DESCRIPTOR: _descriptor.FileDescriptor -class HelloRequest(_message.Message): - __slots__ = ("name",) - NAME_FIELD_NUMBER: _ClassVar[int] - name: str - def __init__(self, name: _Optional[str] = ...) -> None: ... +class FraudRequest(_message.Message): + __slots__ = ("card_number", "order_amount") + CARD_NUMBER_FIELD_NUMBER: _ClassVar[int] + ORDER_AMOUNT_FIELD_NUMBER: _ClassVar[int] + card_number: str + order_amount: float + def __init__(self, card_number: _Optional[str] = ..., order_amount: _Optional[float] = ...) -> None: ... -class HelloResponse(_message.Message): - __slots__ = ("greeting",) - GREETING_FIELD_NUMBER: _ClassVar[int] - greeting: str - def __init__(self, greeting: _Optional[str] = ...) -> None: ... +class FraudResponse(_message.Message): + __slots__ = ("is_fraud",) + IS_FRAUD_FIELD_NUMBER: _ClassVar[int] + is_fraud: bool + def __init__(self, is_fraud: bool = ...) -> None: ... diff --git a/utils/pb/fraud_detection/fraud_detection_pb2_grpc.py b/utils/pb/fraud_detection/fraud_detection_pb2_grpc.py index 4e7a27975..6824e421a 100644 --- a/utils/pb/fraud_detection/fraud_detection_pb2_grpc.py +++ b/utils/pb/fraud_detection/fraud_detection_pb2_grpc.py @@ -5,7 +5,7 @@ import fraud_detection_pb2 as fraud__detection__pb2 -class HelloServiceStub(object): +class FraudDetectionServiceStub(object): """Missing associated documentation comment in .proto file.""" def __init__(self, channel): @@ -14,42 +14,42 @@ def __init__(self, channel): Args: channel: A grpc.Channel. """ - self.SayHello = channel.unary_unary( - '/hello.HelloService/SayHello', - request_serializer=fraud__detection__pb2.HelloRequest.SerializeToString, - response_deserializer=fraud__detection__pb2.HelloResponse.FromString, + self.CheckFraud = channel.unary_unary( + '/fraud_detection.FraudDetectionService/CheckFraud', + request_serializer=fraud__detection__pb2.FraudRequest.SerializeToString, + response_deserializer=fraud__detection__pb2.FraudResponse.FromString, ) -class HelloServiceServicer(object): +class FraudDetectionServiceServicer(object): """Missing associated documentation comment in .proto file.""" - def SayHello(self, request, context): + def CheckFraud(self, request, context): """Missing associated documentation comment in .proto file.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') -def add_HelloServiceServicer_to_server(servicer, server): +def add_FraudDetectionServiceServicer_to_server(servicer, server): rpc_method_handlers = { - 'SayHello': grpc.unary_unary_rpc_method_handler( - servicer.SayHello, - request_deserializer=fraud__detection__pb2.HelloRequest.FromString, - response_serializer=fraud__detection__pb2.HelloResponse.SerializeToString, + 'CheckFraud': grpc.unary_unary_rpc_method_handler( + servicer.CheckFraud, + request_deserializer=fraud__detection__pb2.FraudRequest.FromString, + response_serializer=fraud__detection__pb2.FraudResponse.SerializeToString, ), } generic_handler = grpc.method_handlers_generic_handler( - 'hello.HelloService', rpc_method_handlers) + 'fraud_detection.FraudDetectionService', rpc_method_handlers) server.add_generic_rpc_handlers((generic_handler,)) # This class is part of an EXPERIMENTAL API. -class HelloService(object): +class FraudDetectionService(object): """Missing associated documentation comment in .proto file.""" @staticmethod - def SayHello(request, + def CheckFraud(request, target, options=(), channel_credentials=None, @@ -59,8 +59,8 @@ def SayHello(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/hello.HelloService/SayHello', - fraud__detection__pb2.HelloRequest.SerializeToString, - fraud__detection__pb2.HelloResponse.FromString, + return grpc.experimental.unary_unary(request, target, '/fraud_detection.FraudDetectionService/CheckFraud', + fraud__detection__pb2.FraudRequest.SerializeToString, + fraud__detection__pb2.FraudResponse.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/utils/pb/transaction_verification/transaction_verification_pb2.py b/utils/pb/transaction_verification/transaction_verification_pb2.py index 9441e2d5b..db0e5922d 100644 --- a/utils/pb/transaction_verification/transaction_verification_pb2.py +++ b/utils/pb/transaction_verification/transaction_verification_pb2.py @@ -1,22 +1,12 @@ # -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! -# NO CHECKED-IN PROTOBUF GENCODE # source: transaction_verification.proto -# Protobuf Python Version: 6.31.1 +# Protobuf Python Version: 4.25.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import runtime_version as _runtime_version from google.protobuf import symbol_database as _symbol_database from google.protobuf.internal import builder as _builder -_runtime_version.ValidateProtobufRuntimeVersion( - _runtime_version.Domain.PUBLIC, - 6, - 31, - 1, - '', - 'transaction_verification.proto' -) # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() @@ -29,8 +19,8 @@ _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'transaction_verification_pb2', _globals) -if not _descriptor._USE_C_DESCRIPTORS: - DESCRIPTOR._loaded_options = None +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None _globals['_TRANSACTIONREQUEST']._serialized_start=61 _globals['_TRANSACTIONREQUEST']._serialized_end=233 _globals['_ITEM']._serialized_start=235 diff --git a/utils/pb/transaction_verification/transaction_verification_pb2_grpc.py b/utils/pb/transaction_verification/transaction_verification_pb2_grpc.py index 1219fd0a7..95871b9bf 100644 --- a/utils/pb/transaction_verification/transaction_verification_pb2_grpc.py +++ b/utils/pb/transaction_verification/transaction_verification_pb2_grpc.py @@ -1,29 +1,9 @@ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! """Client and server classes corresponding to protobuf-defined services.""" import grpc -import warnings import transaction_verification_pb2 as transaction__verification__pb2 -GRPC_GENERATED_VERSION = '1.78.0' -GRPC_VERSION = grpc.__version__ -_version_not_supported = False - -try: - from grpc._utilities import first_version_is_lower - _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) -except ImportError: - _version_not_supported = True - -if _version_not_supported: - raise RuntimeError( - f'The grpc package installed is at version {GRPC_VERSION},' - + ' but the generated code in transaction_verification_pb2_grpc.py depends on' - + f' grpcio>={GRPC_GENERATED_VERSION}.' - + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' - + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' - ) - class TransactionVerificationServiceStub(object): """Missing associated documentation comment in .proto file.""" @@ -38,7 +18,7 @@ def __init__(self, channel): '/transaction_verification.TransactionVerificationService/VerifyTransaction', request_serializer=transaction__verification__pb2.TransactionRequest.SerializeToString, response_deserializer=transaction__verification__pb2.TransactionResponse.FromString, - _registered_method=True) + ) class TransactionVerificationServiceServicer(object): @@ -62,7 +42,6 @@ def add_TransactionVerificationServiceServicer_to_server(servicer, server): generic_handler = grpc.method_handlers_generic_handler( 'transaction_verification.TransactionVerificationService', rpc_method_handlers) server.add_generic_rpc_handlers((generic_handler,)) - server.add_registered_method_handlers('transaction_verification.TransactionVerificationService', rpc_method_handlers) # This class is part of an EXPERIMENTAL API. @@ -80,18 +59,8 @@ def VerifyTransaction(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary( - request, - target, - '/transaction_verification.TransactionVerificationService/VerifyTransaction', + return grpc.experimental.unary_unary(request, target, '/transaction_verification.TransactionVerificationService/VerifyTransaction', transaction__verification__pb2.TransactionRequest.SerializeToString, transaction__verification__pb2.TransactionResponse.FromString, - options, - channel_credentials, - insecure, - call_credentials, - compression, - wait_for_ready, - timeout, - metadata, - _registered_method=True) + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) From ffbbf84856edef245e050b1f78534b5b6edd62ec Mon Sep 17 00:00:00 2001 From: mdmuminul Date: Mon, 2 Mar 2026 10:52:18 +0200 Subject: [PATCH 15/18] Suggestions --- docker-compose.yaml | 21 ++++++ orchestrator/src/app.py | 46 ++++++++++-- suggestions/Dockerfile | 15 ++++ suggestions/requirements.txt | 4 ++ suggestions/src/app.py | 76 ++++++++++++++++++++ utils/pb/suggestions/suggestions.proto | 27 +++++++ utils/pb/suggestions/suggestions_pb2.py | 34 +++++++++ utils/pb/suggestions/suggestions_pb2_grpc.py | 66 +++++++++++++++++ 8 files changed, 283 insertions(+), 6 deletions(-) create mode 100644 suggestions/Dockerfile create mode 100644 suggestions/requirements.txt create mode 100644 suggestions/src/app.py create mode 100644 utils/pb/suggestions/suggestions.proto create mode 100644 utils/pb/suggestions/suggestions_pb2.py create mode 100644 utils/pb/suggestions/suggestions_pb2_grpc.py diff --git a/docker-compose.yaml b/docker-compose.yaml index dfa6d438b..9729cb909 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -80,3 +80,24 @@ services: - ./utils:/app/utils # Mount the transaction_verification/src directory in the current directory to the /app/transaction_verification/src directory in the container - ./transaction_verification/src:/app/transaction_verification/src + + suggestions: + build: + # Use the current directory as the build context + # This allows us to access the files in the current directory inside the Dockerfile + context: ./ + # Use the Dockerfile in the suggestions directory + dockerfile: ./suggestions/Dockerfile + ports: + # Expose port 50053 on the host, and map port 50053 of the container to port 50053 on the host + - 50053:50053 + environment: + # Pass the environment variables to the container + # The PYTHONUNBUFFERED environment variable ensures that the output from the application is logged to the console + - PYTHONUNBUFFERED=TRUE + - PYTHONFILE=/app/suggestions/src/app.py + volumes: + # Mount the utils directory in the current directory to the /app/utils directory in the container + - ./utils:/app/utils + # Mount the suggestions/src directory in the current directory to the /app/suggestions/src directory in the container + - ./suggestions/src:/app/suggestions/src diff --git a/orchestrator/src/app.py b/orchestrator/src/app.py index bb6e43330..b962da36a 100644 --- a/orchestrator/src/app.py +++ b/orchestrator/src/app.py @@ -15,6 +15,12 @@ import transaction_verification_pb2 as transaction_verification import transaction_verification_pb2_grpc as transaction_verification_grpc +# Import suggestions stubs +suggestions_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/suggestions')) +sys.path.insert(0, suggestions_grpc_path) +import suggestions_pb2 as suggestions +import suggestions_pb2_grpc as suggestions_grpc + import grpc from flask import Flask, request from flask_cors import CORS @@ -69,6 +75,35 @@ def call_transaction_verification(request_data): print(f"Transaction verification gRPC call failed: {e}") return False +def call_suggestions(request_data): + try: + with grpc.insecure_channel('suggestions:50053') as channel: + stub = suggestions_grpc.SuggestionsServiceStub(channel) + + user_info = request_data.get("user", {}) + items = request_data.get("items", []) + + grpc_items = [ + suggestions.Item( + name=item.get("name", ""), + quantity=item.get("quantity", 0) + ) for item in items + ] + + request_obj = suggestions.SuggestionsRequest( + items=grpc_items, + user_name=user_info.get("name", "") + ) + response = stub.GetSuggestions(request_obj) + + return [ + {"bookId": book.book_id, "title": book.title, "author": book.author} + for book in response.books + ] + except Exception as e: + print(f"Suggestions gRPC call failed: {e}") + return [] + app = Flask(__name__) CORS(app, resources={r'/*': {'origins': '*'}}) @@ -88,15 +123,17 @@ def checkout(): card_number = card_info.get("number", "") order_amount = request_data.get("totalAmount", 0.0) - # Run fraud detection and transaction verification in parallel + # Run all 3 services in parallel with ThreadPoolExecutor(max_workers=3) as executor: fraud_future = executor.submit(call_fraud_detection, card_number, order_amount) verify_future = executor.submit(call_transaction_verification, request_data) + suggestions_future = executor.submit(call_suggestions, request_data) is_fraud = fraud_future.result() is_valid = verify_future.result() + suggested_books = suggestions_future.result() - print(f"Fraud: {is_fraud}, Valid: {is_valid}") + print(f"Fraud: {is_fraud}, Valid: {is_valid}, Books: {len(suggested_books)}") # Consolidate results if is_fraud or not is_valid: @@ -109,10 +146,7 @@ def checkout(): order_status_response = { 'orderId': '12345', 'status': 'Order Approved', - 'suggestedBooks': [ - {'bookId': '123', 'title': 'The Best Book', 'author': 'Author 1'}, - {'bookId': '456', 'title': 'The Second Best Book', 'author': 'Author 2'} - ] + 'suggestedBooks': suggested_books } return order_status_response diff --git a/suggestions/Dockerfile b/suggestions/Dockerfile new file mode 100644 index 000000000..c618243eb --- /dev/null +++ b/suggestions/Dockerfile @@ -0,0 +1,15 @@ +# Use an official Python runtime as the base image +FROM python:3.11 + +# Set the working directory in the container +# Both the utils and src folders will be mounted as volumes, please see docker-compose.yaml +WORKDIR /app + +# Copy the requirements file to the working directory +COPY ./suggestions/requirements.txt . + +# Install the Python dependencies +RUN pip install --no-cache-dir -r requirements.txt + +# Set the command to run the application +CMD python utils/other/hotreload.py "suggestions/src/app.py" \ No newline at end of file diff --git a/suggestions/requirements.txt b/suggestions/requirements.txt new file mode 100644 index 000000000..2c6bbca24 --- /dev/null +++ b/suggestions/requirements.txt @@ -0,0 +1,4 @@ +grpcio==1.60.0 +grpcio-tools==1.60.0 +protobuf>=4.25.0 +watchdog==6.0.0 diff --git a/suggestions/src/app.py b/suggestions/src/app.py new file mode 100644 index 000000000..b0d6f43fd --- /dev/null +++ b/suggestions/src/app.py @@ -0,0 +1,76 @@ +import sys +import os + +# This set of lines are needed to import the gRPC stubs. +# The path of the stubs is relative to the current file, or absolute inside the container. +# Change these lines only if strictly needed. +FILE = __file__ if '__file__' in globals() else os.getenv("PYTHONFILE", "") +suggestions_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/suggestions')) +sys.path.insert(0, suggestions_grpc_path) +import suggestions_pb2 as suggestions +import suggestions_pb2_grpc as suggestions_grpc + +import grpc +from concurrent import futures + +# Static books list +BOOKS = [ + {"book_id": "1", "title": "The Pragmatic Programmer", "author": "David Thomas"}, + {"book_id": "2", "title": "Clean Code", "author": "Robert C. Martin"}, + {"book_id": "3", "title": "Design Patterns", "author": "Gang of Four"}, + {"book_id": "4", "title": "The Hobbit", "author": "J.R.R. Tolkien"}, + {"book_id": "5", "title": "Harry Potter", "author": "J.K. Rowling"}, + {"book_id": "6", "title": "The Great Gatsby", "author": "F. Scott Fitzgerald"}, + {"book_id": "7", "title": "1984", "author": "George Orwell"}, + {"book_id": "8", "title": "To Kill a Mockingbird", "author": "Harper Lee"}, + {"book_id": "9", "title": "The Alchemist", "author": "Paulo Coelho"}, + {"book_id": "10", "title": "Dune", "author": "Frank Herbert"}, +] + +# Create a class to define the server functions +class SuggestionsService(suggestions_grpc.SuggestionsServiceServicer): + + def GetSuggestions(self, request, context): + print(f"Getting suggestions for user: {request.user_name}") + print(f"Items ordered: {[item.name for item in request.items]}") + + # Simple logic: exclude books that match ordered items + # and return first 3 suggestions + ordered_names = [item.name.lower() for item in request.items] + + suggested = [ + book for book in BOOKS + if book["title"].lower() not in ordered_names + ][:3] + + # Build response + response_books = [ + suggestions.Book( + book_id=book["book_id"], + title=book["title"], + author=book["author"] + ) + for book in suggested + ] + + print(f"Suggesting {len(response_books)} books") + return suggestions.SuggestionsResponse(books=response_books) + +def serve(): + # Create a gRPC server + server = grpc.server(futures.ThreadPoolExecutor()) + # Add SuggestionsService + suggestions_grpc.add_SuggestionsServiceServicer_to_server( + SuggestionsService(), server + ) + # Listen on port 50053 + port = "50053" + server.add_insecure_port("[::]:" + port) + # Start the server + server.start() + print("Suggestions server started. Listening on port 50053.") + # Keep thread alive + server.wait_for_termination() + +if __name__ == '__main__': + serve() \ No newline at end of file diff --git a/utils/pb/suggestions/suggestions.proto b/utils/pb/suggestions/suggestions.proto new file mode 100644 index 000000000..8757abf1c --- /dev/null +++ b/utils/pb/suggestions/suggestions.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +package suggestions; + +service SuggestionsService { + rpc GetSuggestions (SuggestionsRequest) returns (SuggestionsResponse); +} + +message SuggestionsRequest { + repeated Item items = 1; + string user_name = 2; +} + +message Item { + string name = 1; + int32 quantity = 2; +} + +message SuggestionsResponse { + repeated Book books = 1; +} + +message Book { + string book_id = 1; + string title = 2; + string author = 3; +} diff --git a/utils/pb/suggestions/suggestions_pb2.py b/utils/pb/suggestions/suggestions_pb2.py new file mode 100644 index 000000000..733f559fc --- /dev/null +++ b/utils/pb/suggestions/suggestions_pb2.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: suggestions.proto +# Protobuf Python Version: 4.25.0 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11suggestions.proto\x12\x0bsuggestions\"I\n\x12SuggestionsRequest\x12 \n\x05items\x18\x01 \x03(\x0b\x32\x11.suggestions.Item\x12\x11\n\tuser_name\x18\x02 \x01(\t\"&\n\x04Item\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x10\n\x08quantity\x18\x02 \x01(\x05\"7\n\x13SuggestionsResponse\x12 \n\x05\x62ooks\x18\x01 \x03(\x0b\x32\x11.suggestions.Book\"6\n\x04\x42ook\x12\x0f\n\x07\x62ook_id\x18\x01 \x01(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12\x0e\n\x06\x61uthor\x18\x03 \x01(\t2i\n\x12SuggestionsService\x12S\n\x0eGetSuggestions\x12\x1f.suggestions.SuggestionsRequest\x1a .suggestions.SuggestionsResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'suggestions_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_SUGGESTIONSREQUEST']._serialized_start=34 + _globals['_SUGGESTIONSREQUEST']._serialized_end=107 + _globals['_ITEM']._serialized_start=109 + _globals['_ITEM']._serialized_end=147 + _globals['_SUGGESTIONSRESPONSE']._serialized_start=149 + _globals['_SUGGESTIONSRESPONSE']._serialized_end=204 + _globals['_BOOK']._serialized_start=206 + _globals['_BOOK']._serialized_end=260 + _globals['_SUGGESTIONSSERVICE']._serialized_start=262 + _globals['_SUGGESTIONSSERVICE']._serialized_end=367 +# @@protoc_insertion_point(module_scope) diff --git a/utils/pb/suggestions/suggestions_pb2_grpc.py b/utils/pb/suggestions/suggestions_pb2_grpc.py new file mode 100644 index 000000000..ca1154a0b --- /dev/null +++ b/utils/pb/suggestions/suggestions_pb2_grpc.py @@ -0,0 +1,66 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +import suggestions_pb2 as suggestions__pb2 + + +class SuggestionsServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetSuggestions = channel.unary_unary( + '/suggestions.SuggestionsService/GetSuggestions', + request_serializer=suggestions__pb2.SuggestionsRequest.SerializeToString, + response_deserializer=suggestions__pb2.SuggestionsResponse.FromString, + ) + + +class SuggestionsServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + + def GetSuggestions(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_SuggestionsServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetSuggestions': grpc.unary_unary_rpc_method_handler( + servicer.GetSuggestions, + request_deserializer=suggestions__pb2.SuggestionsRequest.FromString, + response_serializer=suggestions__pb2.SuggestionsResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'suggestions.SuggestionsService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class SuggestionsService(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod + def GetSuggestions(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/suggestions.SuggestionsService/GetSuggestions', + suggestions__pb2.SuggestionsRequest.SerializeToString, + suggestions__pb2.SuggestionsResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) From 2f82c3fa0e79d3d66a08a31d0b0064155a82f9f6 Mon Sep 17 00:00:00 2001 From: anupkumar Date: Mon, 2 Mar 2026 12:53:22 +0200 Subject: [PATCH 16/18] Revert "Merge branch 'Mumin' into anup_dev" This reverts commit 6e6d4fafea1c121dd48a64a53c08757752b6bbf6, reversing changes made to 06c1f459f157ba435e3d55f3eb90d8f73131e50c. --- docker-compose.yaml | 27 +- fraud_detection/requirements.txt | 2 +- fraud_detection/src/app.py | 63 ++-- orchestrator/requirements.txt | 2 +- orchestrator/src/app.py | 330 ++++++++++++------ suggestions/Dockerfile | 7 - suggestions/requirements.txt | 4 +- suggestions/src/app.py | 78 ++--- test_path.py | 8 - transaction_verification/Dockerfile | 7 - transaction_verification/requirements.txt | 4 +- transaction_verification/src/app.py | 98 ++---- .../pb/fraud_detection/fraud_detection.proto | 27 +- .../pb/fraud_detection/fraud_detection_pb2.py | 18 +- .../fraud_detection/fraud_detection_pb2.pyi | 32 +- .../fraud_detection_pb2_grpc.py | 36 +- utils/pb/suggestions/suggestions.proto | 23 +- utils/pb/suggestions/suggestions_pb2.py | 18 +- .../transaction_verification.proto | 28 +- .../transaction_verification_pb2.py | 16 +- .../transaction_verification_pb2.pyi | 46 +-- .../transaction_verification_pb2_grpc.py | 12 +- 22 files changed, 477 insertions(+), 409 deletions(-) delete mode 100644 test_path.py diff --git a/docker-compose.yaml b/docker-compose.yaml index 9729cb909..e4818a9c8 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -13,6 +13,7 @@ services: volumes: # Mount the frontend directory - ./frontend/src:/usr/share/nginx/html + orchestrator: build: # Use the current directory as the build context @@ -35,12 +36,13 @@ services: - ./utils:/app/utils # Mount the orchestrator/src directory in the current directory to the /app/orchestrator/src directory in the container - ./orchestrator/src:/app/orchestrator/src + fraud_detection: build: # Use the current directory as the build context # This allows us to access the files in the current directory inside the Dockerfile context: ./ - # Use the Dockerfile in the fraud_detection directorys + # Use the Dockerfile in the fraud_detection directory dockerfile: ./fraud_detection/Dockerfile ports: # Expose port 50051 on the host, and map port 50051 of the container to port 50051 on the host @@ -61,7 +63,6 @@ services: transaction_verification: build: # Use the current directory as the build context - # This allows us to access the files in the current directory inside the Dockerfile context: ./ # Use the Dockerfile in the transaction_verification directory dockerfile: ./transaction_verification/Dockerfile @@ -70,34 +71,24 @@ services: - 50052:50052 environment: # Pass the environment variables to the container - # The PYTHONUNBUFFERED environment variable ensures that the output from the application is logged to the console - PYTHONUNBUFFERED=TRUE # The PYTHONFILE environment variable specifies the absolute entry point of the application - # Check app.py in the transaction_verification directory to see how this is used - PYTHONFILE=/app/transaction_verification/src/app.py volumes: # Mount the utils directory in the current directory to the /app/utils directory in the container - ./utils:/app/utils - # Mount the transaction_verification/src directory in the current directory to the /app/transaction_verification/src directory in the container + # Mount the transaction_verification/src directory in the current directory to the container - ./transaction_verification/src:/app/transaction_verification/src suggestions: build: - # Use the current directory as the build context - # This allows us to access the files in the current directory inside the Dockerfile context: ./ - # Use the Dockerfile in the suggestions directory dockerfile: ./suggestions/Dockerfile ports: - # Expose port 50053 on the host, and map port 50053 of the container to port 50053 on the host - - 50053:50053 + - 50053:50053 environment: - # Pass the environment variables to the container - # The PYTHONUNBUFFERED environment variable ensures that the output from the application is logged to the console - - PYTHONUNBUFFERED=TRUE - - PYTHONFILE=/app/suggestions/src/app.py + - PYTHONUNBUFFERED=TRUE + - PYTHONFILE=/app/suggestions/src/app.py volumes: - # Mount the utils directory in the current directory to the /app/utils directory in the container - - ./utils:/app/utils - # Mount the suggestions/src directory in the current directory to the /app/suggestions/src directory in the container - - ./suggestions/src:/app/suggestions/src + - ./utils:/app/utils + - ./suggestions/src:/app/suggestions/src \ No newline at end of file diff --git a/fraud_detection/requirements.txt b/fraud_detection/requirements.txt index b20ca4bc3..a80eedef7 100644 --- a/fraud_detection/requirements.txt +++ b/fraud_detection/requirements.txt @@ -1,4 +1,4 @@ grpcio==1.60.0 grpcio-tools==1.60.0 -protobuf==4.25.0 +protobuf==4.25.2 watchdog==6.0.0 diff --git a/fraud_detection/src/app.py b/fraud_detection/src/app.py index b85b64b9d..d932ef47d 100644 --- a/fraud_detection/src/app.py +++ b/fraud_detection/src/app.py @@ -1,47 +1,64 @@ import sys import os +from concurrent import futures # This set of lines are needed to import the gRPC stubs. -# The path of the stubs is relative to the current file, or absolute inside the container. -# Change these lines only if strictly needed. FILE = __file__ if '__file__' in globals() else os.getenv("PYTHONFILE", "") -fraud_detection_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/fraud_detection')) +fraud_detection_grpc_path = os.path.abspath( + os.path.join(FILE, '../../../utils/pb/fraud_detection') +) sys.path.insert(0, fraud_detection_grpc_path) + +import grpc import fraud_detection_pb2 as fraud_detection import fraud_detection_pb2_grpc as fraud_detection_grpc -import grpc -from concurrent import futures -# Create a class to define the server functions, derived from -# fraud_detection_pb2_grpc.HelloServiceServicer -class FraudService(fraud_detection_grpc.FraudDetectionServiceServicer): - # Create an RPC function to say hello +class HelloService(fraud_detection_grpc.HelloServiceServicer): + def SayHello(self, request, context): + response = fraud_detection.HelloResponse() + response.greeting = "Hello, " + request.name + print(response.greeting) + return response + def CheckFraud(self, request, context): - card_number = request.card_number - order_amount = request.order_amount + print("Received fraud check request") + print("user_name:", request.user_name) + print("card_number:", request.card_number) + print("item_count:", request.item_count) - print(f"Checking fraud for card number: {card_number} and order amount: {order_amount}") - # Dummy Logic if amount > 1000 or card_number starts with 999 then it is fraud is_fraud = False - if order_amount > 1000 or card_number.startswith("999"): + message = "No fraud detected." + + # Very simple dummy rules for now + if request.item_count > 10: is_fraud = True - - return fraud_detection.FraudResponse(is_fraud=is_fraud) + message = "Too many items in order." + elif request.card_number.endswith("0000"): + is_fraud = True + message = "Suspicious card number pattern." + elif "fraud" in request.user_name.lower(): + is_fraud = True + message = "Suspicious user name." + + response = fraud_detection.FraudCheckResponse() + response.is_fraud = is_fraud + response.message = message + + print("Returning fraud result:", response.is_fraud, response.message) + return response + def serve(): - # Create a gRPC server server = grpc.server(futures.ThreadPoolExecutor()) - # Add HelloService - fraud_detection_grpc.add_FraudDetectionServiceServicer_to_server(FraudService(), server) - # Listen on port 50051 + fraud_detection_grpc.add_HelloServiceServicer_to_server(HelloService(), server) + port = "50051" server.add_insecure_port("[::]:" + port) - # Start the server server.start() - print("Server started. Listening on port 50051.") - # Keep thread alive + print("Fraud detection server started. Listening on port 50051.") server.wait_for_termination() + if __name__ == '__main__': serve() \ No newline at end of file diff --git a/orchestrator/requirements.txt b/orchestrator/requirements.txt index f8c1ab8cb..5ba8e254b 100644 --- a/orchestrator/requirements.txt +++ b/orchestrator/requirements.txt @@ -6,7 +6,7 @@ grpcio-tools==1.60.0 itsdangerous==2.1.2 Jinja2==3.1.3 MarkupSafe==2.1.3 -protobuf>=4.25.0 +protobuf==4.25.2 Werkzeug==3.0.1 Flask-CORS==4.0.0 watchdog==6.0.0 \ No newline at end of file diff --git a/orchestrator/src/app.py b/orchestrator/src/app.py index b962da36a..64341eb19 100644 --- a/orchestrator/src/app.py +++ b/orchestrator/src/app.py @@ -1,159 +1,269 @@ import sys import os +import threading +# This set of lines are needed to import the gRPC stubs. +# The path of the stubs is relative to the current file, or absolute inside the container. +# Change these lines only if strictly needed. FILE = __file__ if '__file__' in globals() else os.getenv("PYTHONFILE", "") -# Import fraud detection stubs -fraud_detection_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/fraud_detection')) +fraud_detection_grpc_path = os.path.abspath( + os.path.join(FILE, '../../../utils/pb/fraud_detection') +) sys.path.insert(0, fraud_detection_grpc_path) import fraud_detection_pb2 as fraud_detection import fraud_detection_pb2_grpc as fraud_detection_grpc -# Import transaction verification stubs -transaction_verification_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/transaction_verification')) +transaction_verification_grpc_path = os.path.abspath( + os.path.join(FILE, '../../../utils/pb/transaction_verification') +) sys.path.insert(0, transaction_verification_grpc_path) import transaction_verification_pb2 as transaction_verification import transaction_verification_pb2_grpc as transaction_verification_grpc -# Import suggestions stubs -suggestions_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/suggestions')) +suggestions_grpc_path = os.path.abspath( + os.path.join(FILE, '../../../utils/pb/suggestions') +) sys.path.insert(0, suggestions_grpc_path) import suggestions_pb2 as suggestions import suggestions_pb2_grpc as suggestions_grpc import grpc + from flask import Flask, request from flask_cors import CORS + def greet(name='you'): with grpc.insecure_channel('fraud_detection:50051') as channel: stub = fraud_detection_grpc.HelloServiceStub(channel) response = stub.SayHello(fraud_detection.HelloRequest(name=name)) return response.greeting -def call_fraud_detection(card_number, order_amount): - try: - with grpc.insecure_channel('fraud_detection:50051') as channel: - stub = fraud_detection_grpc.FraudDetectionServiceStub(channel) - request_obj = fraud_detection.FraudRequest( - card_number=card_number, - order_amount=order_amount + +def detect_fraud(user_name, card_number, item_count): + with grpc.insecure_channel('fraud_detection:50051') as channel: + stub = fraud_detection_grpc.HelloServiceStub(channel) + response = stub.CheckFraud( + fraud_detection.FraudCheckRequest( + user_name=user_name or "", + card_number=card_number or "", + item_count=item_count ) - response = stub.CheckFraud(request_obj) - return response.is_fraud - except Exception as e: - print(f"Fraud detection gRPC call failed: {e}") - return True - -def call_transaction_verification(request_data): - try: - with grpc.insecure_channel('transaction_verification:50052') as channel: - stub = transaction_verification_grpc.TransactionVerificationServiceStub(channel) - - card_info = request_data.get("creditCard", {}) - user_info = request_data.get("user", {}) - items = request_data.get("items", []) - - grpc_items = [ - transaction_verification.Item( - name=item.get("name", ""), - quantity=item.get("quantity", 0) - ) for item in items - ] - - request_obj = transaction_verification.TransactionRequest( - card_number=card_info.get("number", ""), - card_expiration=card_info.get("expirationDate", ""), - card_cvv=card_info.get("cvv", ""), - items=grpc_items, - user_name=user_info.get("name", ""), - user_contact=user_info.get("contact", "") + ) + return response + + +def verify_transaction(user_name, user_contact, card_number, expiration_date, cvv, item_count, terms_accepted): + with grpc.insecure_channel('transaction_verification:50052') as channel: + stub = transaction_verification_grpc.TransactionVerificationServiceStub(channel) + response = stub.VerifyTransaction( + transaction_verification.TransactionVerificationRequest( + user_name=user_name or "", + user_contact=user_contact or "", + card_number=card_number or "", + expiration_date=expiration_date or "", + cvv=cvv or "", + item_count=item_count, + terms_accepted=terms_accepted ) - response = stub.VerifyTransaction(request_obj) - return response.is_valid - except Exception as e: - print(f"Transaction verification gRPC call failed: {e}") - return False - -def call_suggestions(request_data): - try: - with grpc.insecure_channel('suggestions:50053') as channel: - stub = suggestions_grpc.SuggestionsServiceStub(channel) - - user_info = request_data.get("user", {}) - items = request_data.get("items", []) - - grpc_items = [ - suggestions.Item( - name=item.get("name", ""), - quantity=item.get("quantity", 0) - ) for item in items - ] - - request_obj = suggestions.SuggestionsRequest( - items=grpc_items, - user_name=user_info.get("name", "") + ) + return response + + +def get_suggestions(user_name, item_count): + with grpc.insecure_channel('suggestions:50053') as channel: + stub = suggestions_grpc.SuggestionsServiceStub(channel) + response = stub.GetSuggestions( + suggestions.SuggestionsRequest( + user_name=user_name or "", + item_count=item_count ) - response = stub.GetSuggestions(request_obj) + ) + return response - return [ - {"bookId": book.book_id, "title": book.title, "author": book.author} - for book in response.books - ] - except Exception as e: - print(f"Suggestions gRPC call failed: {e}") - return [] app = Flask(__name__) CORS(app, resources={r'/*': {'origins': '*'}}) + @app.route('/', methods=['GET']) def index(): response = greet(name='orchestrator') return response + @app.route('/checkout', methods=['POST']) def checkout(): - from concurrent.futures import ThreadPoolExecutor - try: - request_data = request.get_json(force=True, silent=True) or {} - print("Request Data:", request_data.get('items')) - - card_info = request_data.get("creditCard", {}) - card_number = card_info.get("number", "") - order_amount = request_data.get("totalAmount", 0.0) - - # Run all 3 services in parallel - with ThreadPoolExecutor(max_workers=3) as executor: - fraud_future = executor.submit(call_fraud_detection, card_number, order_amount) - verify_future = executor.submit(call_transaction_verification, request_data) - suggestions_future = executor.submit(call_suggestions, request_data) - - is_fraud = fraud_future.result() - is_valid = verify_future.result() - suggested_books = suggestions_future.result() - - print(f"Fraud: {is_fraud}, Valid: {is_valid}, Books: {len(suggested_books)}") - - # Consolidate results - if is_fraud or not is_valid: - order_status_response = { - 'orderId': '12345', - 'status': 'Order Rejected', - 'suggestedBooks': [] + request_data = request.get_json(silent=True) + + if request_data is None: + return { + "error": { + "code": "BAD_REQUEST", + "message": "Request body must be valid JSON." + } + }, 400 + + user = request_data.get("user", {}) + items = request_data.get("items", []) + shipping_method = request_data.get("shippingMethod") + terms_accepted = request_data.get("termsAndConditionsAccepted", False) + + user_name = user.get("name") + user_contact = user.get("contact") + user_comment = user.get("userComment", "") + + credit_card = user.get("creditCard", {}) + card_number = credit_card.get("number") + expiration_date = credit_card.get("expirationDate") + cvv = credit_card.get("cvv") + + print("FULL REQUEST DATA:", request_data) + print("USER NAME:", user_name) + print("USER CONTACT:", user_contact) + print("USER COMMENT:", user_comment) + print("ITEMS:", items) + print("SHIPPING METHOD:", shipping_method) + print("TERMS ACCEPTED:", terms_accepted) + print("CARD NUMBER:", card_number) + print("EXPIRATION DATE:", expiration_date) + print("CVV:", cvv) + + # Keep these simple bad-request checks locally + if not user_name: + return { + "error": { + "code": "BAD_REQUEST", + "message": "User name is required." } - else: - order_status_response = { - 'orderId': '12345', - 'status': 'Order Approved', - 'suggestedBooks': suggested_books + }, 400 + + if not user_contact: + return { + "error": { + "code": "BAD_REQUEST", + "message": "User contact is required." + } + }, 400 + + item_count = len(items) + + results = { + "fraud": None, + "verification": None, + "suggestions": None, + "errors": [] + } + + def fraud_worker(): + try: + print("Calling fraud_detection service...") + results["fraud"] = detect_fraud( + user_name=user_name, + card_number=card_number, + item_count=item_count + ) + print( + "fraud_detection result:", + results["fraud"].is_fraud, + results["fraud"].message + ) + except Exception as e: + error_msg = f"fraud_detection failed: {e}" + print(error_msg) + results["errors"].append(error_msg) + + def verification_worker(): + try: + print("Calling transaction_verification service...") + results["verification"] = verify_transaction( + user_name=user_name, + user_contact=user_contact, + card_number=card_number, + expiration_date=expiration_date, + cvv=cvv, + item_count=item_count, + terms_accepted=terms_accepted + ) + print( + "transaction_verification result:", + results["verification"].is_valid, + results["verification"].message + ) + except Exception as e: + error_msg = f"transaction_verification failed: {e}" + print(error_msg) + results["errors"].append(error_msg) + + def suggestions_worker(): + try: + print("Calling suggestions service...") + results["suggestions"] = get_suggestions( + user_name=user_name, + item_count=item_count + ) + print( + "suggestions returned:", + len(results["suggestions"].books), + "books" + ) + except Exception as e: + error_msg = f"suggestions failed: {e}" + print(error_msg) + results["errors"].append(error_msg) + + fraud_thread = threading.Thread(target=fraud_worker) + verification_thread = threading.Thread(target=verification_worker) + suggestions_thread = threading.Thread(target=suggestions_worker) + + print("Starting worker threads...") + fraud_thread.start() + verification_thread.start() + suggestions_thread.start() + + fraud_thread.join() + verification_thread.join() + suggestions_thread.join() + print("All worker threads finished.") + + if results["errors"]: + return { + "error": { + "code": "INTERNAL_ERROR", + "message": "; ".join(results["errors"]) } + }, 500 + + if results["fraud"] and results["fraud"].is_fraud: + return { + "orderId": "12345", + "status": "Order Rejected", + "suggestedBooks": [] + }, 200 + + if results["verification"] and not results["verification"].is_valid: + return { + "orderId": "12345", + "status": "Order Rejected", + "suggestedBooks": [] + }, 200 + + suggested_books = [] + if results["suggestions"]: + for book in results["suggestions"].books: + suggested_books.append({ + "bookId": book.bookId, + "title": book.title, + "author": book.author + }) - return order_status_response + return { + "orderId": "12345", + "status": "Order Approved", + "suggestedBooks": suggested_books + }, 200 - except Exception as e: - print(f"Checkout failed: {e}") - return {"error": {"message": str(e)}}, 500 if __name__ == '__main__': app.run(host='0.0.0.0') \ No newline at end of file diff --git a/suggestions/Dockerfile b/suggestions/Dockerfile index c618243eb..1c35664df 100644 --- a/suggestions/Dockerfile +++ b/suggestions/Dockerfile @@ -1,15 +1,8 @@ -# Use an official Python runtime as the base image FROM python:3.11 -# Set the working directory in the container -# Both the utils and src folders will be mounted as volumes, please see docker-compose.yaml WORKDIR /app -# Copy the requirements file to the working directory COPY ./suggestions/requirements.txt . - -# Install the Python dependencies RUN pip install --no-cache-dir -r requirements.txt -# Set the command to run the application CMD python utils/other/hotreload.py "suggestions/src/app.py" \ No newline at end of file diff --git a/suggestions/requirements.txt b/suggestions/requirements.txt index 2c6bbca24..43fdaf26f 100644 --- a/suggestions/requirements.txt +++ b/suggestions/requirements.txt @@ -1,4 +1,4 @@ grpcio==1.60.0 grpcio-tools==1.60.0 -protobuf>=4.25.0 -watchdog==6.0.0 +protobuf==4.25.2 +watchdog==6.0.0 \ No newline at end of file diff --git a/suggestions/src/app.py b/suggestions/src/app.py index b0d6f43fd..258c2fb0c 100644 --- a/suggestions/src/app.py +++ b/suggestions/src/app.py @@ -1,76 +1,60 @@ import sys import os +from concurrent import futures -# This set of lines are needed to import the gRPC stubs. -# The path of the stubs is relative to the current file, or absolute inside the container. -# Change these lines only if strictly needed. FILE = __file__ if '__file__' in globals() else os.getenv("PYTHONFILE", "") -suggestions_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/suggestions')) +suggestions_grpc_path = os.path.abspath( + os.path.join(FILE, '../../../utils/pb/suggestions') +) sys.path.insert(0, suggestions_grpc_path) -import suggestions_pb2 as suggestions -import suggestions_pb2_grpc as suggestions_grpc import grpc -from concurrent import futures +import suggestions_pb2 as suggestions +import suggestions_pb2_grpc as suggestions_grpc -# Static books list -BOOKS = [ - {"book_id": "1", "title": "The Pragmatic Programmer", "author": "David Thomas"}, - {"book_id": "2", "title": "Clean Code", "author": "Robert C. Martin"}, - {"book_id": "3", "title": "Design Patterns", "author": "Gang of Four"}, - {"book_id": "4", "title": "The Hobbit", "author": "J.R.R. Tolkien"}, - {"book_id": "5", "title": "Harry Potter", "author": "J.K. Rowling"}, - {"book_id": "6", "title": "The Great Gatsby", "author": "F. Scott Fitzgerald"}, - {"book_id": "7", "title": "1984", "author": "George Orwell"}, - {"book_id": "8", "title": "To Kill a Mockingbird", "author": "Harper Lee"}, - {"book_id": "9", "title": "The Alchemist", "author": "Paulo Coelho"}, - {"book_id": "10", "title": "Dune", "author": "Frank Herbert"}, -] -# Create a class to define the server functions class SuggestionsService(suggestions_grpc.SuggestionsServiceServicer): - def GetSuggestions(self, request, context): - print(f"Getting suggestions for user: {request.user_name}") - print(f"Items ordered: {[item.name for item in request.items]}") + print("Received suggestions request") + print("user_name:", request.user_name) + print("item_count:", request.item_count) + + static_books = [ + {"bookId": "101", "title": "Distributed Systems Basics", "author": "A. Author"}, + {"bookId": "102", "title": "Designing Data-Intensive Applications", "author": "Martin Kleppmann"}, + {"bookId": "103", "title": "Clean Code", "author": "Robert C. Martin"}, + {"bookId": "104", "title": "The Pragmatic Programmer", "author": "Andrew Hunt"}, + ] - # Simple logic: exclude books that match ordered items - # and return first 3 suggestions - ordered_names = [item.name.lower() for item in request.items] + response = suggestions.SuggestionsResponse() - suggested = [ - book for book in BOOKS - if book["title"].lower() not in ordered_names - ][:3] + if request.item_count > 0: + chosen = static_books[:2] + else: + chosen = [] - # Build response - response_books = [ - suggestions.Book( - book_id=book["book_id"], - title=book["title"], - author=book["author"] - ) - for book in suggested - ] + for book in chosen: + b = response.books.add() + b.bookId = book["bookId"] + b.title = book["title"] + b.author = book["author"] + + print("Returning", len(response.books), "suggested books") + return response - print(f"Suggesting {len(response_books)} books") - return suggestions.SuggestionsResponse(books=response_books) def serve(): - # Create a gRPC server server = grpc.server(futures.ThreadPoolExecutor()) - # Add SuggestionsService suggestions_grpc.add_SuggestionsServiceServicer_to_server( SuggestionsService(), server ) - # Listen on port 50053 + port = "50053" server.add_insecure_port("[::]:" + port) - # Start the server server.start() print("Suggestions server started. Listening on port 50053.") - # Keep thread alive server.wait_for_termination() + if __name__ == '__main__': serve() \ No newline at end of file diff --git a/test_path.py b/test_path.py deleted file mode 100644 index 6154cafa5..000000000 --- a/test_path.py +++ /dev/null @@ -1,8 +0,0 @@ -import os -import sys - -FILE = __file__ -print(f"FILE: {FILE}") -path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/fraud_detection')) -print(f"Path: {path}") -print(f"Directory exists: {os.path.exists(path)}") diff --git a/transaction_verification/Dockerfile b/transaction_verification/Dockerfile index 2adbd4e7d..ad4936c4a 100644 --- a/transaction_verification/Dockerfile +++ b/transaction_verification/Dockerfile @@ -1,15 +1,8 @@ -# Use an official Python runtime as the base image FROM python:3.11 -# Set the working directory in the container -# Both the utils and src folders will be mounted as volumes, please see docker-compose.yaml WORKDIR /app -# Copy the requirements file to the working directory COPY ./transaction_verification/requirements.txt . - -# Install the Python dependencies RUN pip install --no-cache-dir -r requirements.txt -# Set the command to run the application CMD python utils/other/hotreload.py "transaction_verification/src/app.py" \ No newline at end of file diff --git a/transaction_verification/requirements.txt b/transaction_verification/requirements.txt index 2c6bbca24..43fdaf26f 100644 --- a/transaction_verification/requirements.txt +++ b/transaction_verification/requirements.txt @@ -1,4 +1,4 @@ grpcio==1.60.0 grpcio-tools==1.60.0 -protobuf>=4.25.0 -watchdog==6.0.0 +protobuf==4.25.2 +watchdog==6.0.0 \ No newline at end of file diff --git a/transaction_verification/src/app.py b/transaction_verification/src/app.py index ad0d9158b..36f592052 100644 --- a/transaction_verification/src/app.py +++ b/transaction_verification/src/app.py @@ -1,89 +1,67 @@ import sys import os +from concurrent import futures -# This set of lines are needed to import the gRPC stubs. -# The path of the stubs is relative to the current file, or absolute inside the container. -# Change these lines only if strictly needed. FILE = __file__ if '__file__' in globals() else os.getenv("PYTHONFILE", "") -transaction_verification_grpc_path = os.path.abspath(os.path.join(FILE, '../../../utils/pb/transaction_verification')) +transaction_verification_grpc_path = os.path.abspath( + os.path.join(FILE, '../../../utils/pb/transaction_verification') +) sys.path.insert(0, transaction_verification_grpc_path) + +import grpc import transaction_verification_pb2 as transaction_verification import transaction_verification_pb2_grpc as transaction_verification_grpc -import grpc -from concurrent import futures -# Create a class to define the server functions, derived from -# transaction_verification_pb2_grpc.TransactionVerificationServiceServicer -class TransactionVerificationService(transaction_verification_grpc.TransactionVerificationServiceServicer): - # Create an RPC function to verify transaction +class TransactionVerificationService( + transaction_verification_grpc.TransactionVerificationServiceServicer +): def VerifyTransaction(self, request, context): - print(f"Verifying transaction for card: {request.card_number}") - - # Check 1: items list must not be empty - if len(request.items) == 0: - print("Verification failed: No items in order") - return transaction_verification.TransactionResponse( - is_valid=False, - reason="Order must contain at least one item" - ) + print("Received transaction verification request") + print("user_name:", request.user_name) + print("user_contact:", request.user_contact) + print("item_count:", request.item_count) + print("terms_accepted:", request.terms_accepted) - # Check 2: user data must be filled in - if not request.user_name or not request.user_contact: - print("Verification failed: Missing user data") - return transaction_verification.TransactionResponse( - is_valid=False, - reason="User name and contact are required" - ) + is_valid = True + message = "Transaction is valid." - # Check 3: card number must be 16 digits - card_number = request.card_number.replace(" ", "") - if not card_number.isdigit() or len(card_number) != 16: - print("Verification failed: Invalid card number") - return transaction_verification.TransactionResponse( - is_valid=False, - reason="Invalid card number format, must be 16 digits" - ) + if not request.user_name: + is_valid = False + message = "Missing user name." + elif not request.user_contact: + is_valid = False + message = "Missing user contact." + elif request.item_count <= 0: + is_valid = False + message = "No items in order." + elif not request.terms_accepted: + is_valid = False + message = "Terms and conditions not accepted." + elif not request.card_number or not request.expiration_date or not request.cvv: + is_valid = False + message = "Missing credit card information." - # Check 4: CVV must be 3 digits - if not request.card_cvv.isdigit() or len(request.card_cvv) != 3: - print("Verification failed: Invalid CVV") - return transaction_verification.TransactionResponse( - is_valid=False, - reason="Invalid CVV, must be 3 digits" - ) + response = transaction_verification.TransactionVerificationResponse() + response.is_valid = is_valid + response.message = message - # Check 5: expiration date format MM/YY - expiration = request.card_expiration - if len(expiration) != 5 or expiration[2] != '/' or \ - not expiration[:2].isdigit() or not expiration[3:].isdigit(): - print("Verification failed: Invalid expiration date") - return transaction_verification.TransactionResponse( - is_valid=False, - reason="Invalid expiration date, use MM/YY format" - ) + print("Returning verification result:", response.is_valid, response.message) + return response - print("Transaction verified successfully") - return transaction_verification.TransactionResponse( - is_valid=True, - reason="Transaction is valid" - ) def serve(): - # Create a gRPC server server = grpc.server(futures.ThreadPoolExecutor()) - # Add TransactionVerificationService transaction_verification_grpc.add_TransactionVerificationServiceServicer_to_server( TransactionVerificationService(), server ) - # Listen on port 50052 + port = "50052" server.add_insecure_port("[::]:" + port) - # Start the server server.start() print("Transaction verification server started. Listening on port 50052.") - # Keep thread alive server.wait_for_termination() + if __name__ == '__main__': serve() \ No newline at end of file diff --git a/utils/pb/fraud_detection/fraud_detection.proto b/utils/pb/fraud_detection/fraud_detection.proto index 54bdcb878..d575366b1 100644 --- a/utils/pb/fraud_detection/fraud_detection.proto +++ b/utils/pb/fraud_detection/fraud_detection.proto @@ -1,16 +1,27 @@ syntax = "proto3"; -package fraud_detection; +package hello; -service FraudDetectionService { - rpc CheckFraud (FraudRequest) returns (FraudResponse); +service HelloService { + rpc SayHello (HelloRequest) returns (HelloResponse); + rpc CheckFraud (FraudCheckRequest) returns (FraudCheckResponse); } -message FraudRequest { - string card_number = 1; - float order_amount = 2; +message HelloRequest { + string name = 1; } -message FraudResponse { - bool is_fraud = 1; +message HelloResponse { + string greeting = 1; } + +message FraudCheckRequest { + string user_name = 1; + string card_number = 2; + int32 item_count = 3; +} + +message FraudCheckResponse { + bool is_fraud = 1; + string message = 2; +} \ No newline at end of file diff --git a/utils/pb/fraud_detection/fraud_detection_pb2.py b/utils/pb/fraud_detection/fraud_detection_pb2.py index 4bb850ad5..d405d9cf5 100644 --- a/utils/pb/fraud_detection/fraud_detection_pb2.py +++ b/utils/pb/fraud_detection/fraud_detection_pb2.py @@ -14,17 +14,21 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66raud_detection.proto\x12\x0f\x66raud_detection\"9\n\x0c\x46raudRequest\x12\x13\n\x0b\x63\x61rd_number\x18\x01 \x01(\t\x12\x14\n\x0corder_amount\x18\x02 \x01(\x02\"!\n\rFraudResponse\x12\x10\n\x08is_fraud\x18\x01 \x01(\x08\x32\x64\n\x15\x46raudDetectionService\x12K\n\nCheckFraud\x12\x1d.fraud_detection.FraudRequest\x1a\x1e.fraud_detection.FraudResponseb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x66raud_detection.proto\x12\x05hello\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"!\n\rHelloResponse\x12\x10\n\x08greeting\x18\x01 \x01(\t\"O\n\x11\x46raudCheckRequest\x12\x11\n\tuser_name\x18\x01 \x01(\t\x12\x13\n\x0b\x63\x61rd_number\x18\x02 \x01(\t\x12\x12\n\nitem_count\x18\x03 \x01(\x05\"7\n\x12\x46raudCheckResponse\x12\x10\n\x08is_fraud\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t2\x88\x01\n\x0cHelloService\x12\x35\n\x08SayHello\x12\x13.hello.HelloRequest\x1a\x14.hello.HelloResponse\x12\x41\n\nCheckFraud\x12\x18.hello.FraudCheckRequest\x1a\x19.hello.FraudCheckResponseb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'fraud_detection_pb2', _globals) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None - _globals['_FRAUDREQUEST']._serialized_start=42 - _globals['_FRAUDREQUEST']._serialized_end=99 - _globals['_FRAUDRESPONSE']._serialized_start=101 - _globals['_FRAUDRESPONSE']._serialized_end=134 - _globals['_FRAUDDETECTIONSERVICE']._serialized_start=136 - _globals['_FRAUDDETECTIONSERVICE']._serialized_end=236 + _globals['_HELLOREQUEST']._serialized_start=32 + _globals['_HELLOREQUEST']._serialized_end=60 + _globals['_HELLORESPONSE']._serialized_start=62 + _globals['_HELLORESPONSE']._serialized_end=95 + _globals['_FRAUDCHECKREQUEST']._serialized_start=97 + _globals['_FRAUDCHECKREQUEST']._serialized_end=176 + _globals['_FRAUDCHECKRESPONSE']._serialized_start=178 + _globals['_FRAUDCHECKRESPONSE']._serialized_end=233 + _globals['_HELLOSERVICE']._serialized_start=236 + _globals['_HELLOSERVICE']._serialized_end=372 # @@protoc_insertion_point(module_scope) diff --git a/utils/pb/fraud_detection/fraud_detection_pb2.pyi b/utils/pb/fraud_detection/fraud_detection_pb2.pyi index 08a4f9a0f..fe3863b06 100644 --- a/utils/pb/fraud_detection/fraud_detection_pb2.pyi +++ b/utils/pb/fraud_detection/fraud_detection_pb2.pyi @@ -4,16 +4,32 @@ from typing import ClassVar as _ClassVar, Optional as _Optional DESCRIPTOR: _descriptor.FileDescriptor -class FraudRequest(_message.Message): - __slots__ = ("card_number", "order_amount") +class HelloRequest(_message.Message): + __slots__ = ("name",) + NAME_FIELD_NUMBER: _ClassVar[int] + name: str + def __init__(self, name: _Optional[str] = ...) -> None: ... + +class HelloResponse(_message.Message): + __slots__ = ("greeting",) + GREETING_FIELD_NUMBER: _ClassVar[int] + greeting: str + def __init__(self, greeting: _Optional[str] = ...) -> None: ... + +class FraudCheckRequest(_message.Message): + __slots__ = ("user_name", "card_number", "item_count") + USER_NAME_FIELD_NUMBER: _ClassVar[int] CARD_NUMBER_FIELD_NUMBER: _ClassVar[int] - ORDER_AMOUNT_FIELD_NUMBER: _ClassVar[int] + ITEM_COUNT_FIELD_NUMBER: _ClassVar[int] + user_name: str card_number: str - order_amount: float - def __init__(self, card_number: _Optional[str] = ..., order_amount: _Optional[float] = ...) -> None: ... + item_count: int + def __init__(self, user_name: _Optional[str] = ..., card_number: _Optional[str] = ..., item_count: _Optional[int] = ...) -> None: ... -class FraudResponse(_message.Message): - __slots__ = ("is_fraud",) +class FraudCheckResponse(_message.Message): + __slots__ = ("is_fraud", "message") IS_FRAUD_FIELD_NUMBER: _ClassVar[int] + MESSAGE_FIELD_NUMBER: _ClassVar[int] is_fraud: bool - def __init__(self, is_fraud: bool = ...) -> None: ... + message: str + def __init__(self, is_fraud: bool = ..., message: _Optional[str] = ...) -> None: ... diff --git a/utils/pb/fraud_detection/fraud_detection_pb2_grpc.py b/utils/pb/fraud_detection/fraud_detection_pb2_grpc.py index 65c6272e6..3ada2e86e 100644 --- a/utils/pb/fraud_detection/fraud_detection_pb2_grpc.py +++ b/utils/pb/fraud_detection/fraud_detection_pb2_grpc.py @@ -5,7 +5,7 @@ import fraud_detection_pb2 as fraud__detection__pb2 -class FraudDetectionServiceStub(object): +class HelloServiceStub(object): """Missing associated documentation comment in .proto file.""" def __init__(self, channel): @@ -14,10 +14,10 @@ def __init__(self, channel): Args: channel: A grpc.Channel. """ - self.CheckFraud = channel.unary_unary( - '/fraud_detection.FraudDetectionService/CheckFraud', - request_serializer=fraud__detection__pb2.FraudRequest.SerializeToString, - response_deserializer=fraud__detection__pb2.FraudResponse.FromString, + self.SayHello = channel.unary_unary( + '/hello.HelloService/SayHello', + request_serializer=fraud__detection__pb2.HelloRequest.SerializeToString, + response_deserializer=fraud__detection__pb2.HelloResponse.FromString, ) self.CheckFraud = channel.unary_unary( '/hello.HelloService/CheckFraud', @@ -26,10 +26,10 @@ def __init__(self, channel): ) -class FraudDetectionServiceServicer(object): +class HelloServiceServicer(object): """Missing associated documentation comment in .proto file.""" - def CheckFraud(self, request, context): + def SayHello(self, request, context): """Missing associated documentation comment in .proto file.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -42,12 +42,12 @@ def CheckFraud(self, request, context): raise NotImplementedError('Method not implemented!') -def add_FraudDetectionServiceServicer_to_server(servicer, server): +def add_HelloServiceServicer_to_server(servicer, server): rpc_method_handlers = { - 'CheckFraud': grpc.unary_unary_rpc_method_handler( - servicer.CheckFraud, - request_deserializer=fraud__detection__pb2.FraudRequest.FromString, - response_serializer=fraud__detection__pb2.FraudResponse.SerializeToString, + 'SayHello': grpc.unary_unary_rpc_method_handler( + servicer.SayHello, + request_deserializer=fraud__detection__pb2.HelloRequest.FromString, + response_serializer=fraud__detection__pb2.HelloResponse.SerializeToString, ), 'CheckFraud': grpc.unary_unary_rpc_method_handler( servicer.CheckFraud, @@ -56,16 +56,16 @@ def add_FraudDetectionServiceServicer_to_server(servicer, server): ), } generic_handler = grpc.method_handlers_generic_handler( - 'fraud_detection.FraudDetectionService', rpc_method_handlers) + 'hello.HelloService', rpc_method_handlers) server.add_generic_rpc_handlers((generic_handler,)) # This class is part of an EXPERIMENTAL API. -class FraudDetectionService(object): +class HelloService(object): """Missing associated documentation comment in .proto file.""" @staticmethod - def CheckFraud(request, + def SayHello(request, target, options=(), channel_credentials=None, @@ -75,9 +75,9 @@ def CheckFraud(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/fraud_detection.FraudDetectionService/CheckFraud', - fraud__detection__pb2.FraudRequest.SerializeToString, - fraud__detection__pb2.FraudResponse.FromString, + return grpc.experimental.unary_unary(request, target, '/hello.HelloService/SayHello', + fraud__detection__pb2.HelloRequest.SerializeToString, + fraud__detection__pb2.HelloResponse.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/utils/pb/suggestions/suggestions.proto b/utils/pb/suggestions/suggestions.proto index 8757abf1c..12f15f4cb 100644 --- a/utils/pb/suggestions/suggestions.proto +++ b/utils/pb/suggestions/suggestions.proto @@ -3,25 +3,20 @@ syntax = "proto3"; package suggestions; service SuggestionsService { - rpc GetSuggestions (SuggestionsRequest) returns (SuggestionsResponse); + rpc GetSuggestions (SuggestionsRequest) returns (SuggestionsResponse); } message SuggestionsRequest { - repeated Item items = 1; - string user_name = 2; + string user_name = 1; + int32 item_count = 2; } -message Item { - string name = 1; - int32 quantity = 2; +message SuggestedBook { + string bookId = 1; + string title = 2; + string author = 3; } message SuggestionsResponse { - repeated Book books = 1; -} - -message Book { - string book_id = 1; - string title = 2; - string author = 3; -} + repeated SuggestedBook books = 1; +} \ No newline at end of file diff --git a/utils/pb/suggestions/suggestions_pb2.py b/utils/pb/suggestions/suggestions_pb2.py index 733f559fc..550a4d48e 100644 --- a/utils/pb/suggestions/suggestions_pb2.py +++ b/utils/pb/suggestions/suggestions_pb2.py @@ -14,7 +14,7 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11suggestions.proto\x12\x0bsuggestions\"I\n\x12SuggestionsRequest\x12 \n\x05items\x18\x01 \x03(\x0b\x32\x11.suggestions.Item\x12\x11\n\tuser_name\x18\x02 \x01(\t\"&\n\x04Item\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x10\n\x08quantity\x18\x02 \x01(\x05\"7\n\x13SuggestionsResponse\x12 \n\x05\x62ooks\x18\x01 \x03(\x0b\x32\x11.suggestions.Book\"6\n\x04\x42ook\x12\x0f\n\x07\x62ook_id\x18\x01 \x01(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12\x0e\n\x06\x61uthor\x18\x03 \x01(\t2i\n\x12SuggestionsService\x12S\n\x0eGetSuggestions\x12\x1f.suggestions.SuggestionsRequest\x1a .suggestions.SuggestionsResponseb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11suggestions.proto\x12\x0bsuggestions\";\n\x12SuggestionsRequest\x12\x11\n\tuser_name\x18\x01 \x01(\t\x12\x12\n\nitem_count\x18\x02 \x01(\x05\">\n\rSuggestedBook\x12\x0e\n\x06\x62ookId\x18\x01 \x01(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12\x0e\n\x06\x61uthor\x18\x03 \x01(\t\"@\n\x13SuggestionsResponse\x12)\n\x05\x62ooks\x18\x01 \x03(\x0b\x32\x1a.suggestions.SuggestedBook2i\n\x12SuggestionsService\x12S\n\x0eGetSuggestions\x12\x1f.suggestions.SuggestionsRequest\x1a .suggestions.SuggestionsResponseb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -22,13 +22,11 @@ if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None _globals['_SUGGESTIONSREQUEST']._serialized_start=34 - _globals['_SUGGESTIONSREQUEST']._serialized_end=107 - _globals['_ITEM']._serialized_start=109 - _globals['_ITEM']._serialized_end=147 - _globals['_SUGGESTIONSRESPONSE']._serialized_start=149 - _globals['_SUGGESTIONSRESPONSE']._serialized_end=204 - _globals['_BOOK']._serialized_start=206 - _globals['_BOOK']._serialized_end=260 - _globals['_SUGGESTIONSSERVICE']._serialized_start=262 - _globals['_SUGGESTIONSSERVICE']._serialized_end=367 + _globals['_SUGGESTIONSREQUEST']._serialized_end=93 + _globals['_SUGGESTEDBOOK']._serialized_start=95 + _globals['_SUGGESTEDBOOK']._serialized_end=157 + _globals['_SUGGESTIONSRESPONSE']._serialized_start=159 + _globals['_SUGGESTIONSRESPONSE']._serialized_end=223 + _globals['_SUGGESTIONSSERVICE']._serialized_start=225 + _globals['_SUGGESTIONSSERVICE']._serialized_end=330 # @@protoc_insertion_point(module_scope) diff --git a/utils/pb/transaction_verification/transaction_verification.proto b/utils/pb/transaction_verification/transaction_verification.proto index bfe033a8e..44ba9cec7 100644 --- a/utils/pb/transaction_verification/transaction_verification.proto +++ b/utils/pb/transaction_verification/transaction_verification.proto @@ -3,24 +3,20 @@ syntax = "proto3"; package transaction_verification; service TransactionVerificationService { - rpc VerifyTransaction (TransactionRequest) returns (TransactionResponse); + rpc VerifyTransaction (TransactionVerificationRequest) returns (TransactionVerificationResponse); } -message TransactionRequest { - string card_number = 1; - string card_expiration = 2; - string card_cvv = 3; - repeated Item items = 4; - string user_name = 5; - string user_contact = 6; +message TransactionVerificationRequest { + string user_name = 1; + string user_contact = 2; + string card_number = 3; + string expiration_date = 4; + string cvv = 5; + int32 item_count = 6; + bool terms_accepted = 7; } -message Item { - string name = 1; - int32 quantity = 2; -} - -message TransactionResponse { - bool is_valid = 1; - string reason = 2; +message TransactionVerificationResponse { + bool is_valid = 1; + string message = 2; } \ No newline at end of file diff --git a/utils/pb/transaction_verification/transaction_verification_pb2.py b/utils/pb/transaction_verification/transaction_verification_pb2.py index db0e5922d..447731158 100644 --- a/utils/pb/transaction_verification/transaction_verification_pb2.py +++ b/utils/pb/transaction_verification/transaction_verification_pb2.py @@ -14,19 +14,17 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1etransaction_verification.proto\x12\x18transaction_verification\"\xac\x01\n\x12TransactionRequest\x12\x13\n\x0b\x63\x61rd_number\x18\x01 \x01(\t\x12\x17\n\x0f\x63\x61rd_expiration\x18\x02 \x01(\t\x12\x10\n\x08\x63\x61rd_cvv\x18\x03 \x01(\t\x12-\n\x05items\x18\x04 \x03(\x0b\x32\x1e.transaction_verification.Item\x12\x11\n\tuser_name\x18\x05 \x01(\t\x12\x14\n\x0cuser_contact\x18\x06 \x01(\t\"&\n\x04Item\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x10\n\x08quantity\x18\x02 \x01(\x05\"7\n\x13TransactionResponse\x12\x10\n\x08is_valid\x18\x01 \x01(\x08\x12\x0e\n\x06reason\x18\x02 \x01(\t2\x92\x01\n\x1eTransactionVerificationService\x12p\n\x11VerifyTransaction\x12,.transaction_verification.TransactionRequest\x1a-.transaction_verification.TransactionResponseb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1etransaction_verification.proto\x12\x18transaction_verification\"\xb0\x01\n\x1eTransactionVerificationRequest\x12\x11\n\tuser_name\x18\x01 \x01(\t\x12\x14\n\x0cuser_contact\x18\x02 \x01(\t\x12\x13\n\x0b\x63\x61rd_number\x18\x03 \x01(\t\x12\x17\n\x0f\x65xpiration_date\x18\x04 \x01(\t\x12\x0b\n\x03\x63vv\x18\x05 \x01(\t\x12\x12\n\nitem_count\x18\x06 \x01(\x05\x12\x16\n\x0eterms_accepted\x18\x07 \x01(\x08\"D\n\x1fTransactionVerificationResponse\x12\x10\n\x08is_valid\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t2\xab\x01\n\x1eTransactionVerificationService\x12\x88\x01\n\x11VerifyTransaction\x12\x38.transaction_verification.TransactionVerificationRequest\x1a\x39.transaction_verification.TransactionVerificationResponseb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'transaction_verification_pb2', _globals) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None - _globals['_TRANSACTIONREQUEST']._serialized_start=61 - _globals['_TRANSACTIONREQUEST']._serialized_end=233 - _globals['_ITEM']._serialized_start=235 - _globals['_ITEM']._serialized_end=273 - _globals['_TRANSACTIONRESPONSE']._serialized_start=275 - _globals['_TRANSACTIONRESPONSE']._serialized_end=330 - _globals['_TRANSACTIONVERIFICATIONSERVICE']._serialized_start=333 - _globals['_TRANSACTIONVERIFICATIONSERVICE']._serialized_end=479 + _globals['_TRANSACTIONVERIFICATIONREQUEST']._serialized_start=61 + _globals['_TRANSACTIONVERIFICATIONREQUEST']._serialized_end=237 + _globals['_TRANSACTIONVERIFICATIONRESPONSE']._serialized_start=239 + _globals['_TRANSACTIONVERIFICATIONRESPONSE']._serialized_end=307 + _globals['_TRANSACTIONVERIFICATIONSERVICE']._serialized_start=310 + _globals['_TRANSACTIONVERIFICATIONSERVICE']._serialized_end=481 # @@protoc_insertion_point(module_scope) diff --git a/utils/pb/transaction_verification/transaction_verification_pb2.pyi b/utils/pb/transaction_verification/transaction_verification_pb2.pyi index 03f9d43be..5bb457074 100644 --- a/utils/pb/transaction_verification/transaction_verification_pb2.pyi +++ b/utils/pb/transaction_verification/transaction_verification_pb2.pyi @@ -1,39 +1,31 @@ -from google.protobuf.internal import containers as _containers from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message -from collections.abc import Iterable as _Iterable, Mapping as _Mapping -from typing import ClassVar as _ClassVar, Optional as _Optional, Union as _Union +from typing import ClassVar as _ClassVar, Optional as _Optional DESCRIPTOR: _descriptor.FileDescriptor -class TransactionRequest(_message.Message): - __slots__ = ("card_number", "card_expiration", "card_cvv", "items", "user_name", "user_contact") - CARD_NUMBER_FIELD_NUMBER: _ClassVar[int] - CARD_EXPIRATION_FIELD_NUMBER: _ClassVar[int] - CARD_CVV_FIELD_NUMBER: _ClassVar[int] - ITEMS_FIELD_NUMBER: _ClassVar[int] +class TransactionVerificationRequest(_message.Message): + __slots__ = ("user_name", "user_contact", "card_number", "expiration_date", "cvv", "item_count", "terms_accepted") USER_NAME_FIELD_NUMBER: _ClassVar[int] USER_CONTACT_FIELD_NUMBER: _ClassVar[int] - card_number: str - card_expiration: str - card_cvv: str - items: _containers.RepeatedCompositeFieldContainer[Item] + CARD_NUMBER_FIELD_NUMBER: _ClassVar[int] + EXPIRATION_DATE_FIELD_NUMBER: _ClassVar[int] + CVV_FIELD_NUMBER: _ClassVar[int] + ITEM_COUNT_FIELD_NUMBER: _ClassVar[int] + TERMS_ACCEPTED_FIELD_NUMBER: _ClassVar[int] user_name: str user_contact: str - def __init__(self, card_number: _Optional[str] = ..., card_expiration: _Optional[str] = ..., card_cvv: _Optional[str] = ..., items: _Optional[_Iterable[_Union[Item, _Mapping]]] = ..., user_name: _Optional[str] = ..., user_contact: _Optional[str] = ...) -> None: ... - -class Item(_message.Message): - __slots__ = ("name", "quantity") - NAME_FIELD_NUMBER: _ClassVar[int] - QUANTITY_FIELD_NUMBER: _ClassVar[int] - name: str - quantity: int - def __init__(self, name: _Optional[str] = ..., quantity: _Optional[int] = ...) -> None: ... + card_number: str + expiration_date: str + cvv: str + item_count: int + terms_accepted: bool + def __init__(self, user_name: _Optional[str] = ..., user_contact: _Optional[str] = ..., card_number: _Optional[str] = ..., expiration_date: _Optional[str] = ..., cvv: _Optional[str] = ..., item_count: _Optional[int] = ..., terms_accepted: bool = ...) -> None: ... -class TransactionResponse(_message.Message): - __slots__ = ("is_valid", "reason") +class TransactionVerificationResponse(_message.Message): + __slots__ = ("is_valid", "message") IS_VALID_FIELD_NUMBER: _ClassVar[int] - REASON_FIELD_NUMBER: _ClassVar[int] + MESSAGE_FIELD_NUMBER: _ClassVar[int] is_valid: bool - reason: str - def __init__(self, is_valid: bool = ..., reason: _Optional[str] = ...) -> None: ... + message: str + def __init__(self, is_valid: bool = ..., message: _Optional[str] = ...) -> None: ... diff --git a/utils/pb/transaction_verification/transaction_verification_pb2_grpc.py b/utils/pb/transaction_verification/transaction_verification_pb2_grpc.py index 95871b9bf..32d7e091c 100644 --- a/utils/pb/transaction_verification/transaction_verification_pb2_grpc.py +++ b/utils/pb/transaction_verification/transaction_verification_pb2_grpc.py @@ -16,8 +16,8 @@ def __init__(self, channel): """ self.VerifyTransaction = channel.unary_unary( '/transaction_verification.TransactionVerificationService/VerifyTransaction', - request_serializer=transaction__verification__pb2.TransactionRequest.SerializeToString, - response_deserializer=transaction__verification__pb2.TransactionResponse.FromString, + request_serializer=transaction__verification__pb2.TransactionVerificationRequest.SerializeToString, + response_deserializer=transaction__verification__pb2.TransactionVerificationResponse.FromString, ) @@ -35,8 +35,8 @@ def add_TransactionVerificationServiceServicer_to_server(servicer, server): rpc_method_handlers = { 'VerifyTransaction': grpc.unary_unary_rpc_method_handler( servicer.VerifyTransaction, - request_deserializer=transaction__verification__pb2.TransactionRequest.FromString, - response_serializer=transaction__verification__pb2.TransactionResponse.SerializeToString, + request_deserializer=transaction__verification__pb2.TransactionVerificationRequest.FromString, + response_serializer=transaction__verification__pb2.TransactionVerificationResponse.SerializeToString, ), } generic_handler = grpc.method_handlers_generic_handler( @@ -60,7 +60,7 @@ def VerifyTransaction(request, timeout=None, metadata=None): return grpc.experimental.unary_unary(request, target, '/transaction_verification.TransactionVerificationService/VerifyTransaction', - transaction__verification__pb2.TransactionRequest.SerializeToString, - transaction__verification__pb2.TransactionResponse.FromString, + transaction__verification__pb2.TransactionVerificationRequest.SerializeToString, + transaction__verification__pb2.TransactionVerificationResponse.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) From c9fadc80f410c550f79b21997624269246f19df8 Mon Sep 17 00:00:00 2001 From: anupkumar Date: Mon, 2 Mar 2026 14:18:03 +0200 Subject: [PATCH 17/18] initial commit --- README.md | 12 +++++++++++ architecture_diagram.png | Bin 0 -> 138538 bytes fraud_detection/src/app.py | 30 ++++++++++++++++++++++++++-- orchestrator/src/app.py | 20 +++++++++---------- system_diagram.png | Bin 0 -> 239025 bytes transaction_verification/src/app.py | 22 +++++++++++++++++++- 6 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 architecture_diagram.png create mode 100644 system_diagram.png diff --git a/README.md b/README.md index f7f53570f..009c93749 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,18 @@ The code consists of multiple services. Each service is located in a separate fo There is also a `utils` folder that contains some helper code or specifications that are used by multiple services. Check the `utils` folder for more information. +### Architecture + +The following diagrams give a high-level view of the system and how the services interact. + +**System overview** + +![System diagram](../system_diagram.png) + +**Service architecture** + +![Service architecture diagram](../architecture_diagram.png) + ### Running the code with Docker Compose [recommended] To run the code, you need to clone this repository, make sure you have Docker and Docker Compose installed, and run the following command in the root folder of the repository: diff --git a/architecture_diagram.png b/architecture_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..2071d8908c5e0f672577a734431fedeccd67b7ef GIT binary patch literal 138538 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
    MZ+YuN-Q*EVQxYoSYCFeL>S0 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 10: + if request.item_count > 20: is_fraud = True message = "Too many items in order." + + # Treat any non-16-digit card number as invalid + elif len(card_digits) != 16: + is_fraud = True + message = "Invalid card number." + + elif request.card_number.startswith("0000"): + is_fraud = True + message = "Suspicious card number pattern." + elif request.card_number.endswith("0000"): is_fraud = True message = "Suspicious card number pattern." + elif "fraud" in request.user_name.lower(): is_fraud = True message = "Suspicious user name." @@ -49,6 +64,13 @@ def CheckFraud(self, request, context): return response +def extract_card_digits(card: str) -> str: + """ + Return only the digit characters from the given card number. + """ + return ''.join(c for c in str(card) if c.isdigit()) + + def serve(): server = grpc.server(futures.ThreadPoolExecutor()) fraud_detection_grpc.add_HelloServiceServicer_to_server(HelloService(), server) @@ -59,6 +81,10 @@ def serve(): print("Fraud detection server started. Listening on port 50051.") server.wait_for_termination() +def mask_fixed(card: str) -> str: + digits = ''.join(c for c in str(card) if c.isdigit()) + masked = '*' * 12 + digits[-4:].rjust(4, '*') + return ' '.join(masked[i:i+4] for i in range(0, 16, 4)) if __name__ == '__main__': serve() \ No newline at end of file diff --git a/orchestrator/src/app.py b/orchestrator/src/app.py index 64341eb19..5e1cae6cf 100644 --- a/orchestrator/src/app.py +++ b/orchestrator/src/app.py @@ -116,19 +116,15 @@ def checkout(): credit_card = user.get("creditCard", {}) card_number = credit_card.get("number") + masked_card_number = mask_fixed(card_number) expiration_date = credit_card.get("expirationDate") cvv = credit_card.get("cvv") + print( + "Received a request for checkout of user : {} for card number : {}".format( + user_name, masked_card_number + ) + ) - print("FULL REQUEST DATA:", request_data) - print("USER NAME:", user_name) - print("USER CONTACT:", user_contact) - print("USER COMMENT:", user_comment) - print("ITEMS:", items) - print("SHIPPING METHOD:", shipping_method) - print("TERMS ACCEPTED:", terms_accepted) - print("CARD NUMBER:", card_number) - print("EXPIRATION DATE:", expiration_date) - print("CVV:", cvv) # Keep these simple bad-request checks locally if not user_name: @@ -264,6 +260,10 @@ def suggestions_worker(): "suggestedBooks": suggested_books }, 200 +def mask_fixed(card: str) -> str: + digits = ''.join(c for c in str(card) if c.isdigit()) + masked = '*' * 12 + digits[-4:].rjust(4, '*') + return ' '.join(masked[i:i+4] for i in range(0, 16, 4)) if __name__ == '__main__': app.run(host='0.0.0.0') \ No newline at end of file diff --git a/system_diagram.png b/system_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..e7ba1b6c564c798b71c51af2daa4c56314fe7684 GIT binary patch literal 239025 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%0A&rArdDgY4=sHqlycKb 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�ZAp@{y5O~KU2aWZqySpG9 zAUNg-kN}lu5tysN$Mjz*wVzuG3d=(;0G3si@K`?Xx(Y!YMo4oN2DQ+J$!bY~00Ra- zuIP<&Ym@P*I^cXcKtKiR@qGJS0~(l74E@>Xfn|gRgYm>_e?E*3gnzIb-UVkQY*_5*R1Q+lLNIdx-zIM< zFF*CN-@95@SG~>P9&6p9R>k4k&qw9wN3`&|?0*jiI8A#H{%Pj$8T^&H}^-Nx=>;psubi9XkYSS_Cs{ zfvYpC4@BW}u#-p8DZYj0_J_iz_ErQzfH5Si)u}pS;MCz;ro%%PyZvgpp9Z2|D;R0P z;_??*I8~7ka08qqHv6j@|8U*$B3@+ww6Ner11nT*ZEc!PH1bO&{`E`i0ZIWVs9DeJ zR2(kK@^Aq;)ZS99cN*!ytF|?yre^~oN%;5|73AX7KfgHw*1*E|gQ?-4LF0}^!mDsb z&gk7X1d=U27y}MfFJKd3_5)=nR~Mx!%vb2VGyrdx%<$g;dG_qet*b)QQfi|9gbeUD z!0(Ydunbb5G&l_a6*j&E_LKu8F_3zi0U`s$@ELL${fi0kCWv34;pj@V3pYjDPd`k>n^8=L z*s{@bm$tngPy{Q0h65N%10Z)Enhp8`P;Fphk_lBoa0_U#kR71#%E3H>^c_f=4lD$_ zdSH#2_85!AM1UXgxe~+26flcs2qNs)biBm~H5+eJe!3mFSX@D`= z(L>*ToZFxViG%A6|3KaFbVHt^2@`ZFvhaPu0|r&E%5gL%1xD8?<<_Yes7xWA&H}d$ z%1pB|SmJZ@U*t9ti*-Sf*#m_i@Z90jsy@zdp$q`a%p<6aiQx2RWVG0{hv3dGM1B0& z5s1%-g;@uUAUWheBxCDR{(}L6>kfgPTf@j{X=spPG5?)>Q$gM;IXwn3BRvKoIb=2? zKoFzom3`qdfn4DW9NyqS-2&Q&52N7Xg7QcTMx8`KO;0BQKF+V;cL6Am8kX6725=Bg zp=fQ|e-d4ffcJw43{X3<@ohj`wela}!HdHMtx9eh-N|+hL>IV4T#&o}bigo9K$V7I zmI8`pCXHfmAQ|U2Hss-sA#DVmFC^AS@E`$0PX*w_{@3?MNNH;DR|SIWfinwnra@^C z9SX32$}eCPiy~4sJJ+DZLaYi1p$)G&Gcyz3J{v#mR!5}0;EvnwdqS>Q<7oNkfEK}f zEw>m&Z0^Y2Aa~zz0dyeuFrXstgK*EFn)~u4&&=9d2n_b?SA?eRp2$DX z5fu+{Rs+17$ku2;ml=)DjiUu?ku z`K{66f7W=QSNZd+npOXeme#+j{wH7Sk=@d@`qK9jaruHi{7(>sEdd|E0*A=2Ar&w5 z1H-F0UgN|Ht9(C0&j$Ab!okrKvPf`gfnfL2vNvwC&OdYo_bzok7{&etWxyygh(QAb z%JqYHMEyleUDp+*J`}YSB*pYAzMU^X;j${gUM@@mrl0UdcGt#Zpoa#XQdB67x8gB0 znm55?0Qnq%hNrj1Z|Ls=M-T|80r<&*%0VDG$P7l6=OC#BYyNwH> z*9isJ*52OLGs|B5KPnz0(AL5{_I3qoQ2c_W7(ygvk{X<}Sm5C#pu8lsgkbj%c>s`7 zG?B3Tp`ppGn-phdhOIcT&IH-q0mep@`@P#hHo(2Gn5Ybg0MrjD7%@A-ZWw3;kpctR zhyaNz-4KI93wAMI}hHn;S=)vOO3_J{f(4*aXW z=-AjckjnwuKbF8Vq;It;dEn?d6D9z^EbW99{*fxAJGI1U*g4n(PNr{~VbEnrCy zZ1~Xg*uw{~1%nn()ISs8BoGla6uz8lZcvuAy8iA6c1zwSMS1OZUCaVskK$aRtu_e zK&Tc5+ZK`#LA4&p3uaw8Fk=6PnBWuH)Mdn;2gQ^EW%iX zj&Fo>MkXe9FzFn6$;Tze-BCB`pn+@~92|sm2uuqV)jLR_0GS}dbtv7DsUJXxJ-i<> zlLQ#?AC^V%4Nx1-61P|w20lN!jQGu%7nzd(f11ZXpSgFj_|AmcJU zlbGizcnFa73(&s-(MA=-2%rsIU}OW9uXNU)s}R62u!~*;qp|T9RIuPsMyhp~i%Y@G zEW7+P#h;yvD;-LFu+qPRMI`y!RUnod{=RIFM0MzWp*hXAm!Sw0f)O}Sk<;td3qs2r zb3k{sX>4rlyXd7e9q%0|SY?+#)_Jl!%rykUXF#ql=RBrws}S z&<7VET+r9v-eT!<{xPt%1*We28R8);D=9AzFM*y^`oJx_dle+=yizmY~alG7O*hGQ=Kk#oIiEr5vf6*nkCI zkyIRc3jgC}Rxf;AS;-4-)~HZQZ$G)xT^%AuUC*{@Xz= zsp@O;dBRVXK^G_);G^Gy?l?x3)#on?iUzizLkNDLF2rPHWQ6X0>)!z%MjRPHgQAV{ zoZPI1la7quisNGPrn{rsD#^)Fy(C>9H{XJ;!3Om$#DWB ztHSWSWo2YwmeoV6iCB=G15I?#2Z|14?;qk~O!wg<-*pS(?j|;%7s3&zcn{!m2PZpw zLtg{Vlj{PyTd&g1GYOhnbPU%HL`s~u44`+C`}^w+5K1Q755|0iMLUQD07__Z&bER< zo7ZKV8Wy$EP*Yz46D|C)27n|lVyS5&Vmqi?5t9=PQ@|6r4xz^k=vXnbQ+VKT9X5aG z6flsA-$>nuLD@vdH$MI0on%2!{SqW#Z~(qdP3g{fi=Hs@@x?*LN38f`6}#!y2Rwxp zC5nJ&iQe#emZuWh`vlc{PMM-!Y|NPiWE%K3Z~v*yHH#2GFpTsNgPVnbzb!4cFf|X- zxSv$|Yy)Ou38L+t zYX=jb9>|@Se^Xi;SZ!Y1SDR$b^P7Yz!P@HLt^9J#BQ)NBV)q)i!f9G>ju5g zJvTK;I3*zLK}?HKI(boVoH7o=n?-axh^`Ul(kW7Y!JWOS`=b~C$mmL)H};>WOd{+a z`-#W8AF60kp?s*ap{;{s{CP+Mm(VE=!mMcbUt*p>upG?jhcV z>(|{TCe0D?sIJ$kgVYD6Z2L5m5ApF`O#w-EwCry*l05wVw1E17rh-k0`-iFw$y)F5 zw1qyjeUP2|vz2Mn4TVa;BceiiGArG*8V#wxnuQV~GU5R|(T1Y&@} zhoOfU0x5t|>Spxfizh%%X?v&VdE^5(P#Fq3QNBb#AV9$Q97Y?#z!reg&E0ivG9}-s zy<(Vo9a8ozc^;QiWSu4**K3D6{~1HuTP9XSYZ(!t42r4*WyK|pdUrm^VYASvW`fHV z8WD+Q|09rlA!AXX#h4C(djgd1Tt{Z4tqZd z`6*=^@DcPJX)n`Vot@d~Teim{JK{^$N4fq!o0!Ro&#%IR@shUM>dbM)ueaG@JJk5~4gc`}*$;!(Yq@^)) znVAcV${Txn?wd18=jJgLl@+y&b<9pD<>kSxX;7Jp!O+LkE$_u=y$tep)?r2-mXMs}e)7+2JV$C|cy=isu% z@5>JEy84SvVcB|5l(RJW>pAc7#4vPy;;L5&LsQlTFYP`QIW6|<*7BNZYDmgbpE~j( zeUe?YHaK@#NqOLq*`k~3AR#ocAxHnZ=czt^-X|WG_j8t$TLN0;r-A!l2U>TG&fT7k z^d22%>-CqIw?4sWJjhmIxO6f-GqyL5oH*F6L=Z4)36~j|&`p@eG570vtDBHOU$yBs z%F)LnRGg8+_m6)**LxT^BI-YZzxQ8H41ww(9;8Dd;bWT%l?(jM&MXQc(=AOQmv2;1 z_khgev(xbYVVQYHg_b8WF3Jc31q_hs`-PfB!S)`wml+zn8xZ(h1F8`VK^-24qhoaN+;Le`_kU# zQG9@KnDkHwA4aU#+KF5^6YE>AX)F8XJqkh=-3-m>K)!XYDwe1((Tv}Vvo|<5&S&iW zg$dDZ&cc#5hi-d?gnRL=dZ_l}5Ur!7-a>716Mg-jk=v*DPPUk!r}ze=;B=oRzJ)Du zop4Ah9aadeORZ#*tk!~d@%=!tt=@LYR3=q4T};`&Vmj_l~r=p4YApX*ym zBw3MSSR_?g(e|5c(njU<#c~W0-`-q)_|1T4(>mzp`OMt%*3=VTl`oHXLOme3yH~yB zvMSRuT*yTZg{pfAeXFO);Y-RdcgV7&oE19KFIwA^H;u-Qkc3G}OPf6ZYJ&V-@x2wS z`|NMh(xTiKoLICzzB#S76PUp%ipifhA0OROV}qNEL&}#}u=aDBs8i&;*zZUh#U5`m zA7>Xv%Gx&WT)Mr|`}K9Nt%tDZ&GVpY+3Ch|cjk$eQvLlCd|&jAEmoawuUgQsLaG&U zZl}w@XK}SNe&>h7cCIB$3cem3&4ppX!7{>eY@fEtLW-EQB9FVL7op%>L~AF`uMADk zt)77!l8=0R;N0+JiqwENEb|mcc)7}X)4h5h`)B0MlB4OZNMF19bL;-xt1kB|YJ=+{ z4ABywjCo_2n}5IW=Cc9|jKQQY+tkV=ezeq{Xv;vJqq%C{w2TIi9tWpgKK)kD>+sqk zw-G~5k+s-uSJz$ba*J{CXes>7-K@lw*h^8iwrMqb(w^t1PC!%~4Yo2OstAM}vmd?E zd$0Rvy-uM0BlR0w+YEt8jJgECY*7*d)&p(cC%|p%zRxjfmioh3nQ*5m3)$y?>*X>n z*xsZN>-)Tw+Y_TK@!Ze|84n1lO^v_bu(_$})z7a0Bet_1S1) zcYncyRQX`hqsC=fYjDmD!j&82WQheQ!`2f9 zL&pkVYE)ca5X=uebSWc?VbM#s8F$Ja&7#s{*8SG4b<<_cu{%Pewy&IsO8A#Kue<}c z+RwhNx3wXyrRHwVP-Wfm>&VH zW&g$`OYY61iwSZjl^)|g(^W2vZ!XqNyXwyoc~}r`)DFEVEwwLSJDJ?99KY!V&!Wez zZramgF_TnTS3XR5$%|C*W5HCn4*$bci{%K!1m`l9!A8nw>y21($|5-RWJx85q{6HN z0P|}}%W}_mjzcsd+N)z_K~MmY3JBB?ItIgb$U;zG93T98I=xQ%!m$v@y=;YiEV~Cd zt?hlG@U!gD`v8>*89=u%GNwLIE}nX6vOv%8!|uir0i?T!Su3)wj@?Ig=iww_rjxbo z@2>BHli3$Oy>YKz&xyvIslqVO#pWNmt-cn%se^N|Th#gruJ+H*z5e`eiOP!SJs+RS zN*gZ!-iX^eqBC=IQ~dJc=As;C*8t6u+rg=2tjiMIx*Ep~suxGvUEMpw&vF${HCJ!w zJX#Hy-2FWjke*YYnzFQFze4!6XZoy5@$b&C>#Zv`WISXC3;XWcD4QUVZ}U67d;{W# zp)V>gT9#6?(zm(>*p-x&j|>_ZGCa8Npm3ON3M*1QNwKBtqK*2{7?P!fQRPDeVh)9g(&5q;cjI|?VAtH0)*k(#_!%EKm#QH$aEH|DD zgadY4D1uu{EZQ*GRH(HJ)KSW2XlEfVyMY#LEY1xpJ>IVCm#5O#v^MVAoy~HFJZj$V z2`1%=&7wkWqJLPwvMR&GgRI886nmal;dQtB-50@xW+ZK!>Ri2-DQKCN9X%fDMdVk(+oREf| zJ^-#3sPMZ@$g$rGZ;AR-w#SO7;duk&qFwb$ZTa471j9)|7A*tZl(Ui=^9A1<#sLDo z=3iru?^`#$=0o!M1_g$4I))JuXYMVKkRby=J&&*XP_wXvLQ`*ME{Nei?NU`e*Klir ze-h>6=kKA_UhNRLI-c1_BbFi`Ou3je{n{(&E@?GRiosPAoQ)|N*fQ~AS~#Stib&(u zo{+~>j&!^fFB|)-dy9+4xkvkct-_0~NnV|OjE>zET8Wh+kijP6$XE>U2AzS`@tmp* zwpR0eQ&xsQm+9%FmG>h)Ft}%ceSJ7Map`1NuzoWQn)Y;Pf!XAGZ*?)Nr&f}t9E z{GfoOL*>Rk-DO@74R!_Z*@-_YEaYgOm|fOeCAfx^;0SV00)Z3|zPds~i>cbUm0@eP zv~#W4IH7ZLZ&lCJoAD1TE=1tRPrZ|v6LGKYXWtgf9GDSt7o^DU`8?EW5CJiI zV^(4)=a~}kO=s6i152ak(CIVhSwj}RkR^i&d|@)~*HAmce%2QF+I$2bZSz!#pv%BH z-#8Dtt)VeWBH;Nu&K3|V@B)*&O@Fd3?dW4I_v)>%o$y*1b1?QO!wPe?H2qP;b2Gqc zw9u8Th}Ll~y0h!49Ve%~OKd_+%vKvC5TbA+WA{g&hHi{Y`D`0$lzG}EhT5E0p$*Sx zOoTIk4}oaTv|;)QmF>jYLEjBQ@&VR8pm8*|9hbPhEyh}Wna80Y!jdIE7og%~MZLSa zY&!R0cu8%!XzkcoE0>8`14YrrraU|`k^8-60AStlRP_3YAt`c+KYADfE1S+4} z7VMSzL${A=@H{BF_eDX*c$-DHwhaISmlBVGOUo1%!5cckryf=|`W72Y%_YjetC%{H z7%@Z(^viy2S~bY4x*+AxEW79Fo*GQEg;8t`n4?}mJ^(HbA@KG6p&Y?28|aO~au-iG zQMZIY9*S}hWEkGgREXaEY%@+4Xf#qi=LEeX{@R9MU5wajIwO~U1M{f{Dv_nbfT!TUIeOyuv668(Yh8&(z7-nU#nfBq9i&7WKN2{Ih~Tqb zz4BN>wqu764#6F^O4cMv(`% z+|^u}!=zR6=HOV+<4qN9`0&77-B31mOhL<1&4O%pL@4!QQC??IIjn0ZS+!j5OYgo* zu1q4Vg_nNdCH|&=W692L#gQ^eCN|_rUAa1+Io--)XO5+7;Y%0)WDg}>p>@HHiMrM- z8%~=ot2eTIyyEW1r=NIZkR{jk-$6-=Jika%NFxywN#ql?JuO^;_gi_9|G3 zWJ8!jk9VuowZEwL3{c9>j-DP`HV~4KEo~1u>sn5}`^^%qfwI6UdzeT~J+%ODB%?>S zX{Fv_XE3OUjmvW4wUCHN_5C__f0SqB9&yEXZ<4-?tNUob9CFBkqXJaNudHkjQ!cg! zG)}KCZP1?NLOqjd0b^7@)p(yhz6?bl6X`gYNh9s!H(rEnW0l6jRF^V$nj4=*Ik9~6 zr#R&$wxekEG?qJ#b(3s=XgZDQ=B73EasUg3BhR`zrS}r&Yr_kEH>Pf2-VDGgNx$Z9@ChYT30YMlE0E@IH6c?;Mf?p*5$%&kNj0A`j8GI7K@e zws&kem+7yOY&^p-6qM%W-$X*!DT&+x3u&UupYUVblfFDz$EjB^`t?M^g*8G;L-YOq z->gRI+I6ncpf}vq?Ue)2S$NBa6>Sofa(Gri$B=ulQx#CN4KpX4RPct!zizQAy)b=? zEnfJ%;SRo=TJU{5O#1tV0evr5&kBS3=x#sUC(ycMPTi6?QfO|`#L}n!ce8IGzCt)< z;Rbms<*Z>vc6fbpksR3imw*ueSE@GikB;X!bmV0p&BAo6PRR z)<)gFYrD(gMR*~4`=s4@0#2icD`Buv@`F~zMv+wsIiu%z*LRsS3N>c4QX@HXwR!Gq zW4kYg2sL{CvB@0oujM$>x%9xGUyaIF6u{DaR-jnO!Cf(IdrzUR75j5-RKDP}zxtK= z@>C>8`f5OEfd0lKFPMwG++Rd$mk}&meP{~*sh>uAlX9EJ(+x+lvkK#S`DsVIIHN|X zJvPOGs14KF*Ud+D5vNpRUL#_jnneV!-*R8g(rb;Y5($HBrrN8$)kKw*ZOdV6-%XUY2|Ely1&aHNGb$J6D_jFrWqT->oxL@9-$nuNb02in zH8j(l&!ox~ZAm|A=GI*gb1N9$F&!Em7hdM}FFDs%8vLT3S#~MH=00oSB({;Sukux$FyY3knwMKfUbBy{Oi^ zuHSl`q*1nbOZD_@Nnre;wNjYdn47Y6y-8S<`kKuVtLG zSjBW53Dd{Sr{DD)8ONWSv$`A*gtmSZQ8e8<`!oD5$@b1d?KyYX!wie9@dD1p5U=%? zj{dhlm_L25FfsAeL7P->k8xS5e-d!o7-%cQBpHHUR#9TMljxQPQC5ySP$RwRQlx=i0E1RzTe*5H{Oma!3=xu6>C%b-!dq$ULBi07H zVCC=L#<;sjmZ#+pJ3Ypold5vZS6j*JF>hjTXXfQ#S|!xawB)^iF;2fc9-u2$|6)A< zGS=$Av%c4VtBn%n1y$tf*7)RmNEE_Fs6T1cF>w!I|1x?jj7%ieNeaJJiH1()`$quy zm&=ks%;rSO>mGmVchIS7AdrVNEIf5U_pcHpHO94WcV-e3%mY#}(-JztIp zFKP~Ii*fI_#I39L=t%vE8bvQ*G*Ttn%qYE|oeN83dq?G!w7A(b&AWlZmd4z1>d|ZG zt{$VxQ=eYis}*+GKM|)McOqArK;HecoLTRxIHK#flAaEa?8^3kXdhQhPW!%u1vHt(G*zBDsFPq(|56>y`eD*k^ml#dw96t=3{k;> zvoX(Bj`U~!({_@CP4RGO0$0jHBKF%}=EgY)708numpZt%KE8JC8q-IvaBQ#jv`S^F zi5jfu$F=EKbZWA*bni%N)f4*#GZquJ(=#;@Lw6+}aEB&Kn{Q`hRu*I{R2Krr33_&m zr`_iv0)Hg!UDVZ6d2q(}!SU(X`fPMg@ZQJnt$~Yz zo>$*S5BysTa7V)6N8Gs6x?*17-3FcwTvF1=RYDOes>fz3@-<`ySEpx30!j|gI4(OU zEaj_J$ZH(0ToYb-UmtLEr`eK7pqAXw?_h3Zt0ec(@@~?>?&sIhG&MY|soTU$1!B>7 z<-^a&rP3;Tc1QJ0(e<+Jo)91d;F+0z;}4vbT_XX;X4-|iz?0O3<*Kgy{>O;=1iB(2 zSg3~A9IiSVr$LCyn{G*^l|ORZ;5Soot4J8=pwD#_k+II8uQBkcdbJ=?y^k-NmK$%F z{eth2_&TBOQQ;VczXj7D`$EhJe&@I$rUwLRsos$k8G5&|QZuP{9}`2*l`cVljAC`8?l;v+6{fsggL6HGylp>k*6f0cp(BA&-&UI{~lo zJSaGL9*A?8Gt580`d~^J=XKnJxiGFeS;>h956+nrW8QBbV;-Fp zA|`9wd+qUch1Iem)Pr8%q%-^7Cx4ei)-8EfLm2m`?Y`YQxR+Ovj=N7MMq5DF0<`kRO#elV{3b*Rj;A_bN zyszBi(wiJ_$H<~1dCJntQ_!naQ|`VqrqRwVHAW>=l;K$WqF}`Zxg-IWr~5iJVejNW zW8ac-v{Qr|6M%tVnqi)~4>iOa#!Sb)Jmu>Wp-B?%_lL*(KbW>s%whP41S~zv^`t*9 z4n%_HIY=@81_HKN(8gs}$4 zceya6zn_z$m&UXktKv54>*sy!&{?ok6|SbAs(cJay09F!?6FuG4iSo*IF-}c=nRX zdt{3+(ui?`?r0Pi-hp=FacW-{X^)#>MjxB&OY#S@T5TJ|6+5d(m{yZjt+Pg`IZngd z7s|yk3=J)tZKq|$>Vsz+)Bke4B`18NKlWokYM2nI#+G{YW=++vP_@bvfYHa7d1biTLJ;GD!4FKCyz>2KmJuh*3R)!dae zZH{a2Nv`w{x#RPrfmZO$yw=LJ=CwH{hcJ25V>4C<9s0e$&g3I%9YtUAn^KV`vzTOJ zpV6F?m;Iz3J(Ia6G7H}`aN{8e^RU~u)v^Pq$Da3v#*;!nSb2`0FM65+3g8w%v z`R?J;G$WiH+*dOk&}Gm=;r|(Z+$EDb^Ql1CB>unxzTP4{yF}fR2qDRAdt#lnWX2x{ zkh>T|D+>0!;C=d*Ed?1FrtXRA5|?o@ z(RH6Y_@v!i$``wIE8h}y->1&op|H&M((0(BbPJDf6ukg*|0hshN#OqYLfYZBw7}<` z;)6NEX~!;f-PJ%Xmk#pzQjOx}H^VNT!v*nveoHTmnbqZN#wne#4g+(BtsgKhT`#yT z=yh9ifP1pA)ctfNuSP3KC9Gz3IK+LVR9N)`!A9+YWQ{7;`Tq6&(}mtAkxUGEs39OfCgZWYTJ^ zznBEynmvo(9N)w=k{V^q_lx3n2g;ZCgmJpKH0JzN- zbEL9NskCP^T`$j1aY2*ayLXRm$6E+fC%u0y-Al*;8e6 zc+YO9G2unxP)YH5vA-`k4x{)rCTkHykYe52v%4}xq~Pem?a@!CTk9+t`9mkNXSz(> zaC?cT&-}l=V?OwJqu;#P9C~_p$+_Q*Qyj4K3@B8m39XGkGHRSFNaPI6HV1yMcd&a9OcY<5RGNNfNk512>Wl6@PRzTL#P!#qc{X+-(CGMY&2u9N z5MB0u<4=1W=zJhIhxx>aKbq8h@x>AN4Jb<{Zh469wUF|<9o|}93#1=2`S#;9SGy*G zRKW3tjXnP?%sr~<37K4;s=7?&w=3tm7F6J;uW!}TPp&r|Qss88SfB9l6XTeNZ+#WBqD)uQ;`e?o7I*`XQKfDy+eyhITD;zSh=k5CN6$$n4vPDVhtaRQ)AU~PTkVB6YT1m=*l$7+_`@SjYmky4LjMNCpgk42vM7br` z;t6OxbR_kpto7st3zk?Z`JCskfSh`Fxi5hHLFm)!arT^J1FIO)vjj}=Ji>Y$=d%sQ zkAuC{U}~&}nizkjbPS$lcqNy>77H04_CHN`FtmB%kdp zI2xOqW7C1G6JkAEfORC<6N?pCC2i9kTJN7#y@e>KU5R()^}((&?xG|? z@BZw#WQj%%{gL<)g!zB9vH0?M%mVEgu!t&?M_^t&W z)m~LsU7}>wNf>yZL|^iO?VB6ct^DJXSBqkvS}5k_(=A~;jf&AQ5qH8n_vhuI5S-wz zs~=xpo6Gni%t$Do4vi?;sT*~fVlzf);22Zhp%Noc>QZhgYr4v?Au6f4fr^%QeyP*t z+%ncwW^}ef&qPLQMTvZQdF4WHcd3=L`?N|^j6`DdR@mM zM{>QO>q*r2>tRHEp7)(ZMUPG*xm_)(25BviScueKkaN&8ZP$W~RNv6>F_>Tnam4+p zhu>P$Xx%(oLqU6EPe|#Fiy`Q~>z(!MC4Z%df1JeQ9Iobjaw4Bu znfIS9r1M&WZMD<-Yo972OC6o8Rh7^WEZEB@*~A2k#`gA3&Bq zKp@Q}kC}rox^Bf>SX}y9uKNp9;##!*`i|Febo(?mFwG_)a@gD^5d{V>?x2O5;@7Y+ zy<~Q`eRB-i@rO87J=dE2)Ra_>VgqL72UwXBWgU17FS}*P<)!c{h8SCde=K}j_%$$m zcPLvUx{u7Gkmb2J@&!3}iH%v+FaA1kdD^?AeIprl%^~4tt>e4;Q$jaqf&v^E&-lEdS#kOD4iZI;Frrhnx zbqi)mZFwFppR?*#b*LANl8BIgouk#KHWsS!SRxzx!b@YR)>HJN*fuwhdDqEH3}B|FLA86uN)h zffW8&UmyEm{??;@a|sFG!7N>kf_nqXG4y?)D{>@(u{9COUry+J4D%%m2OhuaXdLTnQ-I zX)V8VFn4@<`~gRy@1yGxJjZu;PF z{?x4ulXD)llI8*(y+DcZt>vS5WUe5kTZE*3c;?z@i66-S6+ZucvF!0}%D8opC;cW* zdk)hp)7|6+>x{oRo`lulyx7c={6Z>1i+259Ars3Xk5tbkMdg%CCmO}W`MUCnZ(F{8 zeQg}_dlpXfImvh+Bmub2Vl=c*9%f{$PBeEqZtKwZ%vj<$!qD_O zE}Ymn!VRTWmX;*AzUR*VN9EeE{zc z9}lkybkC-f)n#MJHz+t1YkE%a{mypdI;?$=?i%-tFLo4D71vh&{7I~MPhXn8#R-`Flp$b?%J|O6&pzz{C|pg#Sbl(T4`*c zzeS$Wd?y`?Hb%<9&#t2)nPr!w{PDmyWp~4pywla?9CNieLwxn$xpGXIu#7vB{yYkL zDwl+gx%jQ_0vlI%@A>iG^V(h#xkNsB=O)hDOx9VYpIn01+|!4Pr1(Z|zdGY!rPRCB zF(#wtP9KeFTH%w=!Py@JuVi;)@9MPN$L^|~80ZZe+P0LTYIvjTkRFs@AElVtql;iN zVuEfx$%eFX+y{id*uQVmoeQQ(3@?e@2(M@>bMAoW_~J=~viiIR*u-GtBnPq!d`-a{ zmuPe8V{SrhM>l+gzRE|;ADHxldJmJ${HTiCUWQp$+Aw-w%i}k+%9x4V&wDw2j4G9M zFjHMPY5u$Zw}|g&bDkm)Fw_eP3>2uDT&NZFQz(5!;cm>5vGlk6Y9M~P&dQ=YkJ)p0 zh87l0$I&~Rkj8SacG6pET?xCWXR~+QEkm!@?lM`4|JH6u3a?c1C?I83vqE^z&p_vE zL~^2XCE@Y=-{dMUGJ0cQY|v6ue^2hb(AY?orP_QGg^g0kh^o_V-MY7lueVR^V_D@} z3$WI9dqUtp4>2c)xu1bE)noZTOYeu7Yfo4zYs$XoS#p15j!Rv8SY z1y`@p0R78u59*S_>$7q!y>Y8PX$NH{X$LLIzF8s$qgn} zfQ675)(|`sh|-2x5GGjn*j~e8IamUyEi`k;_H`JdT-eOE|$K{Q}En zto3BRkbR`R+)s1n*H51uIrdxRU%6_iR!cYSzQ;#(?EscT;(`b1|Djrb4Wue7xj=KQ zRQ=*6V98C^y%c7AYBN9ghfG_B`s-++fWJ$6_uJIFGw?(Wq#Ft>$`E}j{i=7afA`3= zS@QzM7~W^dSBqzCETfG~@PiECmxhNck_dUiiY&F=vtlZ;%dTuMqIl3}+nE5E0fc7w zYIVSxd(&l6R|QbQg1u|h^nfHU+no<;p;;pg|INUeh^wwJQ6D~aEc?F{bARd8y9bW{CFFsrD^hH%mvRr&SmyK61$kfxo)jOj zCQSq=17aAOl(-`wl<#?$7#(OcWw)t=^2yXMpf%3$5DC2X>4!YSW7F~Uq3cRHF@g9b z8i$?M(9ThQb5T())?e{d&7bT6%@s$TMcr&$AXHg(!*qEwr%}Ie3Zi+brnHx{qSs+q~l?IHxr|AV)FCb*z0=B z6)!CbVjnD1i6xeT;~Crvu=P86EV)(d7;l6*xA;gux`4FQ z0BmcN*b~TGC%)LSU`5)1vQH6STPzT0b{_0i5<08&rRmHHGk@gz`Fm7oRsEbZ=f_FI zm+5mESFiT?jXvM&DcHB>`)`Us-?3#=@usPnM(=_#P=@aP`S`<^_h-;MSjMc{k1S() ze*vABtacj5V<||M7+H1Fg7I6bmy!8yMi&wuyEe(by~{acisuWT{$V{J0PoRi^`L|o z>TSOhcRpYRI78^QPWBl?WhGA;q7#p=s+YS`mBowv^{dN@8_n{(YU2TP2GP5os{467 zdD?=}<@qemyBpzyWcZA{48oqSy&_!I$KC%6E22BioKaAE{I}WOC4~xAuD8}x?YmEs zecG_krfOK^Hh?wEWcU2hcdE}vKJXxetvdZ`m*mW>LYy_(v~((wH)M2O|Ku4|F@JhgCKbqpHz0h*FkAg!t}&?SZA|a0FWYunwIO51>oybO8q~ay>(oc z?Y1?FqJoNmk|OZ}(kLMa@(@Z&DKG#rwY2g_j-)7^5s2l>E*pk<%4Nu6wb4*?;B z)j^~J)I678+27-RnorCXf^!7lRZ32nTozDja4Piy?*i- zT$;cvd3YSM7G_EyMEW;5M!L+r-ACEIGm^*LM|E+p#&io<5)s5G`Zr=6h6pN2(^#x|3M#V4BnJ3O@8aBdxJ@^a(4 zB5Jg2s&<JQxC?Io+TTiZcr!Eq=wQ)qKXW3PzwoX0|wlq1E z_%E(mwCJM@3E2I?+2>-+5R{31uTlAozPj%gaOR znlCSMq8$I;D|~(ZUB!7g^Y|AU4uz+#!;mydKLlY@)vMQNr-!VdKP>pey;XdJ;y=-v z5R4K$_cVJ7+)t`3P@S>Wll?J{%<6k6{s)A*4&Tl5?#U6~F=hgGn+i%ZqWhP-9pB7L zU8Lt@nXp!2%dwf>47MGqmrBqa{2J@GAJJN*hGBO`74&Q2O!vo|Y^=s?HqIp1Y?cGS z7acLxb-!{jp&=2ubp6KS@}1k(%d3}@J5?m=@)t;XY=R7}T#=7?xApL;^efZgpnq}3 z5tb)AJ$>d<(%akBE_}or4?KhQJMhRiu{M@`OYrS(0G^`>4OTYYx2e24oV&mR^iz1e zm2`Uoo#x=6PF!PxaLcgudgHUsW+Tr)L(7rFMB41=l&T(i7P;^ZS;hWc;m(>i^_&l% z9qm^vOhE?&(kOUmr47gH7_-YbDCzkH%TWzXGsw@p;^hjo5b6Jn&^X`^JC6u2E%%D| zftqy)1Nx7`JGS(?ai!H){P*lC<%~Wm#sDw)Tl`qD!2DFR=lK5zd`)gRd4W1 zBqbpYh?=oX5s%Je>9QkHQRlJK2QqQxKiVk5ZxRuSZLpx&OkQ^;?my@$ep}c+0%byd z_^GI-N){zc!nYD9%M>GLRHjStfy=)kZ%>PVKh`T$lh_4GfR-uklmq)%+vMntk*q78 z&yr2tnHf;o$5zt)*n;_GPVoYUc$7VgEj9iPH;i(14qrJn;JiRZ@6!Sv1Cb&hV=lp7 zY#Nnd3%M3{?dY9{|6>!pR}8|@l>`?Xhr^W0c{*1K2?^61wsr?9 z-&iu&e4*r1_#||a@+70(3JO{Hl>^Ob%&j@c)6WBqY8YC7Lr%1( z!wVv_k|%ql&}k)r5hLk;1DOrkLjDXD9aA(F76?fDrEs0m@ee!82yJepZSUH|3CFEiJgI81v~umWt` z%LLl zD{Wg~$9^$?m-XbwyJuLp01TMQCnxu9$$Dp#Zt`%eP?J+00nlW)1H0M*fCcePlL4TJR8PY}4v+Feej%0GAg<%;~Ie`z=7 zfq7%sH)Zs!*s)rqJ8jfX@%`vjR%G|#-mx+%ujL0Jm#XOf36F?|5bzfdHVq!%7SE6l ziDcE~m)E9J2tuDYu~)#iOtJ#`b zAWM3b>B{(tzLtM_TbW(J-*dFy@>GrK&;<>F;efq#97wWOvp{G8TCtY1cJGGcy;PrO z)#uA7s{1a`4jHNjjx;6aG~pq0;&8+trgB4vnJ(}N{|0{y1Vtw*y1nOkf-JpzdZS^BZe1bCU{&9 z7Oy_z|+#Bi2~3L1?c5gZ_w+$Y9AD+P$d$`l6>#3WX$!|AozIcB7odM-t82 zlgBE&{H8%2MgfJ71_$ubFkSbesoeASw6-j}tf@3ayN~kuf2@dQ;hjT6?XD@;+VS(% zVOKYefiv&(*uo7d`aU3<^UkxOKtn+5&^FOa<>Zq($xxrUar?FZKA?mQCFT4*lob5U z>ROe(=a(-pm;16}S9hVqR=U$4lW5MLg`G_&DYU+0Ao<2hVwp5-#T}Bx=GIjDHVzV(k(^LSTwfyRm3CZ2m#kvvNF`~HU5$-f zZ8ex)i@daR>zG+izvFxqaBFEz`=~1giN^2GtW}dk_)NjK>q%>e)26aYBv+c)_3$eO zQqtB987o%t8OSb_bzVFkOG-3Jn!qu#+vB~(#3Wf*i}n=`==nUmITZtpW5yFH|_^wi^i2X z9b1JfMjO_f{rj$f_;HpCP2BYu)5MumzrD-?9h)H>a{dcHs)Xn7&qqgsruEe1Gr4__ zjrV`c3;eL1xla{a`3yx01y{~0cUBV?ZL$Y()S|lijPqw;^;dw^#{jsy+~2Nl{~2V# zkmuPbb5={?;+jV0k1MD%=-Wh3+o>l0{^I4uo+RJlsk;m>(((25^e&xbpt$r!UszfS zYa6w6ID5*E0Y%SU=KSCTwiyNcFMTX@4@V2s-9xwCw0xrRLxf+KuaxAb`F9oBVGIXJ zgQ)1;#N72aLp?OjaT9I;@aY^+XCt;1dIGawFf{gH!=O*lYQ@ao!$w$f0YMMDX>$FL zM!;A@FNZ*!^??_}A8i=$@gcY;2<g??A+?_jJFSsO*1AvjxoaziRwc0H^3piU| z?v&Vjo^k&M78Ww<38e2_q;z&bCP@S)on>cX{mRd4bjW zF@ArA&Rs)P1n=!B_y;eAPg67Pg7#3!!KLIjl?djP0_g5=3|XrN-Y&ag(~#+#N4J+3 z2}PUgJvdAU!gRktwIeY)XhOWR?$Hdh~c`p4)Dk7~daPKtW&ARz-n*TA&T zO`tiihksb)vl~T?gj(iMPoC%k#VeIdD*x-`BwGWg;ka!IUWuC+Z!KUK7)q?w{-NYh zA42jejp5YMxdy>v>nAj^9wMxkC%rnpB1!v@H?F?hD9a>%iP}66A4KU!8ggLW=?#W% z@leqUTBnAv<s=fkd% z9N*g`Z;X`O!k2=gQ7WR)?cMe8U4Ocyv+o&Z`9f;s|Gv(pT`PYU>U95YVPMdHXuoIH zM%GSmVbF%BFbc+tq0zmQcJ%i6c;_-qvgP;v6a!U*+F!qdCEs&>IdA2GXe8+Mwz*@* zXH*p0L0LAS(;F+`Dg!EEeb_WF(63-23Wib|IV9)u3)UNd!N|On!dtB1g{;XqU!~i8 z4jcrG3eQl9w$Sh2TC^Z`jjQ_VID@sdMfwv5PizwActl$I8iT*wkR<^++JOuU!HQ9L%Pg2KEu@FSD92y*2LJ+e zd(Ryn^jcjLY2|zkjXxM|cFr?ZB^gM1*-fQdW_ho^7uT>dd*#4fa>HKlvYK^5;%zzlSdFUVJlrjtp;_P~9^@bty-hULU4x#NS}85`qjp zCFT2=<8!@TkC@p999mnm%?fF9B5OHvx-i#R?Q%-|$nvi1!D;=%`q2K>Tk-zY`{~E2 zg~N@V?TKdF9!UZ+E-Z~OsH|B(yruxQKqE4k=!km>BBcvjPHYBkSVwPdQ!FZ%jXY`G za5tI^Vebeddk199?n{KwKLL%yK5UVjAVKGWbz3k=BJ^dh*5!}9`dvl3Li{#X@dlcA z3TyEMF(-FLM$+E3eplaU{4}zks+3I*@iWDsd-a@J5q2qPZ9g(TAC>%+E)!z=7WNqL z3=qpL11I!-``NK$LXR5dHrS}*LkeQb63_C9pr7@P;LgYOLY9<39QV_yLR>x{Iz}eFcM#cW2Lp z?qiJ2&X!8Tw6y=nkLb|5O9CMcWm405hr=xzI0!a*n2)I^yY=-c@g-~4^#0c zCd>DR>}!w%80ay;XyInn6vhH?o82NG?#mu`Wo7$`A5aynpzqarknjPPH#NYT;J zftLk`Lug`RbrUy!{>u3mZHMsMGhysdl?H;Pn|JU6-d`Y&B8G)6bxmIhZpZ~>CqWBR zuF}D}3hZPGYnwSh#sE2x4VtGQHPeSJHp|*+WbOKp`*>jvnxZ1OTr< z1}-E4D|?0`vJzXa{bw+ z(L$qg5RybR(otA}LYHGIo(ktYFH*-9sSvpLs^IC~Ify`m)0-z~@`I_n5a`^3z=mWb zb5U+?&G?90A85wy1wl=U|>S19` z6?ewD@bSmz$=@y%f>;s%4ZMgSnxFgL7}?X-(P@K&Yz9MlNyD1nq_d!fjA*&TRs_Lv zVo1qgo7BcO@U$!>t^YQj^pnC`Tq-e3WEj(T)xzr2KQ{dlufvWPxa_imZQXKzW`+$M z^AB8sw)XbHrZ$+&fJ>ZABuACw{(W#@g;)j@QrN1$7CdiIW$eS|lLpz<*GoMbCAJ&< z1g+u8_6e_gzbgh#7r9%uqd^x$co`-pOD%V48#_;0YZCOmoNm{PfpKyGIbTjuks^vW z5FO4iftf=qs1L)JC4=B35@*4}BkfNd7w!@B8r21LWH1VT27wqRa|FFqo1t~DqM`!V z5bQkAP+xBWZOTON>AxKtFt1-nSD*M~Vs0MC@q87Oyuqv^x1c~_MIk5+!Ye$NS+ER3 zgk9>HxGua-W=r}ieL-qlKR{#KJ%_cT)AwN7$TQw&@r%+d7h4d8k#I8DL$^pS+*2IncpB}YN3H5rsxH|Aan z(r=zLbDn)cy>}pUsY@GwTv+=Ykz7S|OX0%auJnI;Xgb`a2GC^xJ_z}N^5!I1jR3n2 z#zjtGp9pU^6?xx_B1jI+)$b%H;V^g%B^gXHLWaNwze{8RfOT5pfLx2x30QzF95~er z>Rf3RoO^RVVSf!jEzyQPo#EM6vCxXo7uFhPpv=)M(>R<;fL}$E>rhfnS6~40 zqnC$(GEZ1N7FR~+_3L-#j}0p!xK1?I$3xJD~-uxCy# z(?5?#rpf|mF2%YEyU0^ZC_NLvDTQj0)Es2x;K+Ixh&vz?cOwo?3zsfnRE5KPpj&J~ zwu94r+iiG)q7aJYV3(kL@Q6y7UKONbU3711fb5OD!scf0QmX}au!9AiXekg+?ZcMF z4EzW|3{eI~mMRmQGH#J7EgUy+2dsSArOheVYnqU^2)ng9LpisBwT?Z2}+*EDC;72&8}3 z9y1*bT!^8pm+>L5CWFy|ktdaKkz!s;3cgKhiVd-#4hmU@74{FnDj5AtW%Rzqx0hQ4 zzHOG9i_9IXZg%s74My)USzWIdJQqdfF+uZra>ZHXAuP91Y7lfu-04BE_~ zhRh5`E}HN;Ao`9J`{`t1xKwvQpHv^5?p6nLp*^Ti&x&1HmVEXoQb+JqvDn zV->v0R9yS3t{hz6a|;WTVBG*OZ8`=Wbi~zYX-OPxM0&Bs;DwQg!aA9pe7!zaj)WHv z4-b46b=56`>msqEC`n3G#E&*a59$OoT#*a_Z)kfiTtiFe?tUF+AQ7M4Z#1x@MkH22 zZybiGznP8{eTj(plZ#SyBUK5!Nsa%jFRhOxBg{b0C1j~8LojECJC|XnjJAj7D&qDH zIe=NE$PXN8Jg~_aWxrev^h6G8!_kE|urht{83e&FzyOpm8X6k@B#ZQ5So+i=Vq#W{ zU6ef5%Xe*+;ao>km|UyU$<~}Cc!LD5(_>$~I)&^vDyoa0kq}q}XyG|nNX&P{w1TwV z5};^!9C9dTN@2pXf5ZepYT(Wmc>(=O7Z{j`FWhy*HAm<%YOq%Fg3}D(4f1!S?eYav z7PxM(Ug-I*oS!&=M^r2sP2V4y&28~hdEMrgAQuXSqLq#H%g$y2h&%(R%xSxwYfIY~ zw-mMr;wFJ;0D<1;^z3XMm|O($)q~pBv;cyX5vC;MC-ZT<;?%;H@K|=1`+RZ0feplzZ-OBdAfEBkC=JZOe6T`86m`!|wq=ob zjbvS3d-l23RxPBkA&kH$eAEHrmZi?e4?#u>C~IWUw{_?bipbQl<*A480L#vHi$K8X z0OkOF!KVfCp|~wRU@-Y26J=#JzB}G_ZzC>>Fs6}-#wvhuyBrx{y_glM4T)!XqXjVeC*k=@dAx2!==fZ4j(6A#-XQ8KpNE&MLpBBec*e$B4tK z^wW*EH1Z6lBe<_h3`Peairfa$=m>NI8=Wm>Tq>AOIC%uTn--|X!$az>u(#rQyZ9K2 zfL`o-o!nK{f9WaGq|UR;ATi$p+w6M7&lWeH_Eo4>A@_FNA|z~p41t&?BSAZ%PMCjs z=@bpNx}XjlB&Uth(posDbyp+zS}Y&-be#=Ov_LdH-cQB{92|)tLyY))B5H{sM9vD@ z$%vmWl$u`n2+)L3V+HDn$OPZ7C{L{@~NH+r*+ZR3rw;jw9b` zk%)+R(?X*gQHMt^_qm^RW=;-6CIm#xQ2KTyr>UQp!K2G=cR6&Hse?+wy=<^$?*=>e;Q~YIQ&lgMY4BY}z&$tsJkNRkr0ngIAo#cH#6Km7 zP$rzS4!D#eV;YZw!t-Za5{{FBk=VRbHieQ$Y5nj9@7>q)C zR76Nf#3XtF&9G*hrjnauVErH#NB{^BC1*$t$aMXyv^ge!AD?N+ z^RNf$4D;-uBm$}iJt+I-tP}A3CFSLyJZwMT8P^G6Ve|LzAI;6;Yh7+l@`&6zz&~!Q zc`V(Q5Y5RS@4|F_tr#VrI^8Olma@ZW$e+5|)o_$&R9{0DbFxEx%n z0R$pbk5rbhG=|<5d6t{rgo2Xn;wke!2(K`p{_PHkpA992je1fipne zz(6>V1js-GaQl$ryi{p`f`<2+Yrm}r@e;}V0w=%G;kms)alrH3MQ|6USU zWx)0Wkc*#_n;Q?3xXtTZ5)2xfP&USdWDf!4mn)I>t z0QP}h2JC4>ju+B7o89l%i1Qb$_E|e{szux!kk`FB^Z*G75D9^Zk^gfI5B^*Of<@tt ztdk=Kg_f+&TLj04hc^icuOvoimjGJ@CK8-7LV+3jVOCD9X#9I6UVpYeHTzdsx>9lc zF<|5n0ro*%W!AR>A+eWr2q0P~1?i0O|k zXEBjw47P;J%RZ2_i@*g*IE)6dDQ~*?jcWYn=H@3SKV{6o_`Cht2d#n@4l7F0)UwZ) z-wu0Q2VODE69}|{#73`>ii-dbkfz^R8NdOIYT9^Qq_9nxw@;` z-!L41acrg6Yu9iKy|R3PM0>@U;0G{Xg`?|9|Ou6z^`!F^Mcb@_F#WM zA*63`yD7A$r$X=g^(z71BR4m9j#m9OAXaL>KKaPLn&>5%cqK{B8!|kY%{NX=P>6|% z0qyG#CQtAu7^V;-^lGD+SA^1|E?Yh)!$h@JW zuqV{8w6KVO8c2m~6$G(?#}$-v1!R(597zg{;Ot6@SVAGb1+#UaL;vRO+g=-v&6vS( zGtb!g9R(sP8q(I;nx?zXC;SY5zy7U3McM#UUDHNjt=>{UI`s)4eI%%(llZE7nuV?; zzo>{7N}*Rgx8hBqN8VUl`w{d!!B4av%CsdwW=BUy!~V2&wgdzO^hKnpS` zvTOcYckbK)U^7eoOW7?e>psN)6tGo6)Pq58{DIx?$?WxKL{txeo|u7n40!h=4h8=t z*lqz@$j!^^v4QY}+x!=De@H~S75J=rx;%Wq!mRv`Vh5AmSv4_OJ|Kl5Z~<4QHeelKsuPh|Q!94dxsCiAn z`V%woA_)Hdy@DbH)sL;r9A!zF_LH<~_lyGS*OW-%To61z`|~qCT-R!Z_A%u8EDloI zo?u{`1H7LoUGj-fZ^9pq$cNh6HiCogNVhN{5m?25#S_SrV93Vu zA}&HeVnBiNZOwp+%+bynuk1+gC6Q?=e3uUQ*?@Yy`PYwX&(~yo{;?g^F=7{51Y9Bb zL)b5w-C;TdbycvqLE|sZ@-pSSiK>Z#iz_QD8|L<7&H$4Vu>AQ5{1Ln6&r6U(M8GC* zRz@mt9$W^wA?yQurQ+uP0%RZ?WOm@43dp2&&}{GDZ{!I72vV<4-#@^h2xiKThrc6x z#qH?^)z9&-=3gX7*lrPMR8K>(4Ot}gb@epVBig#UG^aklzJSdwn6bSE(&0N8+d-WN z5bQBj9fk1W7d9rU^?^lPov4ljLr_rHLi~i9Vo=3M)^U5PjqDRI=C40+GMltjlt++v zQETsHd?%&&ZHl;n21IBBluVvZYnU`VYx!&L7nPKhfRl~@Zw6q}6I{>F5W@y|*0cmr z#{jjDU@RUU9uAYi&%k|Z0nmqMjh^1)baNo>v|RqC<@4W*=Nsi!Bd(VoJ~Hv z)K3UO0q_MzN}#8Ubbg^`>;?uCvTrhcZ7{+FLME7lRRM=9e?f^x!e!{7pJ1xe;vydc!No?tiL z4RdKgg+r3jVf}kAe+1_$O>=XolbpdAz+=?;KGda5{|tbFccUPIBQ1y(LLYhhquz&sW!D{EJS zrUCegDN%G-IkKE#;{YO3v>C3(10#KQ%M93(d4QlTUE zFMqyfy1b`A!vZAgp)aHWw>Dx!W%Hr@dr$Ttc$`v+_^{fpt0KuAz$_?T|FU5Y#D*#Y z93{?kpp^+|FZER+BiO3c4-dZ@>4wYJ`RkvLOnE$|31@LJ!T=>2mS9+|2-Q0^m_z;J z(*J}wYItWrmI#fo314%*#^0GTaLh)3QeKqcb!oOOBG_Sf*$^cfiGpAOY*3#KR$x5? zwFaJzKE8(t-?K$!*o?_3&Aa!jToZ^{VE_oNl`X_a48pFgEU`Ra0yV%a8{H2 zy0724!}9WSPo<+Rc*Qh-6Y(u^J?96bz_WA_&!&ohAksq!YFz^ZDS-CD&=V66&z@S+ zps_T@nXN@rdg+yR0hx#w*1}@e@t4`Igm1o|iV~237!QKT*>I3CbB%a93jbYjMgf`N zT`Fh;0me0kdl-i54IT;H10^fh$@@uP$7e>Ur-Xq)D=`2gV8&~3WF+I>`N1YN6hpi& zCtqNHgLNQ+n&6PoH-J^pp}qlxA2izJw{d$^{{t47MqR_g(t#ooSvFungY19k`7qh~ zT+eje=RwnzDk##%45Z}Sah1%f@R$tRDVvBw0&H`hzGra}HD=(F$#@>d24@tgL{ReZ zL;}JzLdiv@t7lRrclY?DARj;>oek*5fy?kcFwUBST00tCy%6nuhg~Bd!h1e2 zyM_35x3#TC?PuJu-2?({Tmp|TtMfBwhrQJZ8oJrmwv*G-p(lOr!D)w;#S^Rw5=8)VVit z><|v)5-+l+Wny?N)`mHemJ=M{uLl~EUM>+6+7QS?6cVacm^j}Lfo(ZlWGV@z6XHgU zB#qybHG@M#hN#E`(SHS#DQFA=Von7Rk-QRmkG*QywBG>r0r$3I{@l0g)YOe+3WWIMvqivfj@I_sWQ46 zc4fe!_QhY=H*U;9NjnEb0b(5rL2hPtRv3021E6G&gVZV@{Sw3i^nfw~($50`CSm|t zc(n;CXk?uMc<$4ZyQu^oPN1Bw3D5-c3@KDnaM)Q85(}hf;9dzS|3qx6n16ix{BFnK zATbdU5fou|03jhLEF5gkK

    bcn~7i8ylNsScs4`@3mXfgbT)h1t5pdAm;{uut7%> zy2>y3!iesxdO;}ynMFgohfYod`bx0nY2XOOCO`C48$f+^2yhDpztfMQp$Oonv~+bt z8^i$^=ve>B+ES_V169O}EBQ`C(FzkbzWr)BxgDJ!?B(U1N2UejhzTboN3FP_nAJGO zs@Gq+|KX!hiQW2NA3gk%)YXV+{V2kcm3tEWKC>lA;tZg`d>yf~f{<-@dc+AAHwg($ zD(c}UxRdALFdiKf15013fUg#iGvX)?)0;PbxhjHbCc+;=pEiP3^CED|;2-A(87cl5 z{qL2 zGlG#opZLLy?@EqCdvbPI9B+~Dav!5HWnh!nL-V18y~6nT3rP|@d8Q)|0bVT*WXFXC zc^C8+h|oci#_jaFRViR>uUyDmuJ2Ka`Geh+(!`cCn~g_JVW#D!7IT;S`zJPJ3TfL> zawVVntn_8i%#Lwyi#b${&ou{Q0LXzp<<)D~5S)d?6=-cEiJVa(^)X!ObmfW-U=UvW zEjOU4O-#P8HQn}y(wWO_vU(Tg>!T5trZE$=0X%{GPJ#e0X=3Ewm*IOh>|? zMgd*UCg?&T<=OGx8jM$6fq)Fr${*|^Sv0C<0q4L?f=3!MS8@o6^cRP`-u~u{7;x=vkcgna@ zac9rmoz6bA*%n=y(3ZIflq0*yHB@S>N|BQ(kF`l_7p3!yR+sff5AWREbWUMAyG!V! zV!4LfHn27gMpOBbE%#U8?Owc=#OAYUImXbo%~wCa)n{NjY~f=#qCBwHr8_lv()u60 z`AwhD=rFlJ@z^E9X=iyTV&ckvGj8xf;^phUqis>AVjlv`$MfjAFZwj8l9cz?_OP>L zRB&xIZk#)xaDx|V;mUckMx4eodi=K7a_;W!`|;Z+tu~mZ!>2#PGUKlQxTbc!khD7B zPO=e2yaHnc%ACPB+zyX;$4w3f>K*5W`{*cx%3`fo*xvCu;#`>IbiIvMY#yyQyC`my zc^d}cZa?Se{tiUK|npHpRiVPQSgcF^61hBne#9jbN}05SvrzUminMfeO!2c~tNGloK~hX*Bx z%kdglTU%QX#|l7iVC`vXX+=%#p-K5N=k*16XQBdu6L@a(5O*Uu3~#}h1QqbC?*Ot| z0OJ5{;6LD1y|OI&Jk6jJ+uT$Pmr9z~b<>C3tQNu%0R(Zx68Kte#A6*{j%$|}mkrMs z1dn3aVCscEFm(J*s#*q#EQQ9x;#4OeUO02)d-i3TmelakGMj66R!#~G`ahIbLC0T^)UvV0$|vr2}alDLl|gi?c22KTW*-VEOz5!L4R5Ch6mp4?}6mbk(1w) zAz`LvJ(Vhs>U`TXT^A^jK;Ukn)r{k?bV^u_kEzR;jlJv&nf5uVPueTEG#c*7DfZC$uk*Z7yU#c0uB9A z`|ad(dd#?EYm7^mkd6kRws5^e=(;yR!Cb|N*{F8}9o9yu;d+>5^$1BwTA=+AuZZg( z3hy53gOAYD#CLPYok%o|qUCkm3xRyKeRk?-+IVxq;PixPb!;(v?T>*8E>$0?fW;N} zEcay%_m#w6t!yo^wmKRje4tmxbi-!n4)!2nl8K zX>YKyv)5&Py@z~6kyJDOhLTrXRwE0U{Ry{Mt(Z(|Smw*ZSc;VaD)Vt(@mSkjxf$N` z12#WpD?&E=Y5GVmblrfRdSYjHpcDYX zaC?0W1rwsJ@W6iE4F=GNSgC^$E{qJI#Z8#_5a8j}LRu*WR2ezj{2kCxV~NEKCKlF7 z`d?Ua8plwyh+h!H+-x_=%skLO!DYbmRiImgW+YYU-G2E4&s+6XuWYu%1dz2pdgzL* zLW!hX?-~O>(yOJri5^#+Pu_$(f|&uuLMd3Ymb#KOhocAVGy|s9C^rw6M9mo+wDe{Z zs1LFCE?>wgW_q09VQrB$)zT?Ym}rw}1StehNC+JbVyRGyziHJYU)%`sz@ON?->2Fn zHg24}tR{rrw(z4S!DRS%is*vc_g?PK(-U-{2vhWKEL<88k69TKf~1|MIwWpt4mxvjpQ`L-s(rDFC@$_EBPB!45Da z8SFigBj?a4L&9Z}#x8ey^oYNWI*+uw)xw+06u z0@jD2A)vGjpn0EHl%0~|3DbHG4i0INFxg;n`s^FMs~^SB4Lp5GCU2~cTq$xtsh-AN zwLe_>m7SelIs%A*B@ayljBCqOc^$n@4(~O?w_l+x0j8?;E14qVPaI-xkD8ITS zK&{-#?^Zq8jG9>dvmE_}D>Bi%tq_2bD6MgfJ=b;Cew82ItNqVX^-2uLrz#Z#Cn8{| zZrERNVIXVb;w^ytq#y{Bv`3YAj^r`i z79W5(yh%=;r6?uEG?b@H4XvTY#YNm(w|-96eDnr;yKU0j0CImo)y4V#_38>3_W)5x z$<8jfb|V3bn#q}&;6YlvQCWT_CJB5N8E63@#@|wMbi#ym?o(~?MyDUdvqMDx5GSu- zGV=ks0QPh-r8C3Jt}AF0tpngkAg9tf%1dWHaV6v4b<7f3NY7~8gG9m_8UdgXplz;% zcEDTOJjXO(c%U7lvmjyQYC*uFh!0C^Z%rV`AXg~<*`!=P<9*HycG#GViid%r84ua5 zj@)$g@u@Nlew8txU-_gpc7;MQYxr@v%vx7pU*AE6N1_*U^}w;7?ukVTCp~32_xMFjm!SZv~^W%v- z4gTamK@#faTxDRDbJ@(x0#=u^3zzupCE^8bek_QG^VqJmX6U;B7tSP7>fYoB!<>u1 zt(a(~qH9KqYjzHj(7z7Zhev`5)$P^ssN9*9*P)$3ukQE#uC@v%U>eA`o5K2(t$+FY z;I!i*2?f7f!^ptEkH>NEPaWCzY-N22t-rzxXwxW(Rw+Im%CmowPA<<}I`16<}|M5C}W#8N*4VK;P>0$Ux-F+v~Ck+_lA}Be*ZZ|or3W0 z&_jd5?&-}xjSxa8R<`yV=1OqLYrjA8h5p44=XZB5*luKGayc2elJh#bSy?N=)U(0R zXlSxDNowYUdTr*73D>WBYlxLqSIKi{$RJ<7sYb4{WL=#B&CWp2=2)x6e(k>wGnow` zIW&Aayz$P5pv7|SNV?2sqci56BDdX}Bpmh@>!y>&6|A$KZfc3V zXbtAskQ+=nQk=I5Rs&TpUxiQ3G_smaaFcDg zXlaFT7!O6ji-(wh$%#se<@(NjyppsMqKf zzO%af5X^UvVVJ1rdJCK#d_>YeoYA+Zrixh{&7=q*zdXIYFCl?%JKH_;_~B_~%!>>z zc7w_6VgGQ(B6H=0HB4oh``gh42L12WP&hxl59oTG_f~H!WvRvk@Gy*)(YbOh>0zX@ z_g(OUz6$nwU_xC$Mx*w5v#SaQO@U5ok0k@NPbD0dZ{JE@F<=6<1>dlL&@vRw&H9EN zsZ*ywM_~qHCoZh0Nl9Trms|%*u@I~KvI}Qph2s|mb@*UI^F`U@P3Ysm`JLBLl))5= z5lS)gX|`(s*uZNA{qiSho$pE7mc5##^ncd`Y^~w#7m!DJbc6VPXTREPlcvOs=&t?Y zGJ(D2f=oXTeEuVK$(IFo1W#mRr(c^ley*upI+UdAtHL4WZCT7EKRCqrJi$m&>0mQo zT;ser_0X%&_+grEwet)IwV14&aW(Gk+s$7rV!w|})<$vFgxr7e!BD>8dCHz^eY3-j zR}dLL|Mq%=O~x_cR>7%hLyAWKM;4G&M?e$)EK0Y;A0Y9H$*D>=s-K6(ZKOh|M( zJf}sq$MTiGdan>{ZFW3H$+1Iy<4&m*4(P-T znyLdflbr%(7&{rM+3O+CSxRjezAYa*+L*nr9j1W*!m1Zd=kELBDE({HXE!q`CC2KG zut7Q|xga4~S)~L&4S!R?0GfxQf=(>@*!=U$L;A!17yk4Or~AHH6CL4@rmYbRdSNX) zstfU0uSv=l*G%Y+L_Cq3!2|XStW;me7Gpxae^&X{efhrh7gh_=yuE~GW9IA^4aK^x zgkV3=EL+L*S#4oOJfH`?IL>8izec;qNq}Lds2UaCcSnkbY{BwiC^x z(pPT{KgL#(1HE+Kk>-{RmAUAyQ7DY*Dvcc)0p2J!|Jc_Lz%2Wy`lIucot>S7{RyUY zT>#Ijl{OEQSMdKE7!!3Dd=HG1R4lhoMpa{zd1wHjm5X09GJ*}B7k>Uoc68(b^Zd%D zhwi>r@OvEHr?hmQ$w4F|B^+eblM?O&i>o(In_weNE9BmX zJMYij_qMI%G(Jx@*koM1Gx97?>W0l4|8F&`tCY9;QzlqPe|>!#daHb&RHwCQY_!Dk zBCHa|5SEO!rx9{`2c@@3N&Nx>a5}8hpXcPL1+B1rS$4045$)=p!=Qb(h4{)Vo7(}V za$mTem%7uh<9VKDtr07K$n|E+T8p%RDK0Y@@7%!?PWSQhs!NiwDl!`pde$WmEBKM^ z*{%Eq=6JIhlJxOnIESxU+i(v;JnpS6?9MbRI0oWjgaVn_o#k$Cwi#ad_Z9Q;3SD4f zE?wal-{YzE#C|Q8D%CE) zOqxQg4B13xy)acJ4;%`Ejw*-Ii15rpNajm_Q@WnLW5b~dreAMeshrc#w5734hFW2y z;b6*>q5z^!_rQSmR^4+zfu#GC+AzpHj(|u&Q>-ql=IOg0IBT5{eBNZO!*tZmdr{En z6GtyJm5w_?Q3wj9Jh0Qi9FUzk1x>yxo%c_MGp?hpqmM0)7P5r((;PtYKf)#BYCRfE z=TAi|DxMz}V}Jb64Jfl5+W}Ev$_#jI#OJy~XtnPs$!XuM+t*U+RUNshFe?KyEnbb` z6xY}Lwb2~+$bTB2vE!E!(!ag;dmHC*ngYAyy4E$6;?Ey-9=DRx^PT2+3fFp#yCUz8 z9d{q4tOH{E!E1ig13T{V>q)#<1?wNgWl-O*hw0UPBOuY2|HC^9c2B=xy9g~N-Q)U>a4Rc<+J-$803SN~Xr5z(Qo!iYzXfx~%msIoNYwo)KQcaE$vW6F1F z;@WX$3mF@JJV|)r+%PJF@Z}npl`9wVh%>i$h zPVnaEAKhk8#R2bOo%M<&hT)W^gJn(wX$V^F{K;+x-Xq~_u;xlJ-Jmmc4bbJM)YWyzaKH@^R<}@hSMsEPXhv+F8qnMjR6#m zxo<5j=h`z1v7QG$xATt_rYX0?=gdz~=2Yq+m1pUwGo9&bhQM@;t^Jz?J?&)6>tySrXz;DUc4&I96zv@dp_ekmlj{S3tYApL~HV!8)Pp(B3d+V*t z4*Lf>d$51CqL6sS-Bb1C4$vsA3-=QGab8%o8Ooko77i8|3FQS)Qt^HWboPAS^D~eU zTgGphD;lVO6s0UFkEr~DM@W;}msd0yxo`KrU22pGb~f5_FbHB|fHpyjUmQ5jSYD)1oti0c94)sBEX}72W*Ts~8h7FVq?>R>a~l9b@&wEqRemSwYXqqaG0&C0uJJPR$we}k4|_9if{_*Tq6_wE_L zWHnDWItD7GEt>!R!V@lU%p23wr5}6K)P(NUPNA!OS$-sAIt0o2g?TJpD0S9BQOeR_ zLwj5=@p~x_I(7jhT?pU$A7C-2UJi2|$vb zJbUf+Lk*p=Wf9=hzg&B<{HschDHda_&bSC;{bS>skqv)Q`v%!B9t*vtZC@U~Cz3VG zeRHPJZ+?)S^z%QFt1^4J**oKp$9OoemN)~u!)5GLPHx~kjjvv67G-f(%+CfMI96&s2O|{X>#${J{>3;O#lgE#$ap1g z$|v18DJiZiZZtZR52zHWA38FvOvWmFfJU!!$Y&~@P)a*Ia$V{4++l`cB@7($XX#E$ zI(!>@yDBH2{|{wv8J5+$bpc}&BGL^?H!6*U(%qes0t$$LG)OlHh$tZ`ok}-INq2XL zw1nh0pMAFHyzlp({ax4h{Mq|*yPs#Rd);f!F~^+u7-e+uS{#2dd46Vn?4}&{2|K-L z;yJDKrCvj`xO&z=Cd-tz9mRvd#I-o}OVN_?A)Yr2I60*SCLmMwQnQSw;edZxe&OjT zHkl9qTyM0|;z7aBIJ@*PFU;X9IKwz-~r;bRsc*NIh$0R=F z;7EoVBbNOlB8s+$`UNpm4$o({>KyHQV!}wr3ys$-AeE$V_VAB-%qEJ^7WFor9+4xX zpG!>htvkHd)L5K@v!64?mJvn&=Hm@>`*?`)@VX;SrV+JC#n&%w2@~<3252)&2-|Ku z{Zj!GWp8=9=U7_|fFCXgQ{p5RH|C3p-g4JL(`C1=)s&h?D$~|Q?Z`3J^V^2zk<>*t z@)FIcO9TSNf;_gdb3pM?`k@;iPEw9v_->Y|3rSIZQ`Zt%gEDF@^j{Y*U^t0`@~L)W>)RLyb*> z1}b%u*T(HGP>htZ+g0eKr^F7*kDEzP0)H4q#GrhmvAOK#ziO3nK{_34oTFDpL+bpd zv90N2zz*^U@YdaCqg6^5(!3pdJ4@&Lr+l}{Z$BPi{K%Yt?6*_+YM533dtqSeak7kL zr|l;;({}E?rJfAu=?(P)6b!Tsy(sdB?2nq#lbFBLgr$kBrA<7f;h>k@aaYg4${<||=(Tvol$(eR)Dl5O+jh@my?WyX^$amIPT>c_tOjF`>7T6Vs5 zm*^zIFLdHc;-?0dSck13lp zB3UXa3Uo^LaTG?slbbxS`OIH;PkZbH?Cc;js2p3*KO`k3ZI5P-&f5DQMc_)JmJ&of zXiWtsCqMm~Z>divpF2`8v$Opr=jDtN25giYul}h~A>ws5iLsJX?ecbk( zvMzW*m|&1|VXEo~SQ%8R%TtCDz01L~-|xs^Z~^r#-)|;%ce$!9Qk6@t4)c~y!4;)c z4HM3Mot}5Q-y;*|cD=<##6*-zQ%-t*y^c;mE>Ael2>ywhbNSi8)T-qhZ4Z{tWjC`& zdU#^v(td6AIUL8G8>pwnVN~TC8>{2c?wc1?y{y|HuW#)Qx3e6^RJg2V+G##AQEJ^e zZlI)Sq@-K=H8V9cW^YHQcv#0}`f?LhA?GQnRt5VP^ND5dDwR}=&2<8*SD!6-|K18; zQgggD^W&>s>8*pFtN8id1n!{zMOZ7>zaIT#m{ZbhKO{XJbe3=~_{}If5m-}oFur8u zis~U|*JNu*p`R4u{G;aay2DwE`bQb_qDP0}p+284FELuH__Ewu99p-I7_u2~f>b6- zv$9ZHTEwcI&jm}C3iQq~q=T!ozG6hUQ>~B;4-BZDUuyS^rJ22MbR_RpZ2OqYO-=OF;@ri7@^@jr;^Y9;X`6iORqb_Mfzrl7&rj>h=0jWAOoB`lU4Gr4 z!Q5%(Tm_Fj$=746*FMFMh-azv*N8rcx2m;!z@-9v@10As=j!VE4n42QCS@&0T>i8N zwrR7w{#KRa$0~9%TUPdWr{vy_cMp9Q%DSme2_kvr)vdI>N7j7_2#6jSHL6&gD{xFx zxLRzo@obniwv9d*I}bq2)5s#&1!H>VST3av%CWqT9wL5ub#?K)Or>fKMPR^3%P!lF zf`|%6&p&fJaZb0Q@r))H6tw!H#SDGWFJG13HN2d%H~LdiqaaIMh@&rrNgI9^aO)mi z+keG0CzDsn>_|+~nU3zUxB7XTYl=Eofi6?2f=@g=K}q|fr%zcWPwQdx1n!!$RF8pd zx8|)=FPJN|*`4=T>49m&a#ztBE+dP0!K_cTEV6s_IH=J2G=a>abHFbK!w0!KCA)D2 zmQ_b&X_5;k*#%LRruKpt;FMJtaK5?HNBv>b1jCAX7lIoIL=~n&7$h2le-dJ5tZ$Els&`JT1 z;MLFBzUw1>iv+091cGmQ5tE<&LDb` z&t`xOa7Z!o=^& zV^&0)Lck6Q+9QSw`r1xMTl~Oa7dd8eMe#rPC?kQ)ef!OJ7XtZ}oFV~>KRY9>zB;hI z->UTgRdbKa0q7nrv_XT`iH}e9ciVNHd>z>fa&ntiY5_3kYb-H$LFImLv{~78wm$4j z8=gN0NGz0S_&i;(+z6etKYYsNPLb*6Otl+vCrJUdPVMW2r`J5rmo0-kpGMgZ_x8S> zwwfZ~ANKB0&qwqDp+c;W;wFC~7rIZ&vELM}Qfs@yy89wA8F-o~2*LR}HBWn^GH@7- zk7P$m{}MvrO<$)aafuJq{q~>c5+Z$ok=;P*$i2{(2VWMV-oFp=q(QutK00Sdp!~*i z585fM^6>`aAx^L`=dxpUBOBx~G=k)h;%Z4J%U`XNByS7eJ>GdJ?1Db8+xB?;Xf;ji z`PQQ5`|czAjp*Z5;?;pXYYbDlkKIEa1v@N@r2842)b-nUrcMteN+z9{_6$D^gw&~D zHbVeCp4l;KDyVbYf0Ktc{%T`gR=|DX=xuVu{kl7A9eh1JKhInqlLKM$W8vN~v-Wqd zEIlG}Z_nf_q%QUbEywhe)z03tWetuYu}%9KJ*pczwX+?o7nJ30n|J^TVDcksMgFs5 zeZy9cP8Nq%>>}2hHjo3Es%5_G8wpi+3hhtH^7RG6U{D0NJw|qMERn-}Is&>Y?mZs~ zm9#=TVoN-ff#UxaYDuS=ezWQgtw)OZeRg}h5jPexjQ%&bpEx5<&WKIks_d(Hq0f{j zy#sg-F@6JRO+#bR;Oh!WiF7cJzA( zhNxasQM|MtJdgid4=b}YVUX8DiBVohaw!M$E_9&NUL0Kj2k!qxR1Z-Mj_B#KcjG3) z+ht&3v8O6O)0D3XXCcmNY8c5wcL+mGYV>>cPby!TKEO( z>^AD*?R{W-C?wz(lrDaB=k^=f-JJ`0>+$mw^y5CALvx9g6#2q6NV2) zr-4)4ILv9goKRGceY-p|UF$`mRA_1H{btW4#MS+MH)8f$ zdw0*)O0EaHez4n~iSqYI%iR>s-8y%Euo&a1LZ{(Z7;ZpP`y<9VM!UVq zfh?WlI%t#ETCeCGX@C1WFhjr2Z@FiWpaP1w;K~+1PruY9myTieo`JGxxFg}#l_LbE zJmlx?Pkv52FV$ru%@EV3u{G`Twno=egjQgx)hw%GmxnPpt=DyoT4SGJGZe>!E6dOT?V|2k#VPZKH+o1f_G zAJF&&%*@WT?7}9M#_t(?^Ij$yI3g7~{SR567oY_v`z2;W_vbc0TG`pB^wUkCNYi;< zKNxX&8oQ-#Og7*rpZ+$Q8Af&CP=rd1-X+-@P+l11H(&p3dox~q>dUO{kV6J-_Ez0X zG=2UI(G8YSjg{vO)me5hordUs@w=b4n3DwKnTCyE;W6upLcHQ0op@;c%G&v24+gTK ztwrN;;R^F7i;yxww5u=GMSSwsFT?sIMG}G6SJ}Rigb>ZiUDn3BH6o}rhiN4|)?Jzh zt0-TjK0G_@3{)vlBYX>ITmY&V!%V<*HA=c&7M4uhqcGl*7n!As|F_Xsw0@NJPwh51 zqs8A~6L@-a;nyd$a+jkk{O)TKOH%9DwiYR{Zh$`9hr6b;O>lG0B#I1uH8*PL#wMht zp~6h@pLie^MuO08h;;Xoz#nEU_j0ll)|trI64{`CAUh6v4v13{)}_z4@0Yj(w(p{k zmdZcXTbc~~rjoUmyU7jb%J;^KBk9SE=(km%8Peg1)@b8Y@KN4qW%LXSY*xusN<7@u z+T~lN(fh{#ik#1H!d+kfBSGRWcKRHTJqug9>}+$CHdDM{^Z~J}N_hA`^yC&6(eVoV zU9Q=03{uS=IvxI;tY0sQgT|b4$^w=;6dl)Z@+WI`wY+Ci_J$@Y4DW@CovJfLBTQ6b zOknWCNS?Ac+jFc$9kqb>>!Woqo#~LT^((_fYkxGL7nrA$*qNDfnK@LHyYF+Xw>2pc zlfp?PguFVP!p5)dkb2HaYCcerP`ZG8znF=S&ufhhf0m=w8wRfsQ(s?9RZosK8-i3f zhK4PtbMGhcmNqmseQe1;pjWJ>J6Nym-O9j26z1vn$}cVVZI@s6i*|>TfB(qw923aj z6sK=~h;A4Ugw@V$qyHfV$H+m(8gz zwRS&y{ivnYjdTmyEj_jxF0Nft@$SM&y1%RNilGnM|Ej`&2$0=>M6^Z^r=iv)=7bLE zQWx=IRwT+kXW&TumgutGaXlUo_~vact-SD0p)|^W7lVRzl4&Xos+S}`(X#Wj%iqNb2@w%0I2~SQj=0V;t5e#F^YS2^HwvfY zd>Mq$eV}o9j5Iu~2CrIoCgxVWfUT$MH1Y2&H~G%a*RP&!(@5croOR2n>*g)u^VN?ORfG!>5}-OLQ~Uoyfu2R=d123l-yS; zD=YhelXHG(<1&lc<6zwbW+2X4#(X5?)7%i>^i@vxw12?zRr<6847RTdzA{ePKv3rq zskClKOhN%Y>^!W#cju+81kW3{y<4e{?M-8b!qn6BD=T>|Lz!@%Dl*$xk@uve4+;VbQ^=^Xm&VShEX2#cl7Q_(B%A`(CcnWaCdnKgZpkoDsOF;ZyB;vN4R)DjFSvL7A{;zX&%RcE(RqibIakz5kr9n>@&N4WT zy;yzc{&U(k0D5%Gz}GK3GSBTrZ`>w2&ap_a-*8h{)iUGrOt?$v``7VBs)>K`z!uro z4ws%Dh$)DoRR0|qT&=U)egb`_ibWSyMp%;w*MfZ|sze=qci^=Jcz=;FaY^e$ zv4t4)aEgjAJP|cj<&ksX$3IEIjuqv?=TDmS^jRZzL zFY2~#&RVFdaN492zIkxpdU|sAC9^v^@t^_ZY?-}}q5^S|xf&IpnLP^9s+9?ccwq!L z<>jYHIQ_>q)_PB5wMxSE!^~_;GyZtk-d_i-AMwKw6CiyYX1yE2%GwM(T(gkmvRgsd zzz=TIH~&TjGpYGx?zJlpLxR&PFrV#QiN3rNX0_P1^kmbS*|Udj=MdUCJg<44K{T-AFdUwOgSyyu4Z^ zVKk=#FtWbHIP`rq_nv5wswvDWSWEa zL<{)B+>e*ECDN)HA1khPcO%(oM!PxW(7~rzHKAt;4!sM_Y%1Xzu5Xcb8aD+pfmCCYmdTByDec! zH1TmRv(&!Y|I@3X82Y`XRUzQft(#JM@wVFyTJdJpt+5KjO^5fv1UTq7;=sniLEGH5 z-$!T3B8k{Xp*k*AR}l!l_nkOhs-6<0btE?zhn3}$C=s8VyR%!=%Pz7FjTGVQPW~7# z4YF6bODq%Nuft?n7IW3>H9BGcUqh>oIH)(^MQE*gjE~|%-c~Vinx&Wbb=`)apWjq2 zv3@@(4!+E0ck=1_V19Bb`akrAY_Ym(pG~X47+2I{xvTkc@5Nb#9VgJrBdf>r128Rh z{WyV^f<1s(UA{lpT)3q5XzOujyk=Bn^@c`3IYpzuL+dj_vXi=odb)Gj4VsxgIIwPg z=3|bCG9l*Jj=PI^Xe;t2=QqiR7Nqe&)Wd;HUHRhj%9;Iy1GOYtbWmF@NA(K+Kza# zj&DqN-Nc|^y}$F0+_h}WYkOGNDI9;~&Fj~wFyax|m+CibGO0^~F&}3&qkWL{w9VPEXI{C0 zs}vL7!u*#V*74QpE+TvuAJt<{5miltl`m-v;WJ_9tJ{kK;zx~zT}ReT`W1IRkUAT- zC0XxKEOV+c>m!Y{2uW}BH{ zA_ri#1Wb%9eV;!pS~Xq>SY94RG%=b4373wAa7}(!Q)`^ASafP~m1A$u)V9`4I7r)aqjhGdW+fobe6_qAZ}hwt^}9aOfMh zOsu5)4Hr=Z#g75mC4+OG-)#otK0rt1j<4 zQ0(JBc0Md@_SvOOPD#0qBq1%`dV(&XvAX6roTv3fS^1hYzRMGN`HWt^wKYPG>R+t6 zT17~keH%H%ih+$JI{Oc-j{Fs#1y>y z@FC3I&H1UMB&OfZgQDI6^t{eEj|gc|Q9?_tvQBN|IjAx|@|iQGBnk-Y=#>F+^KHLg~0g7aC z2kqM@!-NbB?F8IOtm`8q&Az?!!SS#U5Ep+wBF6NQ>lW#__7h=YQnI=W9~#rpLW=`G ztfOyK3vvd$#bxyoZxaIC?Qn(bhyxBTkA-@Ys4uu2nZj-+Fum?04r5ip>{l9?Emzxx=XL&&GDoU&df5li6~Jm>7&(ZUvtjb z`q_4R_Ud*g`kfw>y}ThxEm~Yw+SnGDTGa8}UxY_0#nyq?mCK6Yy~=xPi_@VFbqRTC z@o<4R3MxuIwNKs7*sbwmOJAzZm!c_STHaMn^AAtibEjACt%HB@36oISWH(pFf4$c) z)JmtYRQ2XlK<4eKnj<80^R>dFQU<#?aNaN|jiY7JtMpPYn0~^9cMa*YK0Gy7!XqLlpn*FJp6+uMqYht_R36IEV2xGAfK8N@hKuu&2m3c zJr72_y(NC+?|3+FUr|z4diZrl0qJ*Z$jwVZQ=FJoDk2VZm6XyAV$LTqdQ&^0mioWW z6R~q&K2A0o=~kdyw3Rbg5g``A{n0dvJkNCD85tlj8{H_PV)C1uFLIl8LO}bCdr?>G zRcizNre?#3&PSwI`KO$b(fGqc-V-buSHA_i=Rf*l zjoX(nxDuzd3q=;mVd;aVX=#$?8Mn^pevtLIB*r%#IXetkfmGvMtugC!3on>iexfrx zkQA7~c~h6R($>1aAu)==C*vL@PT#Y`&2bZg9JlR?7i?`IHMx8d%U}@-NAgiG)!G-y zNtth{$vl#zzlDk7)dW|z*WLSKE^Kyo4F^-PxxKqx^v#*6^svo{Z2~Wqr zgIf(WZ7jQ=%|u1Gfx7qGNmFe>UJ{q<4lx(IPjxj3i+=5g?TZcr^}eQ`b&R(-*ass% z9&^rcVvsHBP#wero{ZKT5WUc4SdLz}g|A&TI}o9OEc&P~izv>6hU{$Ai*1!n@uT0i7f z!BfIxRLg5E+2DF;xqkg=>HX|>0YTOdi!=JH`4)p4H=JY=_{g^En46Xga~w|(NtanQ z{2oUf&GHUWTMG^+Jg&EH6_|t=41L7+78m#LUzaTxNUiHQjsXi{IAb3oPAV?~R;BoT}X?{FP?j3HW$Vi)g zi|dn@bqW*(_revUS`4#V4MlV+!r=6cQCCW|?8 ziJN0F^LtxwH0p2@4&sWyjnN2oUPh{4b4TJ4AYPWeyRTY<;_m_{d;3-Ao z!tREACP)SG;pf+97AYs^q=pKFz4^Go`Ay`UA%C;_*3fi&Me}91k07r=|vJJj(^n>6fc2bywfrMTx5tuk+nB=Y z+WPF|CnP&FYsGm^?phT$F){MxUiXt@dOISOZdPY_=lxO`smL(^aDYjf*`goHyZYm_1OYJwYk>afuuZTj49`% z`oXcw^D8ywB&i+*!GuQXjs5i`=2_<4Hs`lPh~r%CCzzQ#ZH|^nJ4v>KGH-<|X5{1f zg^&hqx1e7`auqbf`poa-XZ`Y2NKzB!joh8ptIPO@?T4i*_q3z4f-?)uU zOc62wt8^+ifv>ww`Tgc^yhs5Dnk1p|i=hSi5E23898j=+{~l+#ob`!A)s=FmO__*b z3-#-lZrax^6IUsDoXlm;O0Kc5)1i`n85Egs=T%fg=K^xw?8S@k&COqqLth|~Vay>c zq~J(5GT$nt9Zm|-^Pbu#$1lgc;Xq(=>U$oLKo}etuK$_nahDerQ}t@Jc{MSJQ~r`A zde(W{{UR-UuKZGwWZWGIwDkOA;pCG|yN-En_^(wCB)^;J@8To9;H+(ZN+^#U*-SWY z&hWyveHRwP(g=Z-0f@Ar2Gs@bC~kS|x_A7I}Yvzy2Z_x7qE(P1bUx zvx&*XS=isArTBI~5i3+b<${rvql~f8ir(6}hW&8ZM9b6d^ej9zv7@ccC#dp1=f$_` zUh`b3@#S_^;+-BbeWWLw<3y{y(^nZ|T$Y&$v`06fmF2p+u{K{Y=j^9yz-TEEIKweY%5!Q!?+ne zklDp!)@E-`3|>yrR^O;Tm-s4+xHI!UR1c(hayl%z!nqCB{DzU zm@AmuT<}M{vcCu7xb5eW5Ybt7+I?rDl*}57?Ag?K^T&l+q{j}VNJz&owXU^J^Uv`% zQ(FsM&IhH7mK?2}PgRZ0K3$}~PPXR_mF~_|Wlp`@ $QQM5^ez81cj%B#SzGnUpY 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 U9=&TqAuD)FQT2F|{Ds^91)wa+k^lez literal 0 HcmV?d00001 diff --git a/transaction_verification/src/app.py b/transaction_verification/src/app.py index 36f592052..b1087e51f 100644 --- a/transaction_verification/src/app.py +++ b/transaction_verification/src/app.py @@ -20,9 +20,13 @@ def VerifyTransaction(self, request, context): print("Received transaction verification request") print("user_name:", request.user_name) print("user_contact:", request.user_contact) + masked_card_number = mask_fixed(request.card_number) + print("card_number:", masked_card_number) print("item_count:", request.item_count) print("terms_accepted:", request.terms_accepted) - + # Compute length based on digits only to avoid counting spaces or other characters + card_digits = extract_card_digits(request.card_number) + print("card length (digits only):", len(card_digits)) is_valid = True message = "Transaction is valid." @@ -42,6 +46,11 @@ def VerifyTransaction(self, request, context): is_valid = False message = "Missing credit card information." + # Treat any non-16-digit card number as invalid + elif len(card_digits) != 16: + is_valid = False + message = "Invalid card number." + response = transaction_verification.TransactionVerificationResponse() response.is_valid = is_valid response.message = message @@ -50,6 +59,13 @@ def VerifyTransaction(self, request, context): return response +def extract_card_digits(card: str) -> str: + """ + Return only the digit characters from the given card number. + """ + return ''.join(c for c in str(card) if c.isdigit()) + + def serve(): server = grpc.server(futures.ThreadPoolExecutor()) transaction_verification_grpc.add_TransactionVerificationServiceServicer_to_server( @@ -62,6 +78,10 @@ def serve(): print("Transaction verification server started. Listening on port 50052.") server.wait_for_termination() +def mask_fixed(card: str) -> str: + digits = ''.join(c for c in str(card) if c.isdigit()) + masked = '*' * 12 + digits[-4:].rjust(4, '*') + return ' '.join(masked[i:i+4] for i in range(0, 16, 4)) if __name__ == '__main__': serve() \ No newline at end of file From 5ad3d74fad39b1a5b331b79080c1d0333b2330fa Mon Sep 17 00:00:00 2001 From: anupkumar Date: Mon, 2 Mar 2026 16:55:05 +0200 Subject: [PATCH 18/18] incremental changes --- README.md | 4 ++-- fraud_detection/src/app.py | 5 ++--- orchestrator/src/app.py | 30 +++++++++++++++--------------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 009c93749..e34340b5a 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,11 @@ The following diagrams give a high-level view of the system and how the services **System overview** -![System diagram](../system_diagram.png) +![System diagram](./system_diagram.png) **Service architecture** -![Service architecture diagram](../architecture_diagram.png) +![Service architecture diagram](./architecture_diagram.png) ### Running the code with Docker Compose [recommended] diff --git a/fraud_detection/src/app.py b/fraud_detection/src/app.py index 10c6b4264..ecee0fad5 100644 --- a/fraud_detection/src/app.py +++ b/fraud_detection/src/app.py @@ -44,14 +44,13 @@ def CheckFraud(self, request, context): is_fraud = True message = "Invalid card number." - elif request.card_number.startswith("0000"): + elif card_digits.startswith("0000"): is_fraud = True message = "Suspicious card number pattern." - elif request.card_number.endswith("0000"): + elif card_digits.endswith("0000"): is_fraud = True message = "Suspicious card number pattern." - elif "fraud" in request.user_name.lower(): is_fraud = True message = "Suspicious user name." diff --git a/orchestrator/src/app.py b/orchestrator/src/app.py index 5e1cae6cf..590815ff5 100644 --- a/orchestrator/src/app.py +++ b/orchestrator/src/app.py @@ -49,11 +49,11 @@ def detect_fraud(user_name, card_number, item_count): user_name=user_name or "", card_number=card_number or "", item_count=item_count - ) + ), + timeout=5.0 # seconds ) return response - def verify_transaction(user_name, user_contact, card_number, expiration_date, cvv, item_count, terms_accepted): with grpc.insecure_channel('transaction_verification:50052') as channel: stub = transaction_verification_grpc.TransactionVerificationServiceStub(channel) @@ -110,15 +110,16 @@ def checkout(): shipping_method = request_data.get("shippingMethod") terms_accepted = request_data.get("termsAndConditionsAccepted", False) - user_name = user.get("name") - user_contact = user.get("contact") + # Normalize user fields and enforce that user_name is not empty or just spaces + user_name = (user.get("name") or "").strip() + user_contact = (user.get("contact") or "").strip() user_comment = user.get("userComment", "") credit_card = user.get("creditCard", {}) - card_number = credit_card.get("number") + card_number = credit_card.get("number").strip() masked_card_number = mask_fixed(card_number) - expiration_date = credit_card.get("expirationDate") - cvv = credit_card.get("cvv") + expiration_date = credit_card.get("expirationDate").strip() + cvv = credit_card.get("cvv").strip() print( "Received a request for checkout of user : {} for card number : {}".format( user_name, masked_card_number @@ -127,19 +128,20 @@ def checkout(): # Keep these simple bad-request checks locally - if not user_name: + # user_name must not be empty or contain spaces + if not user_name or "" == user_name: return { "error": { "code": "BAD_REQUEST", - "message": "User name is required." + "message": "User name is required and must not contain spaces." } }, 400 - if not user_contact: + if not user_contact or "" == user_contact: return { "error": { "code": "BAD_REQUEST", - "message": "User contact is required." + "message": "User contact is required and must not contain spaces." } }, 400 @@ -166,10 +168,8 @@ def fraud_worker(): results["fraud"].message ) except Exception as e: - error_msg = f"fraud_detection failed: {e}" - print(error_msg) - results["errors"].append(error_msg) - + print(f"fraud_detection failed: {e}") # Full detail for server logs + results["errors"].append("fraud_detection service unavailable") # Sanitized for client def verification_worker(): try: print("Calling transaction_verification service...")