From 56ebed5445e59e5bc6381a0413b089d73d981d9a Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 13 Dec 2024 14:40:37 -0800 Subject: [PATCH 01/31] switch to log insights for delivery receipts --- app/celery/scheduled_tasks.py | 9 ++++ app/clients/cloudwatch/aws_cloudwatch.py | 65 ++++++++++++++++++++++++ app/dao/notifications_dao.py | 24 +++++++++ 3 files changed, 98 insertions(+) diff --git a/app/celery/scheduled_tasks.py b/app/celery/scheduled_tasks.py index 3597bdbb7..f884de834 100644 --- a/app/celery/scheduled_tasks.py +++ b/app/celery/scheduled_tasks.py @@ -11,6 +11,7 @@ process_job, process_row, ) +from app.clients.cloudwatch.aws_cloudwatch import AwsCloudwatchClient from app.config import QueueNames from app.dao.invited_org_user_dao import ( delete_org_invitations_created_more_than_two_days_ago, @@ -231,3 +232,11 @@ def check_for_services_with_high_failure_rates_or_sending_to_tv_numbers(): technical_ticket=True, ) zendesk_client.send_ticket_to_zendesk(ticket) + + +@notify_celery.task(name="process_delivery_receipts_first_wave") +def process_delivery_receipts_first_wave(): + cloudwatch = AwsCloudwatchClient() + start_time = utc_now() - timedelta(hours=1) + end_time = utc_now() + receipts = cloudwatch.check_delivery_receipts(start_time, end_time) diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index 36bcf5dca..c914501bc 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -2,12 +2,14 @@ import os import re from datetime import timedelta +from time import sleep from boto3 import client from flask import current_app from app.clients import AWS_CLIENT_CONFIG, Client from app.cloudfoundry_config import cloud_config +from app.dao.notifications_dao import dao_update_delivery_receipts from app.exceptions import NotificationTechnicalFailureException from app.utils import hilite, utc_now @@ -108,6 +110,7 @@ def warn_if_dev_is_opted_out(self, provider_response, notification_id): return logline return None + # DEPRECATED def check_sms(self, message_id, notification_id, created_at): region = cloud_config.sns_region # TODO this clumsy approach to getting the account number will be fixed as part of notify-api #258 @@ -165,3 +168,65 @@ def check_sms(self, message_id, notification_id, created_at): raise NotificationTechnicalFailureException( f"No event found for message_id {message_id} notification_id {notification_id}" ) + + +def do_log_insights(self): + region = cloud_config.sns_region + account_number = self._extract_account_number(cloud_config.ses_domain_arn) + + log_group_name = f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber" + log_group_name_failed = ( + f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber/Failed" + ) + + query = """ + fields @timestamp, status, delivery.providerResponse, delivery.destination, notification.messageId, delivery.phoneCarrier + | sort @timestamp asc + """ + start = utc_now() - timedelta(hours=1) + end = utc_now() + + response = client._client.start_query( + logGroupName=log_group_name, + startTime=int(start.timestamp()), + endTime=int(end.timestamp()), + queryString=query, + ) + query_id = response["queryId"] + while True: + result = client._client.get_query_results(queryId=query_id) + if result["status"] == "Complete": + break + sleep(1) + + delivery_receipts = [] + for log in result["results"]: + receipt = {field["field"]: field["value"] for field in log} + delivery_receipts.append(receipt) + print(receipt) + + delivered = delivery_receipts + + response = client._client.start_query( + logGroupName=log_group_name_failed, + startTime=int(start.timestamp()), + endTime=int(end.timestamp()), + queryString=query, + ) + query_id = response["queryId"] + while True: + result = client._client.get_query_results(queryId=query_id) + if result["status"] == "Complete": + break + sleep(1) + + delivery_receipts = [] + for log in result["results"]: + receipt = {field["field"]: field["value"] for field in log} + delivery_receipts.append(receipt) + print(receipt) + + failed = delivery_receipts + + dao_update_delivery_receipts(delivered) + dao_update_delivery_receipts(failed) diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index 052242644..d676f79f7 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -707,3 +707,27 @@ def get_service_ids_with_notifications_on_date(notification_type, date): union(notification_table_query, ft_status_table_query).subquery() ).distinct() } + + +def dao_update_delivery_receipts(receipts): + id_to_status = {r["notification.messageId"]: r["status"] for r in receipts} + id_to_carrier = { + r["notification.messageId"]: r["delivery.phoneCarrier"] for r in receipts + } + id_to_provider_response = { + r["notification.messageId"]: r["delivery.providerResponse"] for r in receipts + } + id_to_timestamp = {r["notification.messageId"]: r["@timestamp"] for r in receipts} + + stmt = ( + update(Notification) + .where(Notification.c.message_id.in_(id_to_carrier.keys())) + .values( + carrier=case(id_to_carrier), + status=case(id_to_status), + notification_status=case(id_to_status), + sent_at=case(id_to_timestamp), + ) + ) + db.session.execute(stmt) + db.session.commit() From 7529ae0153d949c50e6d2b7d54323b8e4f2d7418 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 13 Dec 2024 15:04:18 -0800 Subject: [PATCH 02/31] more --- app/celery/provider_tasks.py | 103 +--------------------- app/clients/cloudwatch/aws_cloudwatch.py | 59 ------------- tests/app/celery/test_provider_tasks.py | 106 +---------------------- 3 files changed, 4 insertions(+), 264 deletions(-) diff --git a/app/celery/provider_tasks.py b/app/celery/provider_tasks.py index a75a68c96..3bdd2d9c0 100644 --- a/app/celery/provider_tasks.py +++ b/app/celery/provider_tasks.py @@ -1,107 +1,19 @@ import json import os -from datetime import timedelta -from botocore.exceptions import ClientError from flask import current_app from sqlalchemy.orm.exc import NoResultFound -from app import aws_cloudwatch_client, notify_celery, redis_store +from app import notify_celery, redis_store from app.clients.email import EmailClientNonRetryableException from app.clients.email.aws_ses import AwsSesClientThrottlingSendRateException from app.clients.sms import SmsClientResponseException from app.config import Config, QueueNames from app.dao import notifications_dao -from app.dao.notifications_dao import ( - sanitize_successful_notification_by_id, - update_notification_status_by_id, -) +from app.dao.notifications_dao import update_notification_status_by_id from app.delivery import send_to_providers from app.enums import NotificationStatus from app.exceptions import NotificationTechnicalFailureException -from app.utils import utc_now - -# This is the amount of time to wait after sending an sms message before we check the aws logs and look for delivery -# receipts -DELIVERY_RECEIPT_DELAY_IN_SECONDS = 30 - - -@notify_celery.task( - bind=True, - name="check_sms_delivery_receipt", - max_retries=48, - default_retry_delay=300, -) -def check_sms_delivery_receipt(self, message_id, notification_id, sent_at): - """ - This is called after deliver_sms to check the status of the message. This uses the same number of - retries and the same delay period as deliver_sms. In addition, this fires five minutes after - deliver_sms initially. So the idea is that most messages will succeed and show up in the logs quickly. - Other message will resolve successfully after a retry or to. A few will fail but it will take up to - 4 hours to know for sure. The call to check_sms will raise an exception if neither a success nor a - failure appears in the cloudwatch logs, so this should keep retrying until the log appears, or until - we run out of retries. - """ - # TODO the localstack cloudwatch doesn't currently have our log groups. Possibly create them with awslocal? - if aws_cloudwatch_client.is_localstack(): - status = "success" - provider_response = "this is a fake successful localstack sms message" - carrier = "unknown" - else: - try: - status, provider_response, carrier = aws_cloudwatch_client.check_sms( - message_id, notification_id, sent_at - ) - except NotificationTechnicalFailureException as ntfe: - provider_response = "Unable to find carrier response -- still looking" - status = "pending" - carrier = "" - update_notification_status_by_id( - notification_id, - status, - carrier=carrier, - provider_response=provider_response, - ) - raise self.retry(exc=ntfe) - except ClientError as err: - # Probably a ThrottlingException but could be something else - error_code = err.response["Error"]["Code"] - provider_response = ( - f"{error_code} while checking sms receipt -- still looking" - ) - status = "pending" - carrier = "" - update_notification_status_by_id( - notification_id, - status, - carrier=carrier, - provider_response=provider_response, - ) - raise self.retry(exc=err) - - if status == "success": - status = NotificationStatus.DELIVERED - elif status == "failure": - status = NotificationStatus.FAILED - # if status is not success or failure the client raised an exception and this method will retry - - if status == NotificationStatus.DELIVERED: - sanitize_successful_notification_by_id( - notification_id, carrier=carrier, provider_response=provider_response - ) - current_app.logger.info( - f"Sanitized notification {notification_id} that was successfully delivered" - ) - else: - update_notification_status_by_id( - notification_id, - status, - carrier=carrier, - provider_response=provider_response, - ) - current_app.logger.info( - f"Updated notification {notification_id} with response '{provider_response}'" - ) @notify_celery.task( @@ -127,17 +39,8 @@ def deliver_sms(self, notification_id): ansi_green + f"AUTHENTICATION CODE: {notification.content}" + ansi_reset ) # Code branches off to send_to_providers.py - message_id = send_to_providers.send_sms_to_provider(notification) + send_to_providers.send_sms_to_provider(notification) - # DEPRECATED - # We have to put it in UTC. For other timezones, the delay - # will be ignored and it will fire immediately (although this probably only affects developer testing) - my_eta = utc_now() + timedelta(seconds=DELIVERY_RECEIPT_DELAY_IN_SECONDS) - check_sms_delivery_receipt.apply_async( - [message_id, notification_id, notification.created_at], - eta=my_eta, - queue=QueueNames.CHECK_SMS, - ) except Exception as e: update_notification_status_by_id( notification_id, diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index c914501bc..9bb52ea88 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -110,65 +110,6 @@ def warn_if_dev_is_opted_out(self, provider_response, notification_id): return logline return None - # DEPRECATED - def check_sms(self, message_id, notification_id, created_at): - region = cloud_config.sns_region - # TODO this clumsy approach to getting the account number will be fixed as part of notify-api #258 - account_number = self._extract_account_number(cloud_config.ses_domain_arn) - - time_now = utc_now() - log_group_name = f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber" - filter_pattern = '{$.notification.messageId="XXXXX"}' - filter_pattern = filter_pattern.replace("XXXXX", message_id) - all_log_events = self._get_log(filter_pattern, log_group_name, created_at) - if all_log_events and len(all_log_events) > 0: - event = all_log_events[0] - message = json.loads(event["message"]) - self.warn_if_dev_is_opted_out( - message["delivery"]["providerResponse"], notification_id - ) - # Here we map the answer from aws to the message_id. - # Previously, in send_to_providers, we mapped the job_id and row number - # to the message id. And on the admin side we mapped the csv filename - # to the job_id. So by tracing through all the logs we can go: - # filename->job_id->message_id->what really happened - current_app.logger.info( - hilite(f"DELIVERED: {message} for message_id {message_id}") - ) - return ( - "success", - message["delivery"]["providerResponse"], - message["delivery"].get("phoneCarrier", "Unknown Carrier"), - ) - - log_group_name = ( - f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber/Failure" - ) - all_failed_events = self._get_log(filter_pattern, log_group_name, created_at) - if all_failed_events and len(all_failed_events) > 0: - event = all_failed_events[0] - message = json.loads(event["message"]) - self.warn_if_dev_is_opted_out( - message["delivery"]["providerResponse"], notification_id - ) - - current_app.logger.info( - hilite(f"FAILED: {message} for message_id {message_id}") - ) - return ( - "failure", - message["delivery"]["providerResponse"], - message["delivery"].get("phoneCarrier", "Unknown Carrier"), - ) - - if time_now > (created_at + timedelta(hours=3)): - # see app/models.py Notification. This message corresponds to "permanent-failure", - # but we are copy/pasting here to avoid circular imports. - return "failure", "Unable to find carrier response." - raise NotificationTechnicalFailureException( - f"No event found for message_id {message_id} notification_id {notification_id}" - ) - def do_log_insights(self): region = cloud_config.sns_region diff --git a/tests/app/celery/test_provider_tasks.py b/tests/app/celery/test_provider_tasks.py index 80d5a0d7e..e16e9c54b 100644 --- a/tests/app/celery/test_provider_tasks.py +++ b/tests/app/celery/test_provider_tasks.py @@ -7,11 +7,7 @@ import app from app.celery import provider_tasks -from app.celery.provider_tasks import ( - check_sms_delivery_receipt, - deliver_email, - deliver_sms, -) +from app.celery.provider_tasks import deliver_email, deliver_sms from app.clients.email import EmailClientNonRetryableException from app.clients.email.aws_ses import ( AwsSesClientException, @@ -27,110 +23,10 @@ def test_should_have_decorated_tasks_functions(): assert deliver_email.__wrapped__.__name__ == "deliver_email" -def test_should_check_delivery_receipts_success(sample_notification, mocker): - mocker.patch("app.delivery.send_to_providers.send_sms_to_provider") - mocker.patch( - "app.celery.provider_tasks.aws_cloudwatch_client.is_localstack", - return_value=False, - ) - mocker.patch( - "app.celery.provider_tasks.aws_cloudwatch_client.check_sms", - return_value=("success", "okay", "AT&T"), - ) - mock_sanitize = mocker.patch( - "app.celery.provider_tasks.sanitize_successful_notification_by_id" - ) - check_sms_delivery_receipt( - "message_id", sample_notification.id, "2024-10-20 00:00:00+0:00" - ) - # This call should be made if the message was successfully delivered - mock_sanitize.assert_called_once() - - -def test_should_check_delivery_receipts_failure(sample_notification, mocker): - mocker.patch("app.delivery.send_to_providers.send_sms_to_provider") - mocker.patch( - "app.celery.provider_tasks.aws_cloudwatch_client.is_localstack", - return_value=False, - ) - mock_update = mocker.patch( - "app.celery.provider_tasks.update_notification_status_by_id" - ) - mocker.patch( - "app.celery.provider_tasks.aws_cloudwatch_client.check_sms", - return_value=("failure", "not okay", "AT&T"), - ) - mock_sanitize = mocker.patch( - "app.celery.provider_tasks.sanitize_successful_notification_by_id" - ) - check_sms_delivery_receipt( - "message_id", sample_notification.id, "2024-10-20 00:00:00+0:00" - ) - mock_sanitize.assert_not_called() - mock_update.assert_called_once() - - -def test_should_check_delivery_receipts_client_error(sample_notification, mocker): - mocker.patch("app.delivery.send_to_providers.send_sms_to_provider") - mocker.patch( - "app.celery.provider_tasks.aws_cloudwatch_client.is_localstack", - return_value=False, - ) - mock_update = mocker.patch( - "app.celery.provider_tasks.update_notification_status_by_id" - ) - error_response = {"Error": {"Code": "SomeCode", "Message": "Some Message"}} - operation_name = "SomeOperation" - mocker.patch( - "app.celery.provider_tasks.aws_cloudwatch_client.check_sms", - side_effect=ClientError(error_response, operation_name), - ) - mock_sanitize = mocker.patch( - "app.celery.provider_tasks.sanitize_successful_notification_by_id" - ) - try: - check_sms_delivery_receipt( - "message_id", sample_notification.id, "2024-10-20 00:00:00+0:00" - ) - - assert 1 == 0 - except ClientError: - mock_sanitize.assert_not_called() - mock_update.assert_called_once() - - -def test_should_check_delivery_receipts_ntfe(sample_notification, mocker): - mocker.patch("app.delivery.send_to_providers.send_sms_to_provider") - mocker.patch( - "app.celery.provider_tasks.aws_cloudwatch_client.is_localstack", - return_value=False, - ) - mock_update = mocker.patch( - "app.celery.provider_tasks.update_notification_status_by_id" - ) - mocker.patch( - "app.celery.provider_tasks.aws_cloudwatch_client.check_sms", - side_effect=NotificationTechnicalFailureException(), - ) - mock_sanitize = mocker.patch( - "app.celery.provider_tasks.sanitize_successful_notification_by_id" - ) - try: - check_sms_delivery_receipt( - "message_id", sample_notification.id, "2024-10-20 00:00:00+0:00" - ) - - assert 1 == 0 - except NotificationTechnicalFailureException: - mock_sanitize.assert_not_called() - mock_update.assert_called_once() - - def test_should_call_send_sms_to_provider_from_deliver_sms_task( sample_notification, mocker ): mocker.patch("app.delivery.send_to_providers.send_sms_to_provider") - mocker.patch("app.celery.provider_tasks.check_sms_delivery_receipt") deliver_sms(sample_notification.id) app.delivery.send_to_providers.send_sms_to_provider.assert_called_with( From b784d33173296dfa530700d8d0218cf38ee26723 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 13 Dec 2024 16:45:09 -0800 Subject: [PATCH 03/31] more work --- app/celery/scheduled_tasks.py | 12 ++++++++---- app/clients/cloudwatch/aws_cloudwatch.py | 12 ++++-------- app/config.py | 5 +++++ app/dao/notifications_dao.py | 1 + 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/app/celery/scheduled_tasks.py b/app/celery/scheduled_tasks.py index f884de834..562e4422d 100644 --- a/app/celery/scheduled_tasks.py +++ b/app/celery/scheduled_tasks.py @@ -23,7 +23,10 @@ find_jobs_with_missing_rows, find_missing_row_for_job, ) -from app.dao.notifications_dao import notifications_not_yet_sent +from app.dao.notifications_dao import ( + dao_update_delivery_receipts, + notifications_not_yet_sent, +) from app.dao.services_dao import ( dao_find_services_sending_to_tv_numbers, dao_find_services_with_high_failure_rates, @@ -234,9 +237,10 @@ def check_for_services_with_high_failure_rates_or_sending_to_tv_numbers(): zendesk_client.send_ticket_to_zendesk(ticket) -@notify_celery.task(name="process_delivery_receipts_first_wave") -def process_delivery_receipts_first_wave(): +@notify_celery.task(name="process-delivery-receipts") +def process_delivery_receipts(): cloudwatch = AwsCloudwatchClient() - start_time = utc_now() - timedelta(hours=1) + start_time = utc_now() - timedelta(minutes=10) end_time = utc_now() receipts = cloudwatch.check_delivery_receipts(start_time, end_time) + dao_update_delivery_receipts(receipts) diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index 9bb52ea88..aa53877ea 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -1,7 +1,5 @@ -import json import os import re -from datetime import timedelta from time import sleep from boto3 import client @@ -10,8 +8,7 @@ from app.clients import AWS_CLIENT_CONFIG, Client from app.cloudfoundry_config import cloud_config from app.dao.notifications_dao import dao_update_delivery_receipts -from app.exceptions import NotificationTechnicalFailureException -from app.utils import hilite, utc_now +from app.utils import utc_now class AwsCloudwatchClient(Client): @@ -111,7 +108,7 @@ def warn_if_dev_is_opted_out(self, provider_response, notification_id): return None -def do_log_insights(self): +def check_delivery_receipts(self, start, end): region = cloud_config.sns_region account_number = self._extract_account_number(cloud_config.ses_domain_arn) @@ -121,11 +118,10 @@ def do_log_insights(self): ) query = """ - fields @timestamp, status, delivery.providerResponse, delivery.destination, notification.messageId, delivery.phoneCarrier + fields @timestamp, status, delivery.providerResponse, delivery.destination, + notification.messageId, delivery.phoneCarrier | sort @timestamp asc """ - start = utc_now() - timedelta(hours=1) - end = utc_now() response = client._client.start_query( logGroupName=log_group_name, diff --git a/app/config.py b/app/config.py index 12159e289..e7f4af14d 100644 --- a/app/config.py +++ b/app/config.py @@ -196,6 +196,11 @@ class Config(object): "schedule": timedelta(minutes=63), "options": {"queue": QueueNames.PERIODIC}, }, + "process-delivery-receipts": { + "task": "process-delivery-receipts", + "schedule": timedelta(minutes=8), + "options": {"queue": QueueNames.PERIODIC}, + }, "expire-or-delete-invitations": { "task": "expire-or-delete-invitations", "schedule": timedelta(minutes=66), diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index d676f79f7..d3871c59b 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -727,6 +727,7 @@ def dao_update_delivery_receipts(receipts): status=case(id_to_status), notification_status=case(id_to_status), sent_at=case(id_to_timestamp), + provider_response=case(id_to_provider_response), ) ) db.session.execute(stmt) From b28b54776279514ec440721c760fccdf8ac1f970 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 13 Dec 2024 17:30:00 -0800 Subject: [PATCH 04/31] more --- app/celery/scheduled_tasks.py | 1 + app/clients/cloudwatch/aws_cloudwatch.py | 114 +++++++++++------------ app/config.py | 2 +- 3 files changed, 57 insertions(+), 60 deletions(-) diff --git a/app/celery/scheduled_tasks.py b/app/celery/scheduled_tasks.py index 562e4422d..d5aaa27a8 100644 --- a/app/celery/scheduled_tasks.py +++ b/app/celery/scheduled_tasks.py @@ -240,6 +240,7 @@ def check_for_services_with_high_failure_rates_or_sending_to_tv_numbers(): @notify_celery.task(name="process-delivery-receipts") def process_delivery_receipts(): cloudwatch = AwsCloudwatchClient() + cloudwatch.init_app(current_app) start_time = utc_now() - timedelta(minutes=10) end_time = utc_now() receipts = cloudwatch.check_delivery_receipts(start_time, end_time) diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index aa53877ea..825d13c5e 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -7,7 +7,6 @@ from app.clients import AWS_CLIENT_CONFIG, Client from app.cloudfoundry_config import cloud_config -from app.dao.notifications_dao import dao_update_delivery_receipts from app.utils import utc_now @@ -107,63 +106,60 @@ def warn_if_dev_is_opted_out(self, provider_response, notification_id): return logline return None + def check_delivery_receipts(self, start, end): + region = cloud_config.sns_region + account_number = self._extract_account_number(cloud_config.ses_domain_arn) + + log_group_name = f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber" + log_group_name_failed = ( + f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber/Failed" + ) + + query = """ + fields @timestamp, status, delivery.providerResponse, delivery.destination, + notification.messageId, delivery.phoneCarrier + | sort @timestamp asc + """ + + response = self._client.start_query( + logGroupName=log_group_name, + startTime=int(start.timestamp()), + endTime=int(end.timestamp()), + queryString=query, + ) + query_id = response["queryId"] + while True: + result = client._client.get_query_results(queryId=query_id) + if result["status"] == "Complete": + break + sleep(1) + + delivery_receipts = [] + for log in result["results"]: + receipt = {field["field"]: field["value"] for field in log} + delivery_receipts.append(receipt) + print(receipt) + + delivered = delivery_receipts + + response = client._client.start_query( + logGroupName=log_group_name_failed, + startTime=int(start.timestamp()), + endTime=int(end.timestamp()), + queryString=query, + ) + query_id = response["queryId"] + while True: + result = client._client.get_query_results(queryId=query_id) + if result["status"] == "Complete": + break + sleep(1) -def check_delivery_receipts(self, start, end): - region = cloud_config.sns_region - account_number = self._extract_account_number(cloud_config.ses_domain_arn) - - log_group_name = f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber" - log_group_name_failed = ( - f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber/Failed" - ) - - query = """ - fields @timestamp, status, delivery.providerResponse, delivery.destination, - notification.messageId, delivery.phoneCarrier - | sort @timestamp asc - """ + delivery_receipts = [] + for log in result["results"]: + receipt = {field["field"]: field["value"] for field in log} + delivery_receipts.append(receipt) + print(receipt) - response = client._client.start_query( - logGroupName=log_group_name, - startTime=int(start.timestamp()), - endTime=int(end.timestamp()), - queryString=query, - ) - query_id = response["queryId"] - while True: - result = client._client.get_query_results(queryId=query_id) - if result["status"] == "Complete": - break - sleep(1) - - delivery_receipts = [] - for log in result["results"]: - receipt = {field["field"]: field["value"] for field in log} - delivery_receipts.append(receipt) - print(receipt) - - delivered = delivery_receipts - - response = client._client.start_query( - logGroupName=log_group_name_failed, - startTime=int(start.timestamp()), - endTime=int(end.timestamp()), - queryString=query, - ) - query_id = response["queryId"] - while True: - result = client._client.get_query_results(queryId=query_id) - if result["status"] == "Complete": - break - sleep(1) - - delivery_receipts = [] - for log in result["results"]: - receipt = {field["field"]: field["value"] for field in log} - delivery_receipts.append(receipt) - print(receipt) - - failed = delivery_receipts - - dao_update_delivery_receipts(delivered) - dao_update_delivery_receipts(failed) + failed = delivery_receipts + return delivered + failed diff --git a/app/config.py b/app/config.py index e7f4af14d..d935b08b9 100644 --- a/app/config.py +++ b/app/config.py @@ -198,7 +198,7 @@ class Config(object): }, "process-delivery-receipts": { "task": "process-delivery-receipts", - "schedule": timedelta(minutes=8), + "schedule": timedelta(minutes=1), "options": {"queue": QueueNames.PERIODIC}, }, "expire-or-delete-invitations": { From 85e100febe51e04d1a0e83b062f62f117ba80b30 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 13 Dec 2024 17:40:28 -0800 Subject: [PATCH 05/31] fix --- tests/app/clients/test_aws_cloudwatch.py | 46 ------------------------ 1 file changed, 46 deletions(-) diff --git a/tests/app/clients/test_aws_cloudwatch.py b/tests/app/clients/test_aws_cloudwatch.py index b9529037b..fce0e150c 100644 --- a/tests/app/clients/test_aws_cloudwatch.py +++ b/tests/app/clients/test_aws_cloudwatch.py @@ -2,7 +2,6 @@ from flask import current_app from app import aws_cloudwatch_client -from app.utils import utc_now def test_check_sms_no_event_error_condition(notify_api, mocker): @@ -74,51 +73,6 @@ def test_warn_if_dev_is_opted_out(response, notify_id, expected_message): assert result == expected_message -def test_check_sms_success(notify_api, mocker): - aws_cloudwatch_client.init_app(current_app) - boto_mock = mocker.patch.object(aws_cloudwatch_client, "_client", create=True) - boto_mock.filter_log_events.side_effect = side_effect - mocker.patch.dict( - "os.environ", - {"SES_DOMAIN_ARN": "arn:aws:ses:us-west-2:12345:identity/ses-xxx.xxx.xxx.xxx"}, - ) - - message_id = "succeed" - notification_id = "ccc" - created_at = utc_now() - with notify_api.app_context(): - aws_cloudwatch_client.check_sms(message_id, notification_id, created_at) - - # We check the 'success' log group first and if we find the message_id, we are done, so there is only 1 call - assert boto_mock.filter_log_events.call_count == 1 - mock_call = str(boto_mock.filter_log_events.mock_calls[0]) - assert "Failure" not in mock_call - assert "succeed" in mock_call - assert "notification.messageId" in mock_call - - -def test_check_sms_failure(notify_api, mocker): - aws_cloudwatch_client.init_app(current_app) - boto_mock = mocker.patch.object(aws_cloudwatch_client, "_client", create=True) - boto_mock.filter_log_events.side_effect = side_effect - mocker.patch.dict( - "os.environ", - {"SES_DOMAIN_ARN": "arn:aws:ses:us-west-2:12345:identity/ses-xxx.xxx.xxx.xxx"}, - ) - message_id = "fail" - notification_id = "bbb" - created_at = utc_now() - with notify_api.app_context(): - aws_cloudwatch_client.check_sms(message_id, notification_id, created_at) - - # We check the 'success' log group and find nothing, so we then check the 'fail' log group -- two calls. - assert boto_mock.filter_log_events.call_count == 2 - mock_call = str(boto_mock.filter_log_events.mock_calls[1]) - assert "Failure" in mock_call - assert "fail" in mock_call - assert "notification.messageId" in mock_call - - def test_extract_account_number_gov_cloud(): domain_arn = "arn:aws-us-gov:ses:us-gov-west-1:12345:identity/ses-abc.xxx.xxx.xxx" actual_account_number = aws_cloudwatch_client._extract_account_number(domain_arn) From 2707f757c8e286c5465f4c4ee464f4c9cf3a0193 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 16 Dec 2024 08:29:34 -0800 Subject: [PATCH 06/31] get rid of duplicated code --- app/clients/cloudwatch/aws_cloudwatch.py | 33 +++++------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index 825d13c5e..f66ed0290 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -121,6 +121,11 @@ def check_delivery_receipts(self, start, end): | sort @timestamp asc """ + delivered = self.run_log_insights_query(log_group_name, start, end, query) + failed = self.run_log_insights_query(log_group_name_failed, start, end, query) + return delivered + failed + + def run_log_insights_query(self, log_group_name, start, end, query): response = self._client.start_query( logGroupName=log_group_name, startTime=int(start.timestamp()), @@ -129,28 +134,7 @@ def check_delivery_receipts(self, start, end): ) query_id = response["queryId"] while True: - result = client._client.get_query_results(queryId=query_id) - if result["status"] == "Complete": - break - sleep(1) - - delivery_receipts = [] - for log in result["results"]: - receipt = {field["field"]: field["value"] for field in log} - delivery_receipts.append(receipt) - print(receipt) - - delivered = delivery_receipts - - response = client._client.start_query( - logGroupName=log_group_name_failed, - startTime=int(start.timestamp()), - endTime=int(end.timestamp()), - queryString=query, - ) - query_id = response["queryId"] - while True: - result = client._client.get_query_results(queryId=query_id) + result = self._client.get_query_results(queryId=query_id) if result["status"] == "Complete": break sleep(1) @@ -159,7 +143,4 @@ def check_delivery_receipts(self, start, end): for log in result["results"]: receipt = {field["field"]: field["value"] for field in log} delivery_receipts.append(receipt) - print(receipt) - - failed = delivery_receipts - return delivered + failed + return delivery_receipts From b5881409520f7ffb471e4131c9a8d81f86db063a Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 16 Dec 2024 11:22:49 -0800 Subject: [PATCH 07/31] change schedule to every 8 minutes --- app/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config.py b/app/config.py index d935b08b9..e7f4af14d 100644 --- a/app/config.py +++ b/app/config.py @@ -198,7 +198,7 @@ class Config(object): }, "process-delivery-receipts": { "task": "process-delivery-receipts", - "schedule": timedelta(minutes=1), + "schedule": timedelta(minutes=8), "options": {"queue": QueueNames.PERIODIC}, }, "expire-or-delete-invitations": { From 87d9ae5f33c9ab5635ebd0f8e0671b5625e34523 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 16 Dec 2024 14:16:35 -0800 Subject: [PATCH 08/31] remove dead code --- app/clients/cloudwatch/aws_cloudwatch.py | 44 +++--------------------- 1 file changed, 5 insertions(+), 39 deletions(-) diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index f66ed0290..0d9f58680 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -7,7 +7,6 @@ from app.clients import AWS_CLIENT_CONFIG, Client from app.cloudfoundry_config import cloud_config -from app.utils import utc_now class AwsCloudwatchClient(Client): @@ -47,44 +46,6 @@ def name(self): def is_localstack(self): return self._is_localstack - def _get_log(self, my_filter, log_group_name, sent_at): - # Check all cloudwatch logs from the time the notification was sent (currently 5 minutes previously) until now - now = utc_now() - beginning = sent_at - next_token = None - all_log_events = [] - current_app.logger.info(f"START TIME {beginning} END TIME {now}") - # There has been a change somewhere and the time range we were previously using has become too - # narrow or wrong in some way, so events can't be found. For the time being, adjust by adding - # a buffer on each side of 12 hours. - TWELVE_HOURS = 12 * 60 * 60 * 1000 - while True: - if next_token: - response = self._client.filter_log_events( - logGroupName=log_group_name, - filterPattern=my_filter, - nextToken=next_token, - startTime=int(beginning.timestamp() * 1000) - TWELVE_HOURS, - endTime=int(now.timestamp() * 1000) + TWELVE_HOURS, - ) - else: - response = self._client.filter_log_events( - logGroupName=log_group_name, - filterPattern=my_filter, - startTime=int(beginning.timestamp() * 1000) - TWELVE_HOURS, - endTime=int(now.timestamp() * 1000) + TWELVE_HOURS, - ) - log_events = response.get("events", []) - all_log_events.extend(log_events) - if len(log_events) > 0: - # We found it - - break - next_token = response.get("nextToken") - if not next_token: - break - return all_log_events - def _extract_account_number(self, ses_domain_arn): account_number = ses_domain_arn.split(":") return account_number @@ -107,6 +68,11 @@ def warn_if_dev_is_opted_out(self, provider_response, notification_id): return None def check_delivery_receipts(self, start, end): + + result = self._client.describe_log_groups() + print(result) + return + region = cloud_config.sns_region account_number = self._extract_account_number(cloud_config.ses_domain_arn) From 6316e266eede9cbe1ee322441f1cc74c8947153e Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 16 Dec 2024 14:33:50 -0800 Subject: [PATCH 09/31] fix batch processing --- app/celery/scheduled_tasks.py | 5 ++++- app/clients/cloudwatch/aws_cloudwatch.py | 4 ---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/celery/scheduled_tasks.py b/app/celery/scheduled_tasks.py index d5aaa27a8..94bea4bea 100644 --- a/app/celery/scheduled_tasks.py +++ b/app/celery/scheduled_tasks.py @@ -244,4 +244,7 @@ def process_delivery_receipts(): start_time = utc_now() - timedelta(minutes=10) end_time = utc_now() receipts = cloudwatch.check_delivery_receipts(start_time, end_time) - dao_update_delivery_receipts(receipts) + batch_size = 100 + for i in range(0, len(receipts), batch_size): + batch = receipts[i : i + batch_size] + dao_update_delivery_receipts(batch) diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index 0d9f58680..cd510e9dd 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -69,10 +69,6 @@ def warn_if_dev_is_opted_out(self, provider_response, notification_id): def check_delivery_receipts(self, start, end): - result = self._client.describe_log_groups() - print(result) - return - region = cloud_config.sns_region account_number = self._extract_account_number(cloud_config.ses_domain_arn) From 7cf747d35af39452e5dcb7fe0ac9044b14a84ea7 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Tue, 17 Dec 2024 15:59:30 -0800 Subject: [PATCH 10/31] go back to filter log events --- app/celery/scheduled_tasks.py | 24 +++- app/clients/cloudwatch/aws_cloudwatch.py | 155 +++++++++++++++-------- app/dao/notifications_dao.py | 66 ++++++++-- 3 files changed, 178 insertions(+), 67 deletions(-) diff --git a/app/celery/scheduled_tasks.py b/app/celery/scheduled_tasks.py index 94bea4bea..b14d50ee5 100644 --- a/app/celery/scheduled_tasks.py +++ b/app/celery/scheduled_tasks.py @@ -35,7 +35,8 @@ from app.enums import JobStatus, NotificationType from app.models import Job from app.notifications.process_notifications import send_notification_to_queue -from app.utils import utc_now +from app.utils import hilite, utc_now +from notifications_utils import aware_utcnow from notifications_utils.clients.zendesk.zendesk_client import NotifySupportTicket MAX_NOTIFICATION_FAILS = 10000 @@ -239,12 +240,21 @@ def check_for_services_with_high_failure_rates_or_sending_to_tv_numbers(): @notify_celery.task(name="process-delivery-receipts") def process_delivery_receipts(): + print(hilite("ENTER PROCESS DELIVERY RECEIPTS")) cloudwatch = AwsCloudwatchClient() cloudwatch.init_app(current_app) - start_time = utc_now() - timedelta(minutes=10) - end_time = utc_now() - receipts = cloudwatch.check_delivery_receipts(start_time, end_time) + start_time = aware_utcnow() - timedelta(minutes=10) + end_time = aware_utcnow() + delivered_receipts, failed_receipts = cloudwatch.check_delivery_receipts( + start_time, end_time + ) + delivered_receipts = list(delivered_receipts) + batch_size = 100 + for i in range(0, len(delivered_receipts), batch_size): + batch = delivered_receipts[i : i + batch_size] + dao_update_delivery_receipts(batch, True) + failed_receipts = list(failed_receipts) batch_size = 100 - for i in range(0, len(receipts), batch_size): - batch = receipts[i : i + batch_size] - dao_update_delivery_receipts(batch) + for i in range(0, len(failed_receipts), batch_size): + batch = failed_receipts[i : i + batch_size] + dao_update_delivery_receipts(batch, False) diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index cd510e9dd..d84044943 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -1,12 +1,12 @@ +import json import os import re -from time import sleep from boto3 import client -from flask import current_app from app.clients import AWS_CLIENT_CONFIG, Client from app.cloudfoundry_config import cloud_config +from app.utils import hilite class AwsCloudwatchClient(Client): @@ -46,63 +46,116 @@ def name(self): def is_localstack(self): return self._is_localstack + def _get_log(self, log_group_name, start, end): + # Check all cloudwatch logs from the time the notification was sent (currently 5 minutes previously) until now + print(hilite(f"START {start} END {end}")) + next_token = None + all_log_events = [] + + while True: + if next_token: + response = self._client.filter_log_events( + logGroupName=log_group_name, + nextToken=next_token, + startTime=int(start.timestamp() * 1000), + endTime=int(end.timestamp() * 1000), + ) + else: + response = self._client.filter_log_events( + logGroupName=log_group_name, + startTime=int(start.timestamp() * 1000), + endTime=int(end.timestamp() * 1000), + ) + log_events = response.get("events", []) + all_log_events.extend(log_events) + next_token = response.get("nextToken") + if not next_token: + break + return all_log_events + def _extract_account_number(self, ses_domain_arn): account_number = ses_domain_arn.split(":") return account_number - def warn_if_dev_is_opted_out(self, provider_response, notification_id): - if ( - "is opted out" in provider_response.lower() - or "has blocked sms" in provider_response.lower() - ): - if os.getenv("NOTIFY_ENVIRONMENT") in ["development", "test"]: - ansi_red = "\033[31m" - ansi_reset = "\033[0m" - logline = ( - ansi_red - + f"The phone number for notification_id {notification_id} is OPTED OUT. You need to opt back in" - + ansi_reset - ) - current_app.logger.warning(logline) - return logline - return None - + def event_to_db_format(self, event): + + # massage the data into the form the db expects. When we switch + # from filter_log_events to log insights this will be convenient + if isinstance(event, str): + event = json.loads(event) + + return { + "notification.messageId": event["notification"]["messageId"], + "status": event["status"], + "delivery.phoneCarrier": event["delivery"]["phoneCarrier"], + "delivery.providerResponse": event["delivery"]["providerResponse"], + "@timestamp": event["notification"]["timestamp"], + } + + # Here is an example of how to get the events with log insights + # def do_log_insights(): + # query = """ + # fields @timestamp, status, message, recipient + # | filter status = "DELIVERED" + # | sort @timestamp asc + # """ + # temp_client = boto3.client( + # "logs", + # region_name="us-gov-west-1", + # aws_access_key_id=AWS_ACCESS_KEY_ID, + # aws_secret_access_key=AWS_SECRET_ACCESS_KEY, + # config=AWS_CLIENT_CONFIG, + # ) + # start = utc_now() + # end = utc_now - timedelta(hours=1) + # response = temp_client.start_query( + # logGroupName = LOG_GROUP_NAME_DELIVERED, + # startTime = int(start.timestamp()), + # endTime= int(end.timestamp()), + # queryString = query + + # ) + # query_id = response['queryId'] + # while True: + # result = temp_client.get_query_results(queryId=query_id) + # if result['status'] == 'Complete': + # break + # time.sleep(1) + + # delivery_receipts = [] + # for log in result['results']: + # receipt = {field['field']: field['value'] for field in log} + # delivery_receipts.append(receipt) + # print(receipt) + + # print(len(delivery_receipts)) + + # In the long run we want to use Log Insights because it is more efficient + # that filter_log_events. But we are blocked by a permissions issue in the broker. + # So for now, use filter_log_events and grab all log_events over a 10 minute interval, + # and run this on a schedule. def check_delivery_receipts(self, start, end): - region = cloud_config.sns_region + # TODO this clumsy approach to getting the account number will be fixed as part of notify-api #258 account_number = self._extract_account_number(cloud_config.ses_domain_arn) - + delivered_event_set = set() log_group_name = f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber" - log_group_name_failed = ( - f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber/Failed" - ) + print(hilite(f"LOG GROUP NAME {log_group_name}")) + all_delivered_events = self._get_log(log_group_name, start, end) + print(f"ALL DELIVEREDS {len(all_delivered_events)}") - query = """ - fields @timestamp, status, delivery.providerResponse, delivery.destination, - notification.messageId, delivery.phoneCarrier - | sort @timestamp asc - """ - - delivered = self.run_log_insights_query(log_group_name, start, end, query) - failed = self.run_log_insights_query(log_group_name_failed, start, end, query) - return delivered + failed - - def run_log_insights_query(self, log_group_name, start, end, query): - response = self._client.start_query( - logGroupName=log_group_name, - startTime=int(start.timestamp()), - endTime=int(end.timestamp()), - queryString=query, + for event in all_delivered_events: + actual_event = self.event_to_db_format(event["message"]) + delivered_event_set.add(json.dumps(actual_event)) + + failed_event_set = set() + log_group_name = ( + f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber/Failure" ) - query_id = response["queryId"] - while True: - result = self._client.get_query_results(queryId=query_id) - if result["status"] == "Complete": - break - sleep(1) + all_failed_events = self._get_log(log_group_name, start, end) + print(f"ALL FAILEDS {len(all_failed_events)}") + for event in all_failed_events: + actual_event = self.event_to_db_format(event["message"]) + failed_event_set.add(json.dumps(actual_event)) - delivery_receipts = [] - for log in result["results"]: - receipt = {field["field"]: field["value"] for field in log} - delivery_receipts.append(receipt) - return delivery_receipts + return delivered_event_set, failed_event_set diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index d3871c59b..ef338dc4d 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -1,7 +1,20 @@ +import json from datetime import timedelta from flask import current_app -from sqlalchemy import asc, delete, desc, func, or_, select, text, union, update +from sqlalchemy import ( + TIMESTAMP, + asc, + cast, + delete, + desc, + func, + or_, + select, + text, + union, + update, +) from sqlalchemy.orm import joinedload from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.sql import functions @@ -709,8 +722,25 @@ def get_service_ids_with_notifications_on_date(notification_type, date): } -def dao_update_delivery_receipts(receipts): - id_to_status = {r["notification.messageId"]: r["status"] for r in receipts} +def dao_update_delivery_receipts(receipts, delivered): + new_receipts = [] + for r in receipts: + if isinstance(r, str): + r = json.loads(r) + new_receipts.append(r) + + receipts = new_receipts + print(receipts) + + statuses = {} + for r in receipts: + if r["status"].lower() == "success": + statuses[r["notification.messageId"]] = NotificationStatus.DELIVERED + else: + statuses[r["notification.messageId"]] = NotificationStatus.FAILED + + print(f"HERE ARE STATUSES {statuses}") + id_to_carrier = { r["notification.messageId"]: r["delivery.phoneCarrier"] for r in receipts } @@ -719,16 +749,34 @@ def dao_update_delivery_receipts(receipts): } id_to_timestamp = {r["notification.messageId"]: r["@timestamp"] for r in receipts} + status_to_update_with = NotificationStatus.DELIVERED + if not delivered: + status_to_update_with = NotificationStatus.FAILED stmt = ( update(Notification) - .where(Notification.c.message_id.in_(id_to_carrier.keys())) + .where(Notification.message_id.in_(id_to_carrier.keys())) .values( - carrier=case(id_to_carrier), - status=case(id_to_status), - notification_status=case(id_to_status), - sent_at=case(id_to_timestamp), - provider_response=case(id_to_provider_response), + carrier=case( + *[ + (Notification.message_id == key, value) + for key, value in id_to_carrier.items() + ] + ), + status=status_to_update_with, + sent_at=case( + *[ + (Notification.message_id == key, cast(value, TIMESTAMP)) + for key, value in id_to_timestamp.items() + ] + ), + provider_response=case( + *[ + (Notification.message_id == key, value) + for key, value in id_to_provider_response.items() + ] + ), ) ) + print(stmt) db.session.execute(stmt) db.session.commit() From 48c3cebc7235e7b6e5ec7b9956a843def891c39f Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 18 Dec 2024 07:44:24 -0800 Subject: [PATCH 11/31] clean up --- app/celery/scheduled_tasks.py | 62 ++++++++++++++++-------- app/clients/cloudwatch/aws_cloudwatch.py | 11 +++-- app/dao/notifications_dao.py | 11 ----- 3 files changed, 48 insertions(+), 36 deletions(-) diff --git a/app/celery/scheduled_tasks.py b/app/celery/scheduled_tasks.py index b14d50ee5..25e4d5034 100644 --- a/app/celery/scheduled_tasks.py +++ b/app/celery/scheduled_tasks.py @@ -35,7 +35,7 @@ from app.enums import JobStatus, NotificationType from app.models import Job from app.notifications.process_notifications import send_notification_to_queue -from app.utils import hilite, utc_now +from app.utils import utc_now from notifications_utils import aware_utcnow from notifications_utils.clients.zendesk.zendesk_client import NotifySupportTicket @@ -238,23 +238,43 @@ def check_for_services_with_high_failure_rates_or_sending_to_tv_numbers(): zendesk_client.send_ticket_to_zendesk(ticket) -@notify_celery.task(name="process-delivery-receipts") -def process_delivery_receipts(): - print(hilite("ENTER PROCESS DELIVERY RECEIPTS")) - cloudwatch = AwsCloudwatchClient() - cloudwatch.init_app(current_app) - start_time = aware_utcnow() - timedelta(minutes=10) - end_time = aware_utcnow() - delivered_receipts, failed_receipts = cloudwatch.check_delivery_receipts( - start_time, end_time - ) - delivered_receipts = list(delivered_receipts) - batch_size = 100 - for i in range(0, len(delivered_receipts), batch_size): - batch = delivered_receipts[i : i + batch_size] - dao_update_delivery_receipts(batch, True) - failed_receipts = list(failed_receipts) - batch_size = 100 - for i in range(0, len(failed_receipts), batch_size): - batch = failed_receipts[i : i + batch_size] - dao_update_delivery_receipts(batch, False) +@notify_celery.task( + bind=True, max_retries=7, default_retry_delay=3600, name="process-delivery-receipts" +) +def process_delivery_receipts(self): + """ + Every eight minutes or so (see config.py) we run this task, which searches the last ten + minutes of logs for delivery receipts and batch updates the db with the results. The overlap + is intentional. We don't mind re-updating things, it is better than losing data. + + We also set this to retry with exponential backoff in the case of failure. The only way this would + fail is if, for example the db went down, or redis filled causing the app to stop processing. But if + it does fail, we need to go back over at some point when things are running again and process those results. + """ + try: + batch_size = 200 # in theory with postgresql this could be 10k to 20k? + + cloudwatch = AwsCloudwatchClient() + cloudwatch.init_app(current_app) + start_time = aware_utcnow() - timedelta(minutes=10) + end_time = aware_utcnow() + delivered_receipts, failed_receipts = cloudwatch.check_delivery_receipts( + start_time, end_time + ) + delivered_receipts = list(delivered_receipts) + for i in range(0, len(delivered_receipts), batch_size): + batch = delivered_receipts[i : i + batch_size] + dao_update_delivery_receipts(batch, True) + failed_receipts = list(failed_receipts) + for i in range(0, len(failed_receipts), batch_size): + batch = failed_receipts[i : i + batch_size] + dao_update_delivery_receipts(batch, False) + except Exception as ex: + retry_count = self.request.retries + wait_time = 3600 * 2**retry_count + try: + raise self.retry(ex=ex, countdown=wait_time) + except self.MaxRetriesExceededError: + current_app.logger.error( + "Failed process delivery receipts after max retries" + ) diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index d84044943..297052741 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -3,6 +3,7 @@ import re from boto3 import client +from flask import current_app from app.clients import AWS_CLIENT_CONFIG, Client from app.cloudfoundry_config import cloud_config @@ -136,13 +137,13 @@ def event_to_db_format(self, event): # and run this on a schedule. def check_delivery_receipts(self, start, end): region = cloud_config.sns_region - # TODO this clumsy approach to getting the account number will be fixed as part of notify-api #258 account_number = self._extract_account_number(cloud_config.ses_domain_arn) delivered_event_set = set() log_group_name = f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber" - print(hilite(f"LOG GROUP NAME {log_group_name}")) all_delivered_events = self._get_log(log_group_name, start, end) - print(f"ALL DELIVEREDS {len(all_delivered_events)}") + current_app.logger.info( + f"Delivered count {len(all_delivered_events)} over range {start} to {end}" + ) for event in all_delivered_events: actual_event = self.event_to_db_format(event["message"]) @@ -153,7 +154,9 @@ def check_delivery_receipts(self, start, end): f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber/Failure" ) all_failed_events = self._get_log(log_group_name, start, end) - print(f"ALL FAILEDS {len(all_failed_events)}") + current_app.logger.info( + f"Failed count {len(all_delivered_events)} over range {start} to {end}" + ) for event in all_failed_events: actual_event = self.event_to_db_format(event["message"]) failed_event_set.add(json.dumps(actual_event)) diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index ef338dc4d..6ce97b801 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -730,16 +730,6 @@ def dao_update_delivery_receipts(receipts, delivered): new_receipts.append(r) receipts = new_receipts - print(receipts) - - statuses = {} - for r in receipts: - if r["status"].lower() == "success": - statuses[r["notification.messageId"]] = NotificationStatus.DELIVERED - else: - statuses[r["notification.messageId"]] = NotificationStatus.FAILED - - print(f"HERE ARE STATUSES {statuses}") id_to_carrier = { r["notification.messageId"]: r["delivery.phoneCarrier"] for r in receipts @@ -777,6 +767,5 @@ def dao_update_delivery_receipts(receipts, delivered): ), ) ) - print(stmt) db.session.execute(stmt) db.session.commit() From 2c2ee415426e6764fb69ddbfcf745f3ccb97cead Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 18 Dec 2024 07:55:55 -0800 Subject: [PATCH 12/31] add back opt out --- app/clients/cloudwatch/aws_cloudwatch.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index 297052741..0184a4d90 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -74,6 +74,23 @@ def _get_log(self, log_group_name, start, end): break return all_log_events + def warn_if_dev_is_opted_out(self, provider_response, notification_id): + if ( + "is opted out" in provider_response.lower() + or "has blocked sms" in provider_response.lower() + ): + if os.getenv("NOTIFY_ENVIRONMENT") in ["development", "test"]: + ansi_red = "\033[31m" + ansi_reset = "\033[0m" + logline = ( + ansi_red + + f"The phone number for notification_id {notification_id} is OPTED OUT. You need to opt back in" + + ansi_reset + ) + current_app.logger.warning(logline) + return logline + return None + def _extract_account_number(self, ses_domain_arn): account_number = ses_domain_arn.split(":") return account_number From 9d9ce137c4bb6fca3d368873254b89ebf17383b6 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 18 Dec 2024 08:12:44 -0800 Subject: [PATCH 13/31] reduce code --- app/clients/cloudwatch/aws_cloudwatch.py | 29 +- loadtest_10k.csv | 10001 +++++++++++++++++++++ 2 files changed, 10011 insertions(+), 19 deletions(-) create mode 100644 loadtest_10k.csv diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index 0184a4d90..5c34cce4d 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -155,27 +155,18 @@ def event_to_db_format(self, event): def check_delivery_receipts(self, start, end): region = cloud_config.sns_region account_number = self._extract_account_number(cloud_config.ses_domain_arn) - delivered_event_set = set() log_group_name = f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber" - all_delivered_events = self._get_log(log_group_name, start, end) - current_app.logger.info( - f"Delivered count {len(all_delivered_events)} over range {start} to {end}" - ) - - for event in all_delivered_events: - actual_event = self.event_to_db_format(event["message"]) - delivered_event_set.add(json.dumps(actual_event)) - - failed_event_set = set() + delivered_event_set = self._get_receipts(log_group_name, start, end) log_group_name = ( f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber/Failure" ) - all_failed_events = self._get_log(log_group_name, start, end) - current_app.logger.info( - f"Failed count {len(all_delivered_events)} over range {start} to {end}" - ) - for event in all_failed_events: - actual_event = self.event_to_db_format(event["message"]) - failed_event_set.add(json.dumps(actual_event)) - + failed_event_set = self._get_receipts(log_group_name, start, end) return delivered_event_set, failed_event_set + + def _get_receipts(self, log_group_name, start, end): + event_set = set() + all_events = self._get_log(log_group_name, start, end) + for event in all_events: + actual_event = self.event_to_db_format(event["message"]) + event_set.add(json.dumps(actual_event)) + return event_set diff --git a/loadtest_10k.csv b/loadtest_10k.csv new file mode 100644 index 000000000..86b1b5ac1 --- /dev/null +++ b/loadtest_10k.csv @@ -0,0 +1,10001 @@ +phone number ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 ++14254147755 ++14254147167 From 4bd97586b426876b9b51f723e072a08c7b796c80 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 18 Dec 2024 09:06:06 -0800 Subject: [PATCH 14/31] add test --- .../notification_dao/test_notification_dao.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/app/dao/notification_dao/test_notification_dao.py b/tests/app/dao/notification_dao/test_notification_dao.py index e2ac10032..6e09f182a 100644 --- a/tests/app/dao/notification_dao/test_notification_dao.py +++ b/tests/app/dao/notification_dao/test_notification_dao.py @@ -1,6 +1,7 @@ import uuid from datetime import date, datetime, timedelta from functools import partial +from unittest.mock import MagicMock, patch import pytest from freezegun import freeze_time @@ -19,6 +20,7 @@ dao_get_notification_history_by_reference, dao_get_notifications_by_recipient_or_reference, dao_timeout_notifications, + dao_update_delivery_receipts, dao_update_notification, dao_update_notifications_by_reference, get_notification_by_id, @@ -1996,6 +1998,34 @@ def test_notifications_not_yet_sent_return_no_rows(sample_service, notification_ assert len(results) == 0 +def test_update_delivery_receipts(mocker): + mock_session = mocker.patch("app.dao.notifications_dao.db.session") + receipts = [ + '{"notification.messageId": "msg1", "delivery.phoneCarrier": "carrier1", "delivery.providerResponse": "resp1", "@timestamp": "2024-01-01T12:00:00"}', # noqa + '{"notification.messageId": "msg2", "delivery.phoneCarrier": "carrier2", "delivery.providerResponse": "resp2", "@timestamp": "2024-01-01T13:00:00"}', # noqa + ] + delivered = True + mock_update = MagicMock() + mock_where = MagicMock() + mock_values = MagicMock() + mock_update.where.return_value = mock_where + mock_where.values.return_value = mock_values + + mock_session.execute.return_value = None + with patch("app.dao.notifications_dao.update", return_value=mock_update): + dao_update_delivery_receipts(receipts, delivered) + mock_update.where.assert_called_once() + mock_where.values.assert_called_once() + mock_session.execute.assert_called_once_with(mock_values) + mock_session.commit.assert_called_once() + + args, kwargs = mock_where.values.call_args + assert "carrier" in kwargs + assert "status" in kwargs + assert "sent_at" in kwargs + assert "provider_response" in kwargs + + @pytest.mark.parametrize( "created_at_utc,date_to_check,expected_count", [ From 9dc7cfeb2ff41a81bc3a1058f726784bfd48833c Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 20 Dec 2024 07:33:28 -0800 Subject: [PATCH 15/31] code review feedback --- app/celery/scheduled_tasks.py | 2 +- app/clients/cloudwatch/aws_cloudwatch.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/celery/scheduled_tasks.py b/app/celery/scheduled_tasks.py index 25e4d5034..2c31c3f4e 100644 --- a/app/celery/scheduled_tasks.py +++ b/app/celery/scheduled_tasks.py @@ -252,7 +252,7 @@ def process_delivery_receipts(self): it does fail, we need to go back over at some point when things are running again and process those results. """ try: - batch_size = 200 # in theory with postgresql this could be 10k to 20k? + batch_size = 1000 # in theory with postgresql this could be 10k to 20k? cloudwatch = AwsCloudwatchClient() cloudwatch.init_app(current_app) diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index 5c34cce4d..c83fd6313 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -7,7 +7,6 @@ from app.clients import AWS_CLIENT_CONFIG, Client from app.cloudfoundry_config import cloud_config -from app.utils import hilite class AwsCloudwatchClient(Client): @@ -49,7 +48,6 @@ def is_localstack(self): def _get_log(self, log_group_name, start, end): # Check all cloudwatch logs from the time the notification was sent (currently 5 minutes previously) until now - print(hilite(f"START {start} END {end}")) next_token = None all_log_events = [] From 1bac8a82a0280cc644cb26e505131071c3892aa1 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 20 Dec 2024 09:58:03 -0800 Subject: [PATCH 16/31] introduce gaps in message sends --- app/celery/tasks.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/celery/tasks.py b/app/celery/tasks.py index c21f4e65c..77c8fca80 100644 --- a/app/celery/tasks.py +++ b/app/celery/tasks.py @@ -1,4 +1,5 @@ import json +from time import sleep from celery.signals import task_postrun from flask import current_app @@ -75,8 +76,15 @@ def process_job(job_id, sender_id=None): ) ) + # notify-api-1495 we are going to sleep periodically to give other + # jobs running at the same time a chance to get some of their messages + # sent. Sleep for 5 minutes after every 500 sends + count = 0 for row in recipient_csv.get_rows(): process_row(row, template, job, service, sender_id=sender_id) + count = count + 1 + if count % 500 == 0: + sleep(5 * 60) # End point/Exit point for message send flow. job_complete(job, start=start) From 4c5741a82e586b34bded8c19c2cab2114066e100 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 23 Dec 2024 08:03:12 -0800 Subject: [PATCH 17/31] change timing a bit --- app/celery/tasks.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/celery/tasks.py b/app/celery/tasks.py index 77c8fca80..5122688a9 100644 --- a/app/celery/tasks.py +++ b/app/celery/tasks.py @@ -78,13 +78,14 @@ def process_job(job_id, sender_id=None): # notify-api-1495 we are going to sleep periodically to give other # jobs running at the same time a chance to get some of their messages - # sent. Sleep for 5 minutes after every 500 sends + # sent. Sleep for 40 seconds after every 100 sends, which gives us throughput + # of about 9000 per hour and would keep the queue clear assuming only one sender. count = 0 for row in recipient_csv.get_rows(): process_row(row, template, job, service, sender_id=sender_id) count = count + 1 - if count % 500 == 0: - sleep(5 * 60) + if count % 100 == 0: + sleep(40) # End point/Exit point for message send flow. job_complete(job, start=start) From f4442e1ef58601c73f807bd3592f748957e0b378 Mon Sep 17 00:00:00 2001 From: Andrew Shumway Date: Mon, 23 Dec 2024 11:37:36 -0700 Subject: [PATCH 18/31] Update jinja2 to 3.1.5 to address vulnerability --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index debdf9ed9..70b7733e4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -1910,13 +1910,13 @@ trio = ["async_generator", "trio"] [[package]] name = "jinja2" -version = "3.1.4" +version = "3.1.5" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, - {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, + {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, + {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, ] [package.dependencies] @@ -4947,4 +4947,4 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.0" python-versions = "^3.12.2" -content-hash = "cf18ae74630e47eec18cc6c5fea9e554476809d20589d82c54a8d761bb2c3de0" +content-hash = "fec0ba8767be575fa1818a6c396c88d2d447a7a94609b8e8680f4786e257b3d5" diff --git a/pyproject.toml b/pyproject.toml index 99858c09e..82dbab9b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ six = "^1.16.0" urllib3 = "^2.2.2" webencodings = "^0.5.1" itsdangerous = "^2.2.0" -jinja2 = "^3.1.4" +jinja2 = "3.1.5" redis = "^5.0.8" requests = "^2.32.3" From e6e336cdf72d75040ba1e5456b5a711a1d188ad8 Mon Sep 17 00:00:00 2001 From: Andrew Shumway Date: Mon, 23 Dec 2024 11:42:39 -0700 Subject: [PATCH 19/31] Fix dependency syntax --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 82dbab9b2..dc568d89e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ six = "^1.16.0" urllib3 = "^2.2.2" webencodings = "^0.5.1" itsdangerous = "^2.2.0" -jinja2 = "3.1.5" +jinja2 = "^3.1.5" redis = "^5.0.8" requests = "^2.32.3" From 90ce2b2a6598b6b6a4e414f20eeb84dbb9922a91 Mon Sep 17 00:00:00 2001 From: Andrew Shumway Date: Mon, 23 Dec 2024 11:46:14 -0700 Subject: [PATCH 20/31] Poetry lock --no-update command --- poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 70b7733e4..e0096a7de 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4947,4 +4947,4 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.0" python-versions = "^3.12.2" -content-hash = "fec0ba8767be575fa1818a6c396c88d2d447a7a94609b8e8680f4786e257b3d5" +content-hash = "271d8e0f25856f45970e5a9cc3b8871a01b732226ab3ed68ea426912b5117fcf" From 0ab56800299975c89683402d6ce2eb513550044b Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 23 Dec 2024 10:52:46 -0800 Subject: [PATCH 21/31] add expiration to redis --- app/service_invite/rest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/service_invite/rest.py b/app/service_invite/rest.py index 38bc1c404..e375b93a5 100644 --- a/app/service_invite/rest.py +++ b/app/service_invite/rest.py @@ -54,7 +54,7 @@ def _create_service_invite(invited_user, nonce, state): data["invited_user_email"] = invited_user.email_address invite_redis_key = f"invite-data-{unquote(state)}" - redis_store.set(invite_redis_key, get_user_data_url_safe(data)) + redis_store.set(invite_redis_key, get_user_data_url_safe(data), ex=2 * 24 * 60 * 60) url = os.environ["LOGIN_DOT_GOV_REGISTRATION_URL"] From 85c5268eaedf9c15037ba96baf289f04ee6c16b2 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 23 Dec 2024 13:51:21 -0800 Subject: [PATCH 22/31] change to send 3 messages per second --- app/celery/tasks.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/celery/tasks.py b/app/celery/tasks.py index 5122688a9..b2ad5abac 100644 --- a/app/celery/tasks.py +++ b/app/celery/tasks.py @@ -78,14 +78,16 @@ def process_job(job_id, sender_id=None): # notify-api-1495 we are going to sleep periodically to give other # jobs running at the same time a chance to get some of their messages - # sent. Sleep for 40 seconds after every 100 sends, which gives us throughput - # of about 9000 per hour and would keep the queue clear assuming only one sender. + # sent. Sleep for 1 second after every 3 sends, which gives us throughput + # of about 3600*3 per hour and would keep the queue clear assuming only one sender. + # It will also hopefully eliminate throttling when we send messages which we are + # currently seeing. count = 0 for row in recipient_csv.get_rows(): process_row(row, template, job, service, sender_id=sender_id) count = count + 1 - if count % 100 == 0: - sleep(40) + if count % 3 == 0: + sleep(1) # End point/Exit point for message send flow. job_complete(job, start=start) From 05755cb3178c8e1ff0c6a1f27d3a6434d5a3b406 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 23 Dec 2024 14:43:55 -0800 Subject: [PATCH 23/31] fix json structure bug --- app/clients/cloudwatch/aws_cloudwatch.py | 36 ++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index c83fd6313..43bedbb35 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -100,12 +100,20 @@ def event_to_db_format(self, event): if isinstance(event, str): event = json.loads(event) + # Don't trust AWS to always send the same JSON structure back + # However, if we don't get message_id and status we might as well blow up + # because it's pointless to continue + phone_carrier = self._aws_value_or_default(event, "delivery", "phoneCarrier") + provider_response = self._aws_value_or_default( + event, "delivery", "providerResponse" + ) + my_timestamp = self._aws_value_or_default(event, "notification", "timestamp") return { "notification.messageId": event["notification"]["messageId"], "status": event["status"], - "delivery.phoneCarrier": event["delivery"]["phoneCarrier"], - "delivery.providerResponse": event["delivery"]["providerResponse"], - "@timestamp": event["notification"]["timestamp"], + "delivery.phoneCarrier": phone_carrier, + "delivery.providerResponse": provider_response, + "@timestamp": my_timestamp, } # Here is an example of how to get the events with log insights @@ -155,16 +163,34 @@ def check_delivery_receipts(self, start, end): account_number = self._extract_account_number(cloud_config.ses_domain_arn) log_group_name = f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber" delivered_event_set = self._get_receipts(log_group_name, start, end) + current_app.logger.info( + (f"Delivered message count: {len(delivered_event_set)}") + ) log_group_name = ( f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber/Failure" ) failed_event_set = self._get_receipts(log_group_name, start, end) + current_app.logger.info((f"Failed message count: {len(failed_event_set)}")) + return delivered_event_set, failed_event_set def _get_receipts(self, log_group_name, start, end): event_set = set() all_events = self._get_log(log_group_name, start, end) for event in all_events: - actual_event = self.event_to_db_format(event["message"]) - event_set.add(json.dumps(actual_event)) + try: + actual_event = self.event_to_db_format(event["message"]) + event_set.add(json.dumps(actual_event)) + except Exception: + current_app.logger.exception( + f"Could not format delivery receipt {event} for db insert" + ) return event_set + + def _aws_value_or_default(self, event, top_level, second_level): + if event.get(top_level) is None or event[top_level].get(second_level) is None: + my_var = "" + else: + my_var = event[top_level][second_level] + + return my_var From 46ec1aafa88cb800f3f69cef1e72f59a15caeb61 Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Mon, 23 Dec 2024 11:17:51 -0500 Subject: [PATCH 24/31] Getting the IntegrityErrors to be OK if the data already exists in the DB. Signed-off-by: Cliff Hill --- app/celery/tasks.py | 46 ++++++++++++---------- app/dao/notifications_dao.py | 10 +++-- app/notifications/process_notifications.py | 5 +++ 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/app/celery/tasks.py b/app/celery/tasks.py index c21f4e65c..72d23531f 100644 --- a/app/celery/tasks.py +++ b/app/celery/tasks.py @@ -23,6 +23,7 @@ from app.errors import TotalRequestsError from app.notifications.process_notifications import ( get_notification, + notification_exists, persist_notification, ) from app.notifications.validators import check_service_over_total_message_limit @@ -218,22 +219,28 @@ def save_sms(self, service_id, notification_id, encrypted_notification, sender_i job = dao_get_job_by_id(job_id) created_by_id = job.created_by_id - saved_notification = persist_notification( - template_id=notification["template"], - template_version=notification["template_version"], - recipient=notification["to"], - service=service, - personalisation=notification.get("personalisation"), - notification_type=NotificationType.SMS, - api_key_id=None, - key_type=KeyType.NORMAL, - created_at=utc_now(), - created_by_id=created_by_id, - job_id=notification.get("job", None), - job_row_number=notification.get("row_number", None), - notification_id=notification_id, - reply_to_text=reply_to_text, - ) + try: + saved_notification = persist_notification( + template_id=notification["template"], + template_version=notification["template_version"], + recipient=notification["to"], + service=service, + personalisation=notification.get("personalisation"), + notification_type=NotificationType.SMS, + api_key_id=None, + key_type=KeyType.NORMAL, + created_at=utc_now(), + created_by_id=created_by_id, + job_id=notification.get("job", None), + job_row_number=notification.get("row_number", None), + notification_id=notification_id, + reply_to_text=reply_to_text, + ) + except IntegrityError as e: + if notification_exists(notification_id): + saved_notification = get_notification(notification_id) + else: + raise # Kick off sns process in provider_tasks.py sn = saved_notification @@ -247,11 +254,8 @@ def save_sms(self, service_id, notification_id, encrypted_notification, sender_i ) current_app.logger.debug( - "SMS {} created at {} for job {}".format( - saved_notification.id, - saved_notification.created_at, - notification.get("job", None), - ) + f"SMS {saved_notification.id} created at {saved_notification.created_at} " + f"for job {notification.get('job', None)}" ) except SQLAlchemyError as e: diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index 6ce97b801..b9c3118fa 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -65,6 +65,12 @@ def dao_get_last_date_template_was_used(template_id, service_id): return last_date +def dao_notification_exists(notification_id) -> bool: + stmt = select(Notification).where(Notification.id == notification_id) + result = db.session.execute(stmt).scalar() + return result is not None + + @autocommit def dao_create_notification(notification): if not notification.id: @@ -86,9 +92,7 @@ def dao_create_notification(notification): notification.normalised_to = "1" # notify-api-1454 insert only if it doesn't exist - stmt = select(Notification).where(Notification.id == notification.id) - result = db.session.execute(stmt).scalar() - if result is None: + if not dao_notification_exists(notification.id): db.session.add(notification) diff --git a/app/notifications/process_notifications.py b/app/notifications/process_notifications.py index 8568b8894..5f1c6676d 100644 --- a/app/notifications/process_notifications.py +++ b/app/notifications/process_notifications.py @@ -8,6 +8,7 @@ from app.dao.notifications_dao import ( dao_create_notification, dao_delete_notifications_by_id, + dao_notification_exists, get_notification_by_id, ) from app.enums import KeyType, NotificationStatus, NotificationType @@ -153,6 +154,10 @@ def persist_notification( return notification +def notification_exists(notification_id): + return dao_notification_exists(notification_id) + + def send_notification_to_queue_detached( key_type, notification_type, notification_id, queue=None ): From 122195d01040965adf02d8e095c682c03c66614f Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Thu, 26 Dec 2024 08:35:58 -0500 Subject: [PATCH 25/31] flake8 stuff Signed-off-by: Cliff Hill --- app/celery/scheduled_tasks.py | 4 +--- app/celery/tasks.py | 13 +++++-------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/app/celery/scheduled_tasks.py b/app/celery/scheduled_tasks.py index 2c31c3f4e..bb5d80f6f 100644 --- a/app/celery/scheduled_tasks.py +++ b/app/celery/scheduled_tasks.py @@ -174,9 +174,7 @@ def check_for_missing_rows_in_completed_jobs(): for row_to_process in missing_rows: row = recipient_csv[row_to_process.missing_row] current_app.logger.info( - "Processing missing row: {} for job: {}".format( - row_to_process.missing_row, job.id - ) + f"Processing missing row: {row_to_process.missing_row} for job: {job.id}" ) process_row(row, template, job, job.service, sender_id=sender_id) diff --git a/app/celery/tasks.py b/app/celery/tasks.py index 72d23531f..87579f560 100644 --- a/app/celery/tasks.py +++ b/app/celery/tasks.py @@ -39,9 +39,7 @@ def process_job(job_id, sender_id=None): start = utc_now() job = dao_get_job_by_id(job_id) current_app.logger.info( - "Starting process-job task for job id {} with status: {}".format( - job_id, job.job_status - ) + f"Starting process-job task for job id {job_id} with status: {job.job_status}" ) if job.job_status != JobStatus.PENDING: @@ -57,7 +55,7 @@ def process_job(job_id, sender_id=None): job.job_status = JobStatus.CANCELLED dao_update_job(job) current_app.logger.warning( - "Job {} has been cancelled, service {} is inactive".format( + f"Job {job_id} has been cancelled, service {service.id} is inactive".format( job_id, service.id ) ) @@ -71,9 +69,7 @@ def process_job(job_id, sender_id=None): ) current_app.logger.info( - "Starting job {} processing {} notifications".format( - job_id, job.notification_count - ) + f"Starting job {job_id} processing {job.notification_count} notifications" ) for row in recipient_csv.get_rows(): @@ -236,9 +232,10 @@ def save_sms(self, service_id, notification_id, encrypted_notification, sender_i notification_id=notification_id, reply_to_text=reply_to_text, ) - except IntegrityError as e: + except IntegrityError: if notification_exists(notification_id): saved_notification = get_notification(notification_id) + else: raise From 8579efccbcd695bfae82be1abc697d5cd897cef9 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 26 Dec 2024 08:50:26 -0800 Subject: [PATCH 26/31] add placehodler for new test --- tests/app/clients/test_aws_cloudwatch.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/app/clients/test_aws_cloudwatch.py b/tests/app/clients/test_aws_cloudwatch.py index fce0e150c..bb3d36cb0 100644 --- a/tests/app/clients/test_aws_cloudwatch.py +++ b/tests/app/clients/test_aws_cloudwatch.py @@ -87,3 +87,7 @@ def test_extract_account_number_gov_staging(): assert len(actual_account_number) == 6 expected_account_number = "12345" assert actual_account_number[4] == expected_account_number + + +def test_check_delivery_receipts(): + pass From 9f3aec755f1a2ed858a4378401cfbc4f5f5870ed Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 26 Dec 2024 09:23:00 -0800 Subject: [PATCH 27/31] add tests --- tests/app/clients/test_aws_cloudwatch.py | 60 ++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tests/app/clients/test_aws_cloudwatch.py b/tests/app/clients/test_aws_cloudwatch.py index bb3d36cb0..7a0379454 100644 --- a/tests/app/clients/test_aws_cloudwatch.py +++ b/tests/app/clients/test_aws_cloudwatch.py @@ -1,3 +1,5 @@ +import json + import pytest from flask import current_app @@ -91,3 +93,61 @@ def test_extract_account_number_gov_staging(): def test_check_delivery_receipts(): pass + + +def test_aws_value_or_default(): + event = { + "delivery": {"phoneCarrier": "AT&T"}, + "notification": {"timestamp": "2024-01-01T:12:00:00Z"}, + } + assert ( + aws_cloudwatch_client._aws_value_or_default(event, "delivery", "phoneCarrier") + == "AT&T" + ) + assert ( + aws_cloudwatch_client._aws_value_or_default( + event, "delivery", "providerResponse" + ) + == "" + ) + assert ( + aws_cloudwatch_client._aws_value_or_default(event, "notification", "timestamp") + == "2024-01-01T:12:00:00Z" + ) + assert ( + aws_cloudwatch_client._aws_value_or_default(event, "nonexistent", "field") == "" + ) + + +def test_event_to_db_format_with_missing_fields(): + event = { + "notification": {"messageId": "12345"}, + "status": "UNKNOWN", + "delivery": {}, + } + result = aws_cloudwatch_client.event_to_db_format(event) + assert result == { + "notification.messageId": "12345", + "status": "UNKNOWN", + "delivery.phoneCarrier": "", + "delivery.providerResponse": "", + "@timestamp": "", + } + + +def test_event_to_db_format_with_string_input(): + event = json.dumps( + { + "notification": {"messageId": "67890", "timestamp": "2024-01-01T14:00:00Z"}, + "status": "FAILED", + "delivery": {"phoneCarrier": "Verizon", "providerResponse": "Error"}, + } + ) + result = aws_cloudwatch_client.event_to_db_format(event) + assert result == { + "notification.messageId": "67890", + "status": "FAILED", + "delivery.phoneCarrier": "Verizon", + "delivery.providerResponse": "Error", + "@timestamp": "2024-01-01T14:00:00Z", + } From f1e8ff3328e3868becc072eeaa3c907af63006d4 Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Fri, 27 Dec 2024 12:17:44 -0500 Subject: [PATCH 28/31] Fixing IntegrityError problems, again. Signed-off-by: Cliff Hill --- app/celery/tasks.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/app/celery/tasks.py b/app/celery/tasks.py index cbb9e22b6..0e36d6c84 100644 --- a/app/celery/tasks.py +++ b/app/celery/tasks.py @@ -214,9 +214,7 @@ def save_sms(self, service_id, notification_id, encrypted_notification, sender_i f"service not allowed to send for job_id {notification.get('job', None)}, aborting" ) ) - current_app.logger.debug( - "SMS {} failed as restricted service".format(notification_id) - ) + current_app.logger.debug(f"SMS {notification_id} failed as restricted service") return try: @@ -244,11 +242,12 @@ def save_sms(self, service_id, notification_id, encrypted_notification, sender_i reply_to_text=reply_to_text, ) except IntegrityError: - if notification_exists(notification_id): - saved_notification = get_notification(notification_id) - - else: - raise + current_app.logger.warning( + f"{NotificationType.SMS}: {notification_id} already exists." + ) + # If we don't have the return statement here, we will fall through and end + # up retrying because IntegrityError is a subclass of SQLAlchemyError + return # Kick off sns process in provider_tasks.py sn = saved_notification From e2413bac76dbda6f41059f0cf01580d37129078e Mon Sep 17 00:00:00 2001 From: Cliff Hill Date: Fri, 27 Dec 2024 12:21:43 -0500 Subject: [PATCH 29/31] Flake8 fixes. Signed-off-by: Cliff Hill --- app/celery/tasks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/celery/tasks.py b/app/celery/tasks.py index 0e36d6c84..3743aa294 100644 --- a/app/celery/tasks.py +++ b/app/celery/tasks.py @@ -24,7 +24,6 @@ from app.errors import TotalRequestsError from app.notifications.process_notifications import ( get_notification, - notification_exists, persist_notification, ) from app.notifications.validators import check_service_over_total_message_limit From 85a55dbaed9cbfcf5b5a72b6034f063409fc6990 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 27 Dec 2024 10:13:28 -0800 Subject: [PATCH 30/31] change time range for incomplete jobs --- app/celery/scheduled_tasks.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/celery/scheduled_tasks.py b/app/celery/scheduled_tasks.py index bb5d80f6f..3a3fa696e 100644 --- a/app/celery/scheduled_tasks.py +++ b/app/celery/scheduled_tasks.py @@ -100,27 +100,29 @@ def check_job_status(): select from jobs where job_status == 'in progress' - and processing started between 30 and 35 minutes ago + and processing started some time ago OR where the job_status == 'pending' - and the job scheduled_for timestamp is between 30 and 35 minutes ago. + and the job scheduled_for timestamp is some time ago. if any results then update the job_status to 'error' process the rows in the csv that are missing (in another task) just do the check here. """ - thirty_minutes_ago = utc_now() - timedelta(minutes=30) - thirty_five_minutes_ago = utc_now() - timedelta(minutes=35) + START_MINUTES = 245 + END_MINUTES = 240 + end_minutes_ago = utc_now() - timedelta(minutes=END_MINUTES) + start_minutes_ago = utc_now() - timedelta(minutes=START_MINUTES) incomplete_in_progress_jobs = Job.query.filter( Job.job_status == JobStatus.IN_PROGRESS, - between(Job.processing_started, thirty_five_minutes_ago, thirty_minutes_ago), + between(Job.processing_started, start_minutes_ago, end_minutes_ago), ) incomplete_pending_jobs = Job.query.filter( Job.job_status == JobStatus.PENDING, Job.scheduled_for.isnot(None), - between(Job.scheduled_for, thirty_five_minutes_ago, thirty_minutes_ago), + between(Job.scheduled_for, start_minutes_ago, end_minutes_ago), ) - jobs_not_complete_after_30_minutes = ( + jobs_not_complete_after_allotted_time = ( incomplete_in_progress_jobs.union(incomplete_pending_jobs) .order_by(Job.processing_started, Job.scheduled_for) .all() @@ -129,7 +131,7 @@ def check_job_status(): # temporarily mark them as ERROR so that they don't get picked up by future check_job_status tasks # if they haven't been re-processed in time. job_ids = [] - for job in jobs_not_complete_after_30_minutes: + for job in jobs_not_complete_after_allotted_time: job.job_status = JobStatus.ERROR dao_update_job(job) job_ids.append(str(job.id)) From 152496fc91d83f56010afb9438d03ab404c8285e Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 27 Dec 2024 10:28:08 -0800 Subject: [PATCH 31/31] fix tests --- tests/app/celery/test_scheduled_tasks.py | 70 ++++++++++++++---------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/tests/app/celery/test_scheduled_tasks.py b/tests/app/celery/test_scheduled_tasks.py index ae9ea571d..f436aacf2 100644 --- a/tests/app/celery/test_scheduled_tasks.py +++ b/tests/app/celery/test_scheduled_tasks.py @@ -23,6 +23,8 @@ from tests.app import load_example_csv from tests.app.db import create_job, create_notification, create_template +CHECK_JOB_STATUS_TOO_OLD_MINUTES = 241 + def test_should_call_delete_codes_on_delete_verify_codes_task( notify_db_session, mocker @@ -108,8 +110,9 @@ def test_check_job_status_task_calls_process_incomplete_jobs(mocker, sample_temp job = create_job( template=sample_template, notification_count=3, - created_at=utc_now() - timedelta(minutes=31), - processing_started=utc_now() - timedelta(minutes=31), + created_at=utc_now() - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), + processing_started=utc_now() + - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), job_status=JobStatus.IN_PROGRESS, ) create_notification(template=sample_template, job=job) @@ -125,9 +128,10 @@ def test_check_job_status_task_calls_process_incomplete_jobs_when_scheduled_job_ job = create_job( template=sample_template, notification_count=3, - created_at=utc_now() - timedelta(hours=2), - scheduled_for=utc_now() - timedelta(minutes=31), - processing_started=utc_now() - timedelta(minutes=31), + created_at=utc_now() - timedelta(hours=5), + scheduled_for=utc_now() - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), + processing_started=utc_now() + - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), job_status=JobStatus.IN_PROGRESS, ) check_job_status() @@ -142,8 +146,8 @@ def test_check_job_status_task_calls_process_incomplete_jobs_for_pending_schedul job = create_job( template=sample_template, notification_count=3, - created_at=utc_now() - timedelta(hours=2), - scheduled_for=utc_now() - timedelta(minutes=31), + created_at=utc_now() - timedelta(hours=5), + scheduled_for=utc_now() - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), job_status=JobStatus.PENDING, ) @@ -175,17 +179,19 @@ def test_check_job_status_task_calls_process_incomplete_jobs_for_multiple_jobs( job = create_job( template=sample_template, notification_count=3, - created_at=utc_now() - timedelta(hours=2), - scheduled_for=utc_now() - timedelta(minutes=31), - processing_started=utc_now() - timedelta(minutes=31), + created_at=utc_now() - timedelta(hours=5), + scheduled_for=utc_now() - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), + processing_started=utc_now() + - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), job_status=JobStatus.IN_PROGRESS, ) job_2 = create_job( template=sample_template, notification_count=3, - created_at=utc_now() - timedelta(hours=2), - scheduled_for=utc_now() - timedelta(minutes=31), - processing_started=utc_now() - timedelta(minutes=31), + created_at=utc_now() - timedelta(hours=5), + scheduled_for=utc_now() - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), + processing_started=utc_now() + - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), job_status=JobStatus.IN_PROGRESS, ) check_job_status() @@ -200,23 +206,24 @@ def test_check_job_status_task_only_sends_old_tasks(mocker, sample_template): job = create_job( template=sample_template, notification_count=3, - created_at=utc_now() - timedelta(hours=2), - scheduled_for=utc_now() - timedelta(minutes=31), - processing_started=utc_now() - timedelta(minutes=31), + created_at=utc_now() - timedelta(hours=5), + scheduled_for=utc_now() - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), + processing_started=utc_now() + - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), job_status=JobStatus.IN_PROGRESS, ) create_job( template=sample_template, notification_count=3, - created_at=utc_now() - timedelta(minutes=31), - processing_started=utc_now() - timedelta(minutes=29), + created_at=utc_now() - timedelta(minutes=300), + processing_started=utc_now() - timedelta(minutes=239), job_status=JobStatus.IN_PROGRESS, ) create_job( template=sample_template, notification_count=3, - created_at=utc_now() - timedelta(minutes=50), - scheduled_for=utc_now() - timedelta(minutes=29), + created_at=utc_now() - timedelta(minutes=300), + scheduled_for=utc_now() - timedelta(minutes=239), job_status=JobStatus.PENDING, ) check_job_status() @@ -230,16 +237,17 @@ def test_check_job_status_task_sets_jobs_to_error(mocker, sample_template): job = create_job( template=sample_template, notification_count=3, - created_at=utc_now() - timedelta(hours=2), - scheduled_for=utc_now() - timedelta(minutes=31), - processing_started=utc_now() - timedelta(minutes=31), + created_at=utc_now() - timedelta(hours=5), + scheduled_for=utc_now() - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), + processing_started=utc_now() + - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), job_status=JobStatus.IN_PROGRESS, ) job_2 = create_job( template=sample_template, notification_count=3, - created_at=utc_now() - timedelta(minutes=31), - processing_started=utc_now() - timedelta(minutes=29), + created_at=utc_now() - timedelta(minutes=300), + processing_started=utc_now() - timedelta(minutes=239), job_status=JobStatus.IN_PROGRESS, ) check_job_status() @@ -311,16 +319,18 @@ def test_check_job_status_task_does_not_raise_error(sample_template): create_job( template=sample_template, notification_count=3, - created_at=utc_now() - timedelta(hours=2), - scheduled_for=utc_now() - timedelta(minutes=31), - processing_started=utc_now() - timedelta(minutes=31), + created_at=utc_now() - timedelta(hours=5), + scheduled_for=utc_now() - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), + processing_started=utc_now() + - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), job_status=JobStatus.FINISHED, ) create_job( template=sample_template, notification_count=3, - created_at=utc_now() - timedelta(minutes=31), - processing_started=utc_now() - timedelta(minutes=31), + created_at=utc_now() - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), + processing_started=utc_now() + - timedelta(minutes=CHECK_JOB_STATUS_TOO_OLD_MINUTES), job_status=JobStatus.FINISHED, )