From 67615f364c3c6615eeb5a63ae22e70681ca83696 Mon Sep 17 00:00:00 2001 From: = <=> Date: Mon, 1 Sep 2025 20:19:11 -0400 Subject: [PATCH] Memory Optimization Draft one complete --- AirlockTools.py | 450 ++++++++++++------ ...proved_hashes_Developers_Dev Audit.parquet | Bin 0 -> 25163 bytes ...es_with_paths_Developers_Dev Audit.parquet | Bin 0 -> 26334 bytes ...ined_hashlist_Developers_Dev Audit.parquet | Bin 0 -> 23689 bytes ...ed_executions_Developers_Dev Audit.parquet | Bin 0 -> 27087 bytes parquet/execution_history_Dev Audit.parquet | Bin 0 -> 374 bytes parquet/execution_history_Developers.parquet | Bin 0 -> 28023 bytes ...ashes_rep_bad_Developers_Dev Audit.parquet | Bin 0 -> 15725 bytes ...shes_rep_good_Developers_Dev Audit.parquet | Bin 0 -> 23459 bytes ...s_rep_unknown_Developers_Dev Audit.parquet | Bin 0 -> 7325 bytes ...eeds_approved_Developers_Dev Audit.parquet | Bin 0 -> 3514 bytes utils/hashfunctions.py | 47 +- utils/pathfunctions.py | 26 + utils/pretty.py | 75 +++ 14 files changed, 440 insertions(+), 158 deletions(-) create mode 100644 parquet/all_approved_hashes_Developers_Dev Audit.parquet create mode 100644 parquet/approved_hashes_with_paths_Developers_Dev Audit.parquet create mode 100644 parquet/combined_hashlist_Developers_Dev Audit.parquet create mode 100644 parquet/condensed_executions_Developers_Dev Audit.parquet create mode 100644 parquet/execution_history_Dev Audit.parquet create mode 100644 parquet/execution_history_Developers.parquet create mode 100644 parquet/hashes_rep_bad_Developers_Dev Audit.parquet create mode 100644 parquet/hashes_rep_good_Developers_Dev Audit.parquet create mode 100644 parquet/hashes_rep_unknown_Developers_Dev Audit.parquet create mode 100644 parquet/path_needs_approved_Developers_Dev Audit.parquet diff --git a/AirlockTools.py b/AirlockTools.py index 182e0f7..a1e7860 100644 --- a/AirlockTools.py +++ b/AirlockTools.py @@ -14,6 +14,7 @@ # along with this program. If not, see . import dotenv +import gc import json import os import pandas as pd @@ -32,23 +33,13 @@ dotenv.load_dotenv() #Constants url = os.getenv('url') badpublisherlist = ["Brave Software, Inc.", "Zoom Video Communications, Inc."] +badpathparts = ["users", "inet\\wwwroot", "windows\\temp", "windows\\temp", "windows\\task", "windows\\system32", "startup", "windows\\fonts", "Recycle.Bin", "AppData", "programdata"] path_exclusion_constant = 3 min_files_for_path = 4 threat_tolerance_constant = 4 def apivalidation(): - print(ct.colorText(r""" - _____ .__ .__ __ ___________ .__ - / _ \ |__|______| | ____ ____ | | __ \__ ___/___ ____ | | ______ - / /_\ \| \_ __ \ | / _ \_/ ___\| |/ / | | / _ \ / _ \| | / ___/ -/ | \ || | \/ |_( <_> ) \___| < | |( <_> | <_> ) |__\___ \ -\____|__ /__||__| |____/\____/ \___ >__|_ \ |____| \____/ \____/|____/____ > - \/ \/ \/ \/ -""", "cyan")) - print(ct.colorText("=================================================================================", "cyan")) - print(ct.colorText("======================== Welcome to the Airlock API Tool ========================", "cyan")) - print(ct.colorText("=================================================================================", "cyan")) match os.getenv('APIKEY'): case '': print(ct.colorText("Please add your API Key to the .env file", "red")) @@ -67,11 +58,25 @@ def tryToReadCSV(csv): df = pd.DataFrame() # Create an empty DataFrame as fallback return df +def tryToReadParquet(parquet): + try: + df = pd.read_parquet(parquet) + if df.empty: + print(ct.colorText("Error: Parquet file has headers but no data rows.", "red")) + else: + print(ct.colorText(f"Data loaded successfully from {parquet}", "green")) + except pd.errors.EmptyDataError: + print(ct.colorText("Notice : Parquet file is completely empty (no headers, no data), falling back to empty frame", "white")) + df = pd.DataFrame() # Create an empty DataFrame as fallback + return df + +def deduplicate_list(lst): + seen = set() + return [x for x in lst if not (x in seen or seen.add(x))] + def menu_main(): while True: - print(ct.colorText("\n-----------------------------------", "magenta")) - print(ct.colorText("------------ Main Menu ------------", "magenta")) - print(ct.colorText("-----------------------------------", "magenta")) + ct.displayIntro(); print(ct.colorText("1. Get All Events for Single Device", "yellow")) print(ct.colorText("2. Placeholder for Local Approval", "yellow")) print(ct.colorText("3. Placeholder for Another Tool", "yellow")) @@ -138,9 +143,9 @@ def menu_prepare_to_enforce(): df_aggregated_combo = pd.DataFrame() #If the directorys where we're going to store our output dont exist, make them. - if not os.path.exists("dataframe_html"): os.makedirs("dataframe_html") - if not os.path.exists("dataframe_csv"): os.makedirs("dataframe_csv") - if not os.path.exists("manuallyapproved"): os.makedirs("manuallyapproved") + if not os.path.exists("parquet"): os.makedirs("parquet") + if not os.path.exists("needs_approved"): os.makedirs("needs_approved") + if not os.path.exists("approved"): os.makedirs("approved") if not os.path.exists("preflight"): os.makedirs("preflight") while True: @@ -163,54 +168,55 @@ def menu_prepare_to_enforce(): print(ct.colorText("2. Pulls and stages event history, combines the histories, adds hash info, then categorizes the hashes", "cyan")) - if os.path.exists(f"dataframe_csv\\executionhist_{first_policy}.csv"): + if os.path.exists(f"parquet\\execution_history_{first_policy}.parquet"): print(ct.colorText(f" [✓] Execution history has been compiled for {first_policy}","green")) - elif not os.path.exists(f"dataframe_csv\\executionhist_{first_policy}.csv"): + elif not os.path.exists(f"parquet\\execution_history_{first_policy}.parquet"): print(ct.colorText(f" [✗] Execution history has not been compiled for {first_policy}","red")) - elif second_policy is not first_policy and os.path.exists(f"dataframe_csv\\executionhist_{second_policy}.csv"): + elif second_policy is not first_policy and os.path.exists(f"parquet\\execution_history_{second_policy}.parquet"): print(ct.colorText(f" [✓] Execution history has been compiled for {second_policy}","green")) - elif second_policy is not first_policy and not os.path.exists(f"dataframe_csv\\executionhist_{second_policy}.csv"): + elif second_policy is not first_policy and not os.path.exists(f"parquet\\execution_history_{second_policy}.parquet"): print(ct.colorText(f" [✗] Execution history has not been compiled for {second_policy}","red")) - if os.path.exists(f"dataframe_csv\\execuctionhist_combined_{first_policy}_{second_policy}.csv"): - print(ct.colorText(f" [✓] Execution history has been_combined_for {first_policy} and_{second_policy}", "green")) - else: - print(ct.colorText(f" [✗] Execution history has not been_combined_for {first_policy} and_{second_policy}", "red")) - - if os.path.exists(f"dataframe_csv\\augmented_combo_{first_policy}_{second_policy}.csv"): + if os.path.exists(f"parquet\\combined_hashlist_{first_policy}_{second_policy}.parquet"): print(ct.colorText(f" [✓] Hash Info has been added to the combined execution history", "green")) else: print(ct.colorText(f" [✗] Hash Info has not been added to the combined execution history", "red")) - if os.path.exists(f"dataframe_csv\\hashes_needing_approval_{first_policy}_{second_policy}.csv") and os.path.exists(f"dataframe_csv\\automatically_approved_hashes_{first_policy}_{second_policy}.csv") and os.path.exists(f"dataframe_csv\\unapproved_hashes__{first_policy}_{second_policy}.csv"): + if os.path.exists(f"parquet\\hashes_rep_unknown_{first_policy}_{second_policy}.parquet") and os.path.exists(f"parquet\\hashes_rep_good_{first_policy}_{second_policy}.parquet") and os.path.exists(f"parquet\\hashes_rep_bad_{first_policy}_{second_policy}.parquet"): print(ct.colorText(f" [✓] Hashes have been cateogrized", "green")) else: print(ct.colorText(f" [✗] Hashes have not been cateogrized", "red")) + if os.path.exists(f"parquet\\condensed_executions_{first_policy}_{second_policy}.parquet"): + print(ct.colorText(f" [✓] Execution history has been_combined_for {first_policy} and_{second_policy}", "green")) + else: + print(ct.colorText(f" [✗] Execution history has not been_combined_for {first_policy} and_{second_policy}", "red")) + + print(ct.colorText(f"3. Manually review the files:","cyan")) - print(ct.colorText(" '\\dataframe_csv\\hashes_needing_approval_{first_policy}_{second_policy}.csv' and 'dataframe_csv\\automatically_approved_hashes_{first_policy}_{second_policy}.csv'", "cyan")) + print(ct.colorText(" 'needs_approved\\hashes_rep_good_{first_policy}_{second_policy}.csv' and 'needs_approved\\hashes_rep_unknown_{first_policy}_{second_policy}.csv'", "cyan")) print(ct.colorText(" Remove the rows containing hashes you do not approve of, and those you would not approve of without metarules.", "cyan")) print(ct.colorText(" If metarules need to be created, please make note of them, and remove the row from the csv.", "cyan")) - print(ct.colorText(" When complete, save both csv files to the directory 'manuallyapproved' and choose this option.","cyan")) + print(ct.colorText(" When complete, save both csv files to the directory 'approved' and choose this option.","cyan")) print(ct.colorText(" This will combine these approved hashes with the automatically approved hashes and generate a list of paths to be reviewed", "cyan")) - if os.path.exists(f"manuallyapproved\\hashes_needing_approval_{first_policy}_{second_policy}.csv") and os.path.exists(f"manuallyapproved\\automatically_approved_hashes_{first_policy}_{second_policy}.csv"): + if os.path.exists(f"approved\\hashes_rep_good_{first_policy}_{second_policy}.csv") and os.path.exists(f"approved\\hashes_rep_unknown_{first_policy}_{second_policy}.csv"): print(ct.colorText(" [✓] Reviewed hashes have been loaded","green")) else: print(ct.colorText(" [✗] Reviewed hashes have not been loaded","red")) - if os.path.exists(f"dataframe_csv\\all_approved_hashes_{first_policy}_{second_policy}.csv"): + if os.path.exists(f"parquet\\all_approved_hashes_{first_policy}_{second_policy}.parquet"): print(ct.colorText(" [✓] The combined approved hashes list has been generated","green")) else: print(ct.colorText(" [✗] The combined approved hashes list has not been generated","red")) - if os.path.exists(f"dataframe_csv\\allinfo_{first_policy}_{second_policy}.csv"): + if os.path.exists(f"parquet\\approved_hashes_with_paths_{first_policy}_{second_policy}.parquet"): print(ct.colorText(" [✓] Longest common filepaths have been generated and appended to hash info","green")) else: print(ct.colorText(" [✗] Longest common filepaths have not been generated","red")) - if os.path.exists(f"dataframe_html\\lcf_needs_appoved_{first_policy}_{second_policy}.html"): + if os.path.exists(f"needs_approved\\path_needs_approved_{first_policy}_{second_policy}.csv"): print(ct.colorText(" [✓] Path review list created","green")) else: print(ct.colorText(" [✗] Path review list has not been created","red")) @@ -218,20 +224,20 @@ def menu_prepare_to_enforce(): print(ct.colorText(f"4. Manually review the file 'paths_needing_review_{first_policy}_{second_policy}.csv'", "cyan")) print(ct.colorText(" Remove the rows containing path exclusions you do not approve of" , "cyan")) - print(ct.colorText(" When complete, save the csv file to the directory 'manuallyapproved'", "cyan")) + print(ct.colorText(" When complete, save the csv file to the directory 'approved'", "cyan")) print(ct.colorText(" Preflight Lists will be generated", "cyan")) - if os.path.exists(f"manuallyapproved\\lcf_needs_approved_{first_policy}_{second_policy}.csv"): + if os.path.exists(f"approved\\path_needs_approved_{first_policy}_{second_policy}.csv"): print(ct.colorText(" [✓] Reviewed path list detected","green")) else: print(ct.colorText(" [✗] Path review list has not been detected","red")) - if os.path.exists(f"preflight\\final_path_exclusions_{first_policy}_{second_policy}.csv"): + if os.path.exists(f"preflight\\final_path_exclusions_{first_policy}_{second_policy}.html"): print(ct.colorText(" [✓] Preflight Path Exclusion List has been generated","green")) else: print(ct.colorText(" [✗] Preflight Path Exclusion List has not been generated","red")) - if os.path.exists(f"preflight\\final_hash_approvals_{first_policy}_{second_policy}.csv"): + if os.path.exists(f"preflight\\final_hash_approvals_{first_policy}_{second_policy}.html"): print(ct.colorText(" [✓] Preflight hash approval list has been generated","green")) else: print(ct.colorText(" [✗] Preflight hash approval list has not been generated","red")) @@ -277,114 +283,262 @@ def menu_prepare_to_enforce(): print(ct.colorText("Please answer with 'yes' or 'no'.", "red")) elif choice == "2": - - if not os.path.exists(f"dataframe_csv\\executionhist_{first_policy}.csv"): + + if not os.path.exists(f"parquet\\execution_history_{first_policy}.parquet"): print(choice) print(first_policy) - - exe1 = utils.allowlist.pullPolicyExechistories(url, choice, first_policy ,True) + exe1 = utils.allowlist.pullPolicyExechistories(url, choice, first_policy, True) data = json.loads(exe1) executionhist_policy1 = pd.DataFrame(data["response"]["exechistories"]) - - if not executionhist_policy1.empty: - executionhist_policy1 = executionhist_policy1.sort_values(by=['sha256','filename']) - executionhist_policy1.to_csv(f"dataframe_csv\\executionhist_{first_policy}.csv", index=False) - ct.style_dataframe_dark(executionhist_policy1, f"dataframe_html\\executionhist_{first_policy}.html") - print(ct.colorText(f"Staging of Execution history for policy: {first_policy} is complete","green")) - - if not os.path.exists(f"dataframe_csv\\executionhist_{second_policy}.csv"): - exe2 = utils.allowlist.pullPolicyExechistories(url,choice, second_policy,True) + if not executionhist_policy1.empty: + executionhist_policy1 = executionhist_policy1[['sha256', 'publisher', 'filename', 'hostname', 'username', 'pprocess', 'gprocess', 'commandline']] + executionhist_policy1 = executionhist_policy1.drop_duplicates(subset=['sha256', 'filename', 'hostname']) + executionhist_policy1 = executionhist_policy1.sort_values(by=['sha256', 'filename']) + + executionhist_policy1.to_parquet(f"parquet\\execution_history_{first_policy}.parquet", index=False) + print(ct.colorText(f"Staging of Execution history for policy: {first_policy} is complete", "green")) + + del executionhist_policy1 + gc.collect() + + if not os.path.exists(f"parquet\\execution_history_{second_policy}.parquet"): + exe2 = utils.allowlist.pullPolicyExechistories(url, choice, second_policy, True) data2 = json.loads(exe2) executionhist_policy2 = pd.DataFrame(data2["response"]["exechistories"]) - + if not executionhist_policy2.empty: - executionhist_policy2 = executionhist_policy2.sort_values(by=['sha256','filename']) - - executionhist_policy2.to_csv(f"dataframe_csv\\executionhist_{second_policy}.csv", index=False) - ct.style_dataframe_dark(executionhist_policy2, f"dataframe_html\\executionhist_{second_policy}.html") - print(ct.colorText(f"Staging of Exection history for policy: {first_policy} is complete","green")) + executionhist_policy2 = executionhist_policy2[['sha256', 'publisher', 'filename', 'hostname', 'username', 'pprocess', 'gprocess', 'commandline']] + executionhist_policy2 = executionhist_policy2.drop_duplicates(subset=['sha256', 'filename', 'hostname']) + executionhist_policy2 = executionhist_policy2.sort_values(by=['sha256', 'filename']) - #Combine the two policies execution histories + executionhist_policy2.to_parquet(f"parquet\\execution_history_{second_policy}.parquet", index=False) + print(ct.colorText(f"Staging of Execution history for policy: {second_policy} is complete", "green")) + + del executionhist_policy2 + gc.collect() + + if not os.path.exists(f"parquet\\combined_hashlist_{first_policy}_{second_policy}.parquet"): + combined_hashes = pd.DataFrame(columns=['sha256', 'publisher']) + hashes = [] + + try: + hash1 = pd.read_parquet(f"parquet\\execution_history_{first_policy}.parquet", columns=['sha256', 'publisher']) + utils.pathfunctions.inspect_parquet(f"parquet\\execution_history_{first_policy}.parquet") + if not hash1.empty: + hashes.append(hash1) + else: + print("⚠️ First dataframe is empty.") + except Exception as e: + print(f"❌ Error reading first Parquet file: {e}") + + try: + hash2 = pd.read_parquet(f"parquet\\execution_history_{second_policy}.parquet", columns=['sha256', 'publisher']) + utils.pathfunctions.inspect_parquet(f"parquet\\execution_history_{second_policy}.parquet") + if not hash2.empty: + hashes.append(hash2) + else: + print("⚠️ Second dataframe is empty.") + except Exception as e: + print(f"❌ Error reading second Parquet file: {e}") + + if hashes: + combined_hashes = pd.concat(hashes, ignore_index=True) + print(f"✅ Combined {len(combined_hashes)} hashes.") + else: + print("⚠️ No valid dataframes to combine.") + + combined_hashes = combined_hashes.drop_duplicates(subset=['sha256']) + augmented_combo = utils.hashfunctions.augmentAggregatedHashes(url, combined_hashes) + + numeric_reputation_cols = [ + 'reputation_scannermatch', + 'reputation_scannercount', + 'reputation_threatlevel' + ] + + for col in numeric_reputation_cols: + if col in augmented_combo.columns: + augmented_combo[col] = pd.to_numeric(augmented_combo[col].replace('N/A', pd.NA), errors='coerce') + + augmented_combo = augmented_combo.rename(columns={'publisher_x': 'publisher'}) + augmented_combo = augmented_combo[['sha256', 'publisher', 'description', 'productname', 'productversion', + 'reputation_lastseen', 'reputation_scannermatch', 'reputation_scannercount', + 'reputation_status', 'reputation_threatlevel', 'reputation_threatname', + 'reputation_timestamp']] + augmented_combo = augmented_combo.sort_values(by=['publisher', 'description', 'productname']) + augmented_combo.to_parquet(f"parquet\\combined_hashlist_{first_policy}_{second_policy}.parquet", index=False) + + del combined_hashes + del augmented_combo + gc.collect() + + print(ct.colorText("Hash reputation info added to dataframe", "green")) + + if not os.path.exists(f"parquet\\hashes_rep_unknown_{first_policy}_{second_policy}.parquet") and not os.path.exists(f"parquet\\hashes_rep_good_{first_policy}_{second_policy}.parquet") and not os.path.exists(f"parquet\\hashes_rep_bad_{first_policy}_{second_policy}.parquet"): + + # Categorize the hashes + categorized = utils.hashfunctions.categorizeHashes( + pd.read_parquet(f"parquet\\combined_hashlist_{first_policy}_{second_policy}.parquet"), + threat_tolerance_constant, + badpublisherlist + ) + + categorized[0].to_parquet(f"parquet\\hashes_rep_unknown_{first_policy}_{second_policy}.parquet", index=False) + categorized[1].to_parquet(f"parquet\\hashes_rep_good_{first_policy}_{second_policy}.parquet", index=False) + categorized[2].to_parquet(f"parquet\\hashes_rep_bad_{first_policy}_{second_policy}.parquet", index=False) + + del categorized + gc.collect() - if second_policy is first_policy: - execuctionhist_combined = executionhist_policy1 - execuctionhist_combined.to_csv(f"dataframe_csv\\execuctionhist_combined_{first_policy}_{second_policy}.csv", index=False) - ct.style_dataframe_dark(df_aggregated_combo, f"dataframe_html\\execuctionhist_combined_{first_policy}_{second_policy}.html") - print(ct.colorText(f"Dataframes have been combined","green")) + if not os.path.exists(f"parquet\\condensed_executions_{first_policy}_{second_policy}.parquet"): + # Condense execution history + try: + exe1 = pd.read_parquet(f"parquet\\execution_history_{first_policy}.parquet") + utils.pathfunctions.inspect_parquet(f"parquet\\execution_history_{first_policy}.parquet") + if not exe1.empty: + condensed_exe1 = exe1.groupby('sha256').agg(lambda x: list(set(x))).reset_index() + else: + print("⚠️ First dataframe is empty.") + except Exception as e: + print(f"❌ Error reading first Parquet file: {e}") - elif os.path.exists(f"dataframe_csv\\executionhist_{first_policy}.csv") and os.path.exists(f"dataframe_csv\\executionhist_{second_policy}.csv"): - execuctionhist_combined = pd.concat([tryToReadCSV(f"dataframe_csv\\executionhist_{first_policy}.csv") , tryToReadCSV(f"dataframe_csv\\executionhist_{second_policy}.csv")], ignore_index=True).sort_values(by=['sha256','filename']) - execuctionhist_combined.to_csv(f"dataframe_csv\\execuctionhist_combined_{first_policy}_{second_policy}.csv", index=False) - ct.style_dataframe_dark(df_aggregated_combo, f"dataframe_html\\execuctionhist_combined_{first_policy}_{second_policy}.html") - print(ct.colorText(f"Dataframes have been combined","green")) + try: + exe2 = pd.read_parquet(f"parquet\\execution_history_{second_policy}.parquet") + utils.pathfunctions.inspect_parquet(f"parquet\\execution_history_{second_policy}.parquet") + if not exe2.empty: + condensed_exe2 = exe2.groupby('sha256').agg(lambda x: list(set(x))).reset_index() + else: + print("⚠️ Second dataframe is empty.") + except Exception as e: + print(f"❌ Error reading second Parquet file: {e}") - #Keep only unique combinations of hash, filename, and hostname - if f"dataframe_csv\\execuctionhist_combined_{first_policy}_{second_policy}.csv": - unique_executions = tryToReadCSV(f"dataframe_csv\\execuctionhist_combined_{first_policy}_{second_policy}.csv").drop_duplicates(subset=['sha256', 'filename', 'hostname']) - unique_executions.to_csv(f"dataframe_csv\\unique_executions{first_policy}_{second_policy}.csv") - ct.style_dataframe_dark(unique_executions, f"dataframe_html\\unique_execuctions.html") + if not exe1.empty and not exe2.empty: + condensed_combo = pd.concat([condensed_exe1, condensed_exe2], ignore_index=True) + print(f"✅ Combined {len(condensed_combo)} hashes.") + elif exe1.empty: + condensed_combo = condensed_exe2 + elif exe2.empty: + condensed_combo = condensed_exe1 + else: + print("⚠️ No valid dataframes to combine.") + condensed_combo.to_parquet(f"parquet\\condensed_executions_{first_policy}_{second_policy}.parquet", index=False) + del condensed_combo + gc.collect() - #Add Hash info to the combined execution history - if not os.path.exists(f"dataframe_html\\augmented_combo_{first_policy}_{second_policy}.html"): - print(ct.colorText(f"Preparing to pull hash info","green")) - augmented_combo= utils.hashfunctions.augmentAggregatedHashes(url,tryToReadCSV(f"dataframe_csv\\unique_executions{first_policy}_{second_policy}.csv")) - augmented_combo.to_csv(f"dataframe_csv\\augmented_combo_{first_policy}_{second_policy}.csv", index=False) - ct.style_dataframe_dark(augmented_combo, f"dataframe_html\\augmented_combo_{first_policy}_{second_policy}.html") - print(ct.colorText(f"Hash reputation info added to dataframe","green")) - - #Categorize the hashes - if os.path.exists(f"dataframe_csv\\hashes_needing_approval_{first_policy}_{second_policy}.csv") and os.path.exists(f"dataframe_csv\\automatically_approved_hashes_{first_policy}_{second_policy}.csv") and os.path.exists(f"dataframe_csv\\unapproved_hashes__{first_policy}_{second_policy}.csv"): - break - else: - categorized = utils.hashfunctions.categorizeHashes(pd.read_csv(f"dataframe_csv\\augmented_combo_{first_policy}_{second_policy}.csv"), threat_tolerance_constant, badpublisherlist) + if not os.path.exists(f"needs_approved\\hashes_rep_unknown_{first_policy}_{second_policy}.csv"): - if not categorized[0].empty: - categorized[0].sort_values(by=['sha256','filename_x']) - - categorized[0].to_csv(f"dataframe_csv\\hashes_needing_approval_{first_policy}_{second_policy}.csv", index=False) - ct.style_dataframe_dark(categorized[0], f"dataframe_html\\hashes_needing_approval_{first_policy}_{second_policy}.html") - - if not categorized[1].empty: - categorized[1].sort_values(by=['sha256','filename_x']) - - categorized[1].to_csv(f"dataframe_csv\\automatically_approved_hashes_{first_policy}_{second_policy}.csv", index=False) - ct.style_dataframe_dark(categorized[1], f"dataframe_html\\automatically_approved_hashes_{first_policy}_{second_policy}.html") - - if not categorized[2].empty: - categorized[2].sort_values(by=['sha256','filename_x']) + condensed_combo = pd.read_parquet(f"parquet\\condensed_executions_{first_policy}_{second_policy}.parquet") + needsapproval= pd.read_parquet(f"parquet\\hashes_rep_unknown_{first_policy}_{second_policy}.parquet") - categorized[2].to_csv(f"dataframe_csv\\unapproved_hashes__{first_policy}_{second_policy}.csv", index=False) - ct.style_dataframe_dark(categorized[2], f"dataframe_html\\unapproved_hashes_{first_policy}_{second_policy}.html") + #Pull hash info for the entries in the needs approval table + needsapproval = pd.merge(condensed_combo, needsapproval, on='sha256', how='inner') - print(ct.colorText(f"Hashes have been categorized","green")) + #Deduplicate lists in the columns + for col in needsapproval.columns: + if needsapproval[col].apply(lambda x: isinstance(x, list)).all(): + needsapproval[col] = needsapproval[col].apply(deduplicate_list) - + #Rename Publisher, Keep and reorder columns we want + needsapproval = needsapproval.rename(columns={'publisher_x': 'publisher'}) + needsapproval = needsapproval[['sha256', 'publisher', 'description', 'filename', 'hostname', 'username', 'productname', 'productversion','reputation_lastseen', 'reputation_scannermatch', 'reputation_scannercount','reputation_status', 'reputation_threatlevel', 'reputation_threatname','reputation_timestamp', 'pprocess', 'gprocess', 'commandline']] + + needsapproval.to_csv(f"needs_approved\\hashes_rep_unknown_{first_policy}_{second_policy}.csv",index=False) + needsapproval.to_parquet(f"parquet\\hashes_rep_unknown_{first_policy}_{second_policy}.parquet",index=False) + ct.style_dataframe_dark(needsapproval, f"needs_approved\\hashes_rep_unknown_{first_policy}_{second_policy}.html") + + + del needsapproval + del condensed_combo + gc.collect() + + if not os.path.exists(f"needs_approved\\hashes_rep_good_{first_policy}_{second_policy}.csv"): + + condensed_combo = pd.read_parquet(f"parquet\\condensed_executions_{first_policy}_{second_policy}.parquet") + needsapproval= pd.read_parquet(f"parquet\\hashes_rep_good_{first_policy}_{second_policy}.parquet") + + #Pull hash info for the entries in the needs approval table + needsapproval = pd.merge(condensed_combo, needsapproval, on='sha256', how='inner') + + #Deduplicate lists in the columns + for col in needsapproval.columns: + if needsapproval[col].apply(lambda x: isinstance(x, list)).all(): + needsapproval[col] = needsapproval[col].apply(deduplicate_list) + + #Rename Publisher, Keep and reorder columns we want + needsapproval = needsapproval.rename(columns={'publisher_x': 'publisher'}) + needsapproval = needsapproval[['sha256', 'publisher', 'description', 'filename', 'hostname', 'username', 'productname', 'productversion','reputation_lastseen', 'reputation_scannermatch', 'reputation_scannercount','reputation_status', 'reputation_threatlevel', 'reputation_threatname','reputation_timestamp', 'pprocess', 'gprocess', 'commandline']] + + needsapproval.to_csv(f"needs_approved\\hashes_rep_good_{first_policy}_{second_policy}.csv",index=False) + needsapproval.to_parquet(f"parquet\\hashes_rep_good_{first_policy}_{second_policy}.parquet", index=False) + ct.style_dataframe_dark(needsapproval, f"needs_approved\\hashes_rep_good_{first_policy}_{second_policy}.html") + + + del needsapproval + del condensed_combo + gc.collect() + + if not os.path.exists(f"needs_approved\\hashes_rep_bad_{first_policy}_{second_policy}.html"): + + condensed_combo = pd.read_parquet(f"parquet\\condensed_executions_{first_policy}_{second_policy}.parquet") + needsapproval= pd.read_parquet(f"parquet\\hashes_rep_bad_{first_policy}_{second_policy}.parquet") + + #Pull hash info for the entries in the needs approval table + needsapproval = pd.merge(condensed_combo, needsapproval, on='sha256', how='inner') + + #Deduplicate lists in the columns + for col in needsapproval.columns: + if needsapproval[col].apply(lambda x: isinstance(x, list)).all(): + needsapproval[col] = needsapproval[col].apply(deduplicate_list) + + #Rename Publisher, Keep and reorder columns we want + needsapproval = needsapproval.rename(columns={'publisher_x': 'publisher'}) + needsapproval = needsapproval[['sha256', 'publisher', 'description', 'filename', 'hostname', 'username', 'productname', 'productversion','reputation_lastseen', 'reputation_scannermatch', 'reputation_scannercount','reputation_status', 'reputation_threatlevel', 'reputation_threatname','reputation_timestamp', 'pprocess', 'gprocess', 'commandline']] + + needsapproval.to_parquet(f"parquet\\hashes_rep_bad_{first_policy}_{second_policy}.parquet", index=False) + ct.style_dataframe_dark(needsapproval, f"needs_approved\\hashes_rep_bad_{first_policy}_{second_policy}.html") + + del needsapproval + del condensed_combo + gc.collect() + elif choice == "3": - if os.path.exists(f"manuallyapproved\\hashes_needing_approval_{first_policy}_{second_policy}.csv") and os.path.exists(f"manuallyapproved\\automatically_approved_hashes_{first_policy}_{second_policy}.csv"): - df1 = tryToReadCSV(f"manuallyapproved\\hashes_needing_approval_{first_policy}_{second_policy}.csv") - df2 = tryToReadCSV(f"manuallyapproved\\automatically_approved_hashes_{first_policy}_{second_policy}.csv") + if os.path.exists(f"approved\\hashes_rep_unknown_{first_policy}_{second_policy}.csv") and os.path.exists(f"approved\\hashes_rep_good_{first_policy}_{second_policy}.csv"): + + if not os.path.exists(f"parquet\\all_approved_hashes_{first_policy}_{second_policy}.parquet"): - all_approved_hashes = pd.concat([df1 , df2], ignore_index=True).sort_values(by=['sha256','filename_x']) - print(ct.colorText(f"Approved hash lists have been combined","green")) - all_approved_hashes.to_csv(f"dataframe_csv\\all_approved_hashes_{first_policy}_{second_policy}.csv", index=False) - ct.style_dataframe_dark(all_approved_hashes, f"dataframe_html\\all_approved_hashes_{first_policy}_{second_policy}.html") - - print(ct.colorText(f"Beginning calculating longest common filepaths for path exceptions","green")) - grouped_df_view, df_with_groups_appended = utils.pathfunctions.export_groups_for_review(all_approved_hashes,"filename_x","longestcfp",min_files_for_path,path_exclusion_constant) - - df_with_groups_appended.to_csv(f"dataframe_csv\\allinfo_{first_policy}_{second_policy}.csv", index=False) - ct.style_dataframe_dark(df_with_groups_appended, f"dataframe_html\\allinfo_{first_policy}_{second_policy}.html") - - forbidden_lcfp = grouped_df_view["longestcfp"].str.contains(r"(?i)(?:\\Users|\\c\$\\Users|inetpub\\wwwroot|windows\\temp)", na=False) - grouped_df_view = grouped_df_view[~forbidden_lcfp] - print(ct.colorText(f"Removing forbidden filepaths for path exceptions","green")) + df1 = tryToReadCSV(f"approved\\hashes_rep_unknown_{first_policy}_{second_policy}.csv") + df2 = tryToReadCSV(f"approved\\hashes_rep_good_{first_policy}_{second_policy}.csv") - grouped_df_view.to_csv(f"dataframe_csv\\lcf_needs_approved_{first_policy}_{second_policy}.csv", index=False) - ct.style_dataframe_dark(grouped_df_view, f"dataframe_html\\lcf_needs_appoved_{first_policy}_{second_policy}.html") + all_approved_hashes = pd.concat([df1 , df2], ignore_index=True).sort_values(by=['sha256','filename']) + print(ct.colorText(f"Approved hash lists have been combined","green")) + + all_approved_hashes.to_parquet(f"parquet\\all_approved_hashes_{first_policy}_{second_policy}.parquet", index=False) + del all_approved_hashes + gc.collect() + + if not os.path.exists(f"parquet\\path_needs_approved_{first_policy}_{second_policy}.parquet"): + all_approved_hashes = pd.read_parquet(f"parquet\\all_approved_hashes_{first_policy}_{second_policy}.parquet") + print(ct.colorText(f"Beginning calculating longest common filepaths for path exceptions","green")) + grouped_df_view, df_with_groups_appended = utils.pathfunctions.export_groups_for_review(all_approved_hashes,"filename","longestcfp",min_files_for_path,path_exclusion_constant) + + df_with_groups_appended.to_parquet(f"parquet\\approved_hashes_with_paths_{first_policy}_{second_policy}.parquet", index=False) + + forbidden = utils.pathfunctions.regulator(badpathparts, True) + forbidden_lcfp = grouped_df_view["longestcfp"].str.contains(forbidden, na=False) + grouped_df_view = grouped_df_view[~forbidden_lcfp] + print(ct.colorText(f"Removing forbidden filepaths for path exceptions","green")) + + grouped_df_view.to_parquet(f"parquet\\path_needs_approved_{first_policy}_{second_policy}.parquet", index=False) + grouped_df_view.to_csv(f"needs_approved\\path_needs_approved_{first_policy}_{second_policy}.csv", index=False) + ct.style_dataframe_dark(grouped_df_view, f"needs_approved\\path_needs_approved_{first_policy}_{second_policy}.html") + + del grouped_df_view + del df_with_groups_appended + gc.collect() else: print(ct.colorText(f"Please manually approve hashes prior to this step","red")) @@ -392,17 +546,29 @@ def menu_prepare_to_enforce(): elif choice == "4": - if os.path.exists(f"dataframe_csv\\allinfo_{first_policy}_{second_policy}.csv") and os.path.exists(f"manuallyapproved\\lcf_needs_approved_{first_policy}_{second_policy}.csv"): - df1 = tryToReadCSV(f"dataframe_csv\\allinfo_{first_policy}_{second_policy}.csv") - allowbyhash = utils.pathfunctions.mask_from_csv(df1, f"manuallyapproved\\lcf_needs_approved_{first_policy}_{second_policy}.csv","longestcfp") - pathexclusions = tryToReadCSV(f"manuallyapproved\\lcf_needs_approved_{first_policy}_{second_policy}.csv") - pathexclusions.to_csv(f"preflight\\final_path_exclusions_{first_policy}_{second_policy}.csv", index=False) - ct.style_dataframe_dark(pathexclusions, f"preflight\\final_path_exclusions_{first_policy}_{second_policy}.html") + if os.path.exists(f"parquet\\approved_hashes_with_paths_{first_policy}_{second_policy}.parquet") and os.path.exists(f"approved\\path_needs_approved_{first_policy}_{second_policy}.csv"): + if not os.path.exists(f"parquet\\final_hash_approvals_{first_policy}_{second_policy}.parquet") and not os.path.exists(f"parquet\\final_path_exclusions_{first_policy}_{second_policy}.parquet"): + df1 = pd.read_parquet(f"parquet\\approved_hashes_with_paths_{first_policy}_{second_policy}.parquet") + allowbyhash = utils.pathfunctions.mask_from_csv(df1, f"approved\\path_needs_approved_{first_policy}_{second_policy}.csv","longestcfp") + + pathexclusions = tryToReadCSV(f"approved\\path_needs_approved_{first_policy}_{second_policy}.csv") + + pathexclusions.to_parquet(f"parquet\\final_path_exclusions_{first_policy}_{second_policy}.parquet", index=False) + + allowbyhash.to_parquet(f"parquet\\final_hash_approvals_{first_policy}_{second_policy}.parquet", index=False) + + easyview = allowbyhash.groupby('sha256').agg(list).reset_index() + + ct.style_dataframe_dark(easyview, f"preflight\\final_hash_approvals_{first_policy}_{second_policy}.html") + ct.style_dataframe_dark(pathexclusions, f"preflight\\final_path_exclusions_{first_policy}_{second_policy}.html") + + del df1 + del allowbyhash + del pathexclusions + del easyview + gc.collect() - allowbyhash.to_csv(f"preflight\\final_hash_approvals_{first_policy}_{second_policy}.csv", index=False) - easyview = allowbyhash.groupby('sha256').agg(list).reset_index() - ct.style_dataframe_dark(easyview, f"preflight\\final_hash_approvals_{first_policy}_{second_policy}.html") elif choice == "5": @@ -425,18 +591,12 @@ def menu_prepare_to_enforce(): allowlist_child_id = allowid[choice] elif choice == "6": - if os.path.exists(f"preflight\\final_path_exclusions_{first_policy}_{second_policy}.csv") and os.path.exists(f"preflight\\final_hash_approvals_{first_policy}_{second_policy}.csv") and allowlist_parent_name != " " and allowlist_child_name != " " and destination_name != " ": + if os.path.exists(f"preflight\\final_path_exclusions_{first_policy}_{second_policy}.html") and os.path.exists(f"preflight\\final_hash_approvals_{first_policy}_{second_policy}.html") and allowlist_parent_name != " " and allowlist_child_name != " " and destination_name != " ": - pathexclusions = tryToReadCSV(f"preflight\\final_path_exclusions_{first_policy}_{second_policy}.csv") - allowbyhash = tryToReadCSV(f"preflight\\final_hash_approvals_{first_policy}_{second_policy}.csv") + pathexclusions = pd.read_parquet(f"parquet\\final_path_exclusions_{first_policy}_{second_policy}.parquet") + allowbyhash = pd.read_parquet(f"parquet\\final_hash_approvals_{first_policy}_{second_policy}.parquet") - print(ct.colorText(f"*******************************************************************************************************************************************","red")) - print(ct.colorText(f"*=========================================================================================================================================*","yellow")) - print(ct.colorText(f"*=========================================================================================================================================*","red")) - print(ct.colorText(f"*-------------This program will now begin to make changes to the Airlock Console. Do you understand and agree to proceed? ----------------*", "yellow")) - print(ct.colorText(f"*=========================================================================================================================================*","red")) - print(ct.colorText(f"*=========================================================================================================================================*","yellow")) - print(ct.colorText(f"*******************************************************************************************************************************************","red")) + ct.areYouSure() confirmation = input(ct.colorText("Type 'I AGREE' to continue: ","white")) if confirmation.strip().upper() == "I AGREE": @@ -449,11 +609,13 @@ def menu_prepare_to_enforce(): allowlist_parenthashlist = allowbyhash[allowbyhash['reputation_status'] == 'KNOWN']['sha256'].unique().tolist() utils.policyfunctions.addHash(allowlist_parent_id,allowlist_parenthashlist) - print(ct.colorText(f"Adding hashes to {allowlist_child_name}", "yellow")) allowlist_childhashlist = allowbyhash[allowbyhash['reputation_status'] == 'UNKNOWN']['sha256'].unique().tolist() - utils.policyfunctions.addHash(allowlist_child_id, allowlist_childhashlist) + utils.policyfunctions.addHash(allowlist_child_id, allowlist_childhashlist) + + ct.locked() + exit() else: print(ct.colorText("Operation aborted. You MUST EXPLICITLY AGREE to proceed.", "red")) diff --git a/parquet/all_approved_hashes_Developers_Dev Audit.parquet b/parquet/all_approved_hashes_Developers_Dev Audit.parquet new file mode 100644 index 0000000000000000000000000000000000000000..a78a84ab27127b74aff503bdc7fedd24e574d55b GIT binary patch literal 25163 zcmb`w3t&{`nLhrV$xN6@CMPqKnPCzGPGSOyW~S$Ui8M_hNl6GX1_ZQ?}t4NY5={(DtJa3qy$SRs@Dk6uGV}`6?vnpD$1db6HVX_ULF*vl!Sq#tU zs$$88D%+yUu#C+Kcuh1-USSPh!7bZnWreX>5vGA{(D|f2Sb^nb!QwGrRh1=0Vp)wd z1q=(LKzABrh&n#N=Z2;loN1_x$}lEOrr5G1PmV*D8Bu05N!LU}ku^b9MT5~SU0^JX zNwh7|f^}_o@~r88sxjz7mQ_ht1YNIr;dm=6%RFmaJjZIXCL0E?i;|(sZqI_QSO%xs z8pC6089`AbcL8}_H)LFvW!N&?S`#|nBI6CiW)+baMO|V{$udQjS2RU3WJOnPQ`BTr zGI@hBO%*ocIDr!+OW}A{k}TP`^LUHO%d)~MvZ|^atH7>;hEbYW2T>Oci{&ki&kXW23$L*yAn;cTVmF@duML_EW3Is%)=a%@GYA|~C4#Ij2^ zhj0{NLzR^@Q`0odP&Gk?)i4?XuVd*Ez8EQ^8=54#{>{N7WmAXa+q}U6dSES9<6(GF zgG1|##0Vmba5WK)rYad|Ox9g!&<%v90!z$OI29wpYQcbvgiy43UVs+}lBVh=Jf4Ns zO$!0T=n7|XfD;unlSKo6Q=xqd;#gJ<6-Kui))2A$oNmDxc}q1}4U2$f&{*oV5T>SR zHFwp?vSeDeX_#gsLPLRTXqLs>oC2WKOoahT38o^bhGlUgeAjh%lNGTrrmg`+bpgwU z2-7uL)qPKHG&z+KZNoBT6aB-vWl>c{Ohr;eQ`h&?CdZ3_X2Db~fzbuPlBSEgD42|% zDQrP>^FS$u#Z69Q(TU9Q05(Ntb#$!qZC4E{s;$H67(rDe*V-b&LzgWL5lZc>M)dOx z%PCsb6S4r0P!Qp^CFm?{%D|d71|kD;IG_Rx8#1QIiJGDciUHuV3WGd+S+*6Hg&8qI z9uNZ0z*GT9>#vqI9;(*K#Ty)l#&wRj02P8DYQRRu zu?*FlG@fMg~(sd5`9@!uLpdA5IK*~iDbwU0>-(lWF27)uQEGL5^h?cAv z0BYW_IZ4vcr3m~0Fd&{-+oD;0Y(J>QCW;YWi;TmVKNK@s0WP@ z;lnQFQ4yPfZe(0g9DstVQSbVm>=8JNUA{yL!=xM+N2gKkEg%!{y!>Bws0%O5}B-@6M+Xf>6))`xM z(+h)S4hp~wU~xeukV25Y06QYG5O4AtNAK|;zlYTj1{xq7e$1(0K&GXMwgQZ1KxZ@^ z6iahKSrBCK4Mo*u$+fzVeq1ihxoz;40KiOA&YWE+yq zu%-&!1o|Sw+p>UZi*RWkgwhRaK!6FHglRbuBZBW?YPy8HA&Js~n~%2&Dhr1&3{Xu0 zYXG8%DYFb{h>gg$kd8Q+l^6qv3%D01(+I2bECa}v3`3qw_ZS}>*+8VJa9Dw5WlrUJ zQv+^koTk_aP6Hq7rU8G^c?0fZa-s>+fJw_*NAh?JfD+jm$O?FsIn9(2KVU%uaxI2m>?p&% z;bw}?0~Q!$Dha*^G&joH?=o501e!9oz*;)8yr6KPa)4LEl0kg1uAD6+u5fc}9fM3@ zND62xCS)DBIUyLJgR)w)%MZ%jc2&WGXGpeTfIfqnWkSdAyd1YyEsua;jki&5)@CkbTx*Y?xQq;Gggl^}uszf)x}rY=XjrBpL`w z8|%koNn{58h`bAkF@PB|h#W#qL%{>Wj#>iLm)8T}j^H7@g6IHaMC~ESHlR|p8Pqzq zZKDYeBm@aXQsBn2VIlV+ZL27qK+ZS|38s#<;D_M2I8iRnrWB910~1EL#KSz!a$7Y(zI^tb&LFcz7@n z7Cak;5%RJr8lcLY0UjQbP%@bG=gXc3@PIVKdZ3ZI3CP6=Bt-+SKrMn=14ts{MWjH% z5Wxw6r3U->SGAIzHgL}ZA;b6-Fc!oZ@Ihy71E|iaU}?N^^nyOwxn&+~9SlPN&`FAg_yLB4|DkL%H4&TzQNsg?RmRu8P=$+e zHuxS7y2kN_Bry{&?n8D4I|X;-5QOdvNX01aG#w~|P;!e*8@8MDCl!1`LOF`DgBL0` z0!O!zZjs3WeTWC##lNVyIQ)e6L1PioV8@66_3`R?BI-d91WALxa0n)v3*3Y*frzNz zbPiaCxhSYISnzI6MHz_N5FE*(tNeaZv3*ZQQ9cLyL4!RQdt&};O;HJ{hhgZq{eu8`7W@G`0k%NgpzH#V1;@l-BcY`TEgdXHg#AC1W0VCw7>KT(E?VWR?@(|ff-0HSXb~%)Gpx3Hk1feWKpDAh;*Po3;TAM1&{&- zsoj#W(C}B#2o1FmtSTb0>1~-YkN^n?z^iBxbu>~MN?Sk?z(O$(^d%&KAg>DAj;CE6 z1B}oF*V8Thl{gdF0upS3+b|FuP-Y|c5vp#jF2E~AN%TE=mu6$&;M5Fj85qAUK|BF@ zM|c_lV-+_|5F%tSK|Q(*^%Go0MaeFyhN;E<0YBV{E}`oXT@WWgK1BN3U=)-GE3tJ( z5&(ukRCw0+5ADdlm@A@Q1RsEcU@JRX5zMTr)ALLGj3!dQy$jamQN}SSSrAsBE+{xr zGNT#*b#m1RBwKKQNfFGg&vzuFkSAa_dTn4S@ClA@TF8ztu87swk$7pbJczPDr?-_Z zv;gl4N;z3VenZ6!Iu`K6lwy;cbJcXOe1-_L>~14(lD?d^`{Aiz|}PrL@p!}a0c)QTLK?c>05$zEI27_ zZ}M`aCom5{&4?O8L zjhc5G1WN#qfb|(};!n3RsG?B~Nnr0Lgc?+}0Cs>m$}*5X)QFfOhgB0JgXLb?qJL0c z2TBQ%$ij5!V3_E1v}6mI2=XP!kN_40C_@2kqMC)kfoSG=R@m{`12^wO-c+%?&=Np@ z!F2%39Fim87~y4uY@wzDN26~ki*h``m!;Q6>fj|9A%GHCwNruiAc82eu#kw^*$5U? zD+~{Fn=JmqLiQbXi2@eGi(y(}%$RT!Rs6P&%&W1FmfLZ}ckgGa?okJ9W=B6Vspih9riL_D1 zhywC~4%taT{-QSpn(D&l7{5SK0*EFjVw{*Cc8mswp6`g~&zzG1#Lc zsE#b49S9nP0#Q6V=H(R^(-o9N@FC3aFql1cq0FzCm7zQ1HC8|6O z$O2Z7XkhclFDJ^@Bm?aSWdV<vWEo57m_#LC8X4X-Tiy(qJ-Rwt*t00~eHPto;*gzt! zSqg;=F=L}~I0W9LSqqvH#0i9^!Q1pr zWp!``1R$ytu4Y~x*1>>2fjnAM)nO(P&>(oIrs&Uwt1$v7ceX%3>E8*UXF#P<{6jyq zR6rO9z6Xg>heT(xZeICaQv#|TWIK`iH6ueW)uCQP8?t12St;S^Tj(gV1;CU3v>)a| zJOc|kLzi@sPM3OBJ~Gc=4Z%TSG(m_g^ZT*H6YX`Tq`5*cG86rm(pGqYD`}xL0|-Gb zw&>sZweR^+<~J^V4g}vs<$zRdL56^OhqXuS*&qX0eNY|)9U{4);1gWp3jG6y;A-CU z+T3EZ8Y+t>L$9GPD!&|rMFG0QNLU+`=um1zz_P9Ep9{$v84Oy8E~yf3MvjNQaJ2#| z9Rbye!T=Nvuu>#-h?gjpFe0cw5;P*nE$~OM6G(dqCMdF#h4$Z zq84ocHlb(*|Cd!-D5Z0i3Fzk_N+!L$tO4YfburKsq)Y++*7kCPfjIysQ5IQriY`Dz z0D=m@T38YQge?Hx#B} z^8yjk8pzzyANIg^AlIXiL;ga^j~bXa>X#;T2E~zO)m)X}z`tR-nwN=mbjAKhAu-%a zR5}-Todf`eLW_#gp-2?v120*Sg;5eluC1s;xSEhGSc#ul^x7x=wjt5knL)TXNByD? z!WQBSbQ!8PYHcJbMbr-jhmk*35Ceo45(bJ{xDBuXxUb;#bAnM+3Lw$+8-X6MANUpw z0?v>5gR^mLe6TzUy#Qp3E<2|IWjL}F>K8$w_XLPczg&`l^bD@UMHUDAA}7&xm4G@H z3>1YcIH#pN{<;Fzi)o=M0-c2G?0?1&@sc{f4!j(E0gI$WMoQ;FxfPI&WC-&zV%nlF z^?P-;aj75Ep>A7hpwa=&V}O0Ar=eAW1Y!pFCg^18<&1{B3+WXV6~X~P2gF3e*0lq{ zY8~1&C@Mog9&;Db)~SV%{_q@XN~q=l=KaSKHsT&-HGRi9H8=TzlJw>ZuPFrDk6!y6 zxG3}{uws*y;G5WxfN}>B7Z?RPgUSP#2ze063w1nv5B`K=$EH`tCaR;*B2fs_Un}<` zY9bd0ygWomR0Rs zA)P3Llmza@qi6tjxfp*iaN~AjY`xi!0*{^-s)pXdLNK-Hg+XXxNO~4sTh)gJz@C-` zrBN46H??3dMLc?A2vxoU4!#syag2&;g@NL$p?(C>$8c$(q7Rj%tBQklqKL!p0OrP6 z6SErtGQb>28k}DL!ak_z?xLDlTM$?jG05bCCMppBG%T}<@(2N=Q{}KJ^bCPs9uI*d zTN-_SRhQWWYw0NdA@`!wL>Z(-g#{8LFtG)uO&DX~ve?c;F2Yui1yUq~IYNtr42fNm zz)mlU*B6M`Hgg4B8wJ@tKGl`T7XMN(O_bnZ`#KbU zKq+_?q@)_aDn^X06>R#cs2-v9=|~w+-!-YGK7oBg&>rTsKZcNzSe^b;e4!1ucK4Z4 zCqYhI(=AIj;)<%HY%xp~M3@IDzNK*Lt9tkd5rBX(qA8NGj&-_{NKy>o(4OD+1c z3NLh+8%jfvI(3PzsczRmNl;YCh&WV_u6jyeT9SZJjlDj;e&14PDv&v$Q33@}Rimbq zKr*Q(8emfm8%0=7lippnRO1vt3RsDR7B#FhRzqh&JpqH!2Gqu~4z&TQDN;iLZi#Bs zwBfao!?1@ZV)7sYI$()WkN&h81-hX^laCK3gO)7tbpI?`522>C+dc=thE-9V{JFXb z$O5v@O3=17`d?>xQ3HIjx&dZ%WhxGF-)3R}F9kvj0%lGUCMm^pHjSQkQ$SwBc z>7R#CpH)aRN#ekgT+_9mGVnpwVK3 z1cwqJjo4J$-NHloK>!1#grtfc3~T|iKp!Yypaqg#^V50IW1#$F#~s^H*oPI`?oOcY zkXc3Vx+{u$6fA~bbZ!HrL~uJEE2l*Mu{^0kc!N%7qx36{Vs8gKku|(mmFOE$^Ya`% z5JUVVYzE4etkC}$YH&A3k*TrV=2kg`a|9q`*Tnk(Y!)PIL=X-LfIdS%;8pr|zaQ09 z#9LMevVi0Utx=+%FZJ3y^{WJf9Uq`Et@$^)j9o;AgPeg~9nc!kF{rH&jDWYS9B&Wz zVAMGK01XmJN@83kUl!@^iY9C~B5j~{M%>bGpVtnt2zz$ekOlXI+z17irb^3pwgaj0 zGmr_25fB_ynBF%t0ba}iyJ#y?(_1Y;y5b=t(J7=^mZvMKqgV=t(IXFsytYnfs_Duq zO}`vYi~>?skRP#y@9w2yR5(K-&{U#Y0w|-VGw8}-HB=i0UW>i#Aa-ULy5O%yDFw1A zC~fl>B8dQFu}O*4ip&EgLYsK84n-U`3?PbXZDt5GS~g!BquP<#;35DWI18AjO22$w z5Yi-1`|6|cC{F0FbthoHd zDIFTmTsF6Nw2)kqS(~-YxvM%Ogp>v9sx!Idl2O~r^`1vMMdC#MhHE{Vi0r5k`n8;u z?80_XKH1Z=z)5)jrfX}$`NNDeuJj*fRG*j^!NeZ(#eU$OKCxFk$1kbC1NC0g>i3d` zAwpV1l|J{CApZ7cvTM7t_UN*VwIP9@+eeLceOlHUPA(bG6s)8@noFj8twKFMYa7#y zK`S{tx>m?qg=FBI<2Q9IO?KwA5o^O}Ze5Z~Gv~NXSi^X`Fq+fWTFJ#)7XRdu3x+dR zwt&t_$H)>Zw?1Q7%X8Y;n3bb&FPX*{nA{rE%nL3^_KoHWnm%kL8%}=LHa3<|8>1u1 z9&J2}LF5`IUn{|DOUBVi-}us{m%8&w|Ah3E<6k+oGBcL!%H|8&@UWE&QnxjYZpaRg zYG$&%r>Fkb=Sg=DnQpkJU#4P*FPv_<*GG?ACwyW#TD)xTg64sNzTD_qOgPz@8MgAt zhK-8UI56POcwnF-Td;CtxlI1ltOo{0^4i+*%)r2KMjsf^wL)fHD#I$-6q{zb^pKXD zyXrDDee5z)c3G1#wl1?VHDs=1#ZhXFS7ZWf$Q8bajxXpyzi_<51~|{az!+96gB4qk z6~lO@tzX*OXw7X(&KIUv?BV?8H3_RbT8(rW13?XZM&p5lO zjqUl7_Do*OW9##)tMvUr7mRHeIHZ zi(~rnu1oS(E4;^?is~IFUo1gFs9#)rUnLvau%Cb z(##q`V)4|<#cgXkR&>mDW>VtJnyZ2%T4p%4!7rxS#+hVg>|4j4DGKGS!uXi_V?Q7& zu$tJ;YT{enj@d69%@?|`bXe9xW;EM*hleb4hKO%y*FS~Ut}mq6FWy2fbykvDD?@oB zml;d1B4mZLip*LSGDe|x&3e%Jy{GHRY3d&=V*UnXmuM~Uyzo(-d; zX1*}GF=dSAtdy1?h7GjkLDvbK+dPYJ^LA=&p9-&pfZkYmzp+gooPalR9Xe{@co5Z`yx+HV#t{JVc(9*%2l^+}(Hrs##g|@lUZv)QqlG^1ZN}pxrPN3AMbED%O zd!%*5vAw(OH@+Fwa~X53wZDdNch@>!@N|8F=nwuPB&4u25g2eb`|jQxc(7XAP)Lmz zGQ+dJ?c80Ixw|^AX+x>Z$QZS<)-EMWoKJg5NA1gHRRKTURCa7R2`ryC2?K!DjfE74 z01z7ooz@v|v^EZUjXWI+UOXE%POl{1jUzQic%>5!#G`@VU07QYNdGWM4CisGKFip{ zo3Jjayf$uFxj-hNB2LA0`^bE!wItqJ(gX{phetPPYcp0_e1*u3uaK_T_Ydwp)G~t- z>2H=Fc-fJPMx?G(^XH44yS=;ao(Bt!4kPeWP_?1!b15IuMBlNW`+{pnbS?g3nJ}6i z-jw1oVkQL|@Ky)uj#)LLH$U*u5S7g4+cSvnwfV+%j!4H*50063DraR)D~CoIx~8Nn zP6lINKNhC^SduS&z3Tc%=dohv-lELCWI^OXf1)R&=d|3WmJI=CSMm3E&8`kq1H0D3 zNK)ek&X+u0UkZ+x**yJ~a1i&nHmQm!AtUuW=}iG{Cq)J#Z&XB+9g7zX47~LUNv19* z1N55}Bp+{}>Gwm`!zOH&V&%xiB$dv zVLw0U9P{0MECK)AkWb|%Zm<1Q37HrB#>fi&o$zcDtj;jw+4a^HnM^m)W38M?J+vg| z&W*mcJZk0I)>_%_X99$c*;QAUpr6X%!jp;Xk}*>Q)~3hutnx*5}8N;;dBOT$d74^iz=_leR{}CNX2j|GbP!0-zU+X0w*DY&?Qv1A|(v zaw>UFWlZ|Hiuo0!>osTDj5n5r7K{vEl396$*SWPMeQSvy8L6dg23h5M*SWLkjlobM zr@^*|BP4hJ`z6j#y}N!&x0I2g_|N=aF1_PgGDP=99MikYtVTB7n6fsew(3>Upc9?( zMznEeBENoZ3X^c6)chzFTkTzIMS3DtZv>9Tf)QMOCDr*WhKF#vB2_yabl&u=degr^ zE6|_uw_G;ExiApFFfe<#l#D$7*~r#tI$P=-_jDb9*YxMdGR=cCNP7I@1YpS=-H`wB z1&WRD+QtimR(7dnv|IG%*sgY`hK|?JU9=zBE}ii>-}7{RuP$H6S=xv`4&nFbUNK#@ z#P8fsHQrx6qUAE!c}_*X=_f|yrg)?xP}N;UmWqAH9A5}tye>nh<8()bbD{Su7cyg` z8TdVy>g?)m>j_-y+)o1cH;j!AXN*m7L^(b3oHN(cHJ5%m;2*XM5w(hbyP`hmxcNK? zTXDWi>HC622wdhI4AdSB5Z$+u`o`i)=dIHCTcu4%rpP*DgBc^An!UG_aN$R$K52WN zY>fZwIoR8(N|ZU3RH`!YO>c^Ad%o&gntXbkt2$D0XlHqJ$tI-jk@$~Gj)Y4SIet95 zX`@kfq}+RT5q&I1ulC>iSyGMkzh+I}k|mML&LMr4uXU-FFRWqKZrX^`Z&unI+Z6dp ziA2Q{Mvi5mqtbF%38bI4^^QhG;NP{s5e;E_5Nax4m z*OoqdKTfr;ETNj#jdL1u>H2iuSlfL+xvqpF!pciY!}ti7XUEO4^x(Q@4T^}k*R*LJ zvmtMcuS;(-_3j5qnyp&-2u0YHD@oIpI3!XS9Ue~)a$5IFvMopvY2^yiv=#+dZhdZD zdMLNP8$T~-ThpB_tm#;=q>Wo$Rpn)sl>?-S$$^6DYngOT8|oe)Z_-qQIBW^S8$>p} z?uxD-IuqU-ClVX2oMGj=P_Geg&hugCOTqY;g1a7z=2P&1we&=ku=gjOKa|z}p{(lJ zkavMa|2Ez!M4Vsw?*3JLbHJP5Q1*Y``o^5T>LX0moTtm$&wK{DzUjl~;~g z`V~CCc9TA0jcy!Yr!xYG4Cjy{2L>hyc;$@bl{oLtrZ!4K+ZFz~t9JXE@2&7x zXY#4V%i8(AxOHwQliz3#M{e~?7th#s_YC)=Wfw2&QCdEYJbux4_Ym$6=bq&87md-& zB2`Ofl9r(*WYxKKYmv9dtSknbxg!K7To`>k>fA+F-9^X$>%2t1PcznOYiBDn8^23Z zu{*dGWeo!ZpUzoU7L1@E{b{z-Ls#|C(V=_}=Nvl@($6Hki~Fm}OUZ@4&#k=J)6tjU zgfycL41mzAfo7H|tno#$o$9hUu53JWN9|}lennI( zZN4DX*EgOYOkI>Sa~)%Cg+eZ)j~C#231>zzu01n~Z^B+Dq$p8Jp_mp^kiLbKW{5@# zr9F;yOE}HQGHZT3gK&Z89l1O%m)~6)X*jRyiALx4c<1f$CQ$X%lHRtyB?~WFn(1+l zogc^5?oWVaV5XVK@0w;W^gHVU@pXZpK1uI8m;S|bu_@t$PM z%N0&0P?ZS~qqZ$YggO7G#(BSJhp8c30=T3E5T#o6Pcx`qs$c4b)2EVP8trHtoi&N!tdJS+(I?p!XT?IKr?Hxb#1Kc{7i82Zr4M>F)f#m z+#X~9=zMc#{F^h~>^t&8=XZ#6$anXl=pb^AsYhO{sA?{A*3WojeeEM9WSIU6Q+Aot zztRV#+M_HoF9qKJ%480+2dKfhiLUL(%+9){Ws&t zo-Vn1Br{@-jSmk;Zmz1jFXj|^cNHZtKrq2nSrbVH>84WdUxN=_R?~JpcjxRVB&mYN1-|FJN;STE z_h+T!v&fM12=P6_eLvFBv2kn|^+v9(udC$(YI?zY=LNCreADaQ{~I$;l)G*Lec4=; zkc&=~kaJgcLqnK7e-80BB`J}t3y4JQ7fJU*@+v+k@okMR#4aeyIwNG;2zm8R;;7_G z6@`7hk3l=g*C2y#)TMTIKSCY5g-YE*=3O^NnozEGrFs`ES=_aBAywwhq?}EJ+T<*x zu3ShtYsjr@$gyjw)U~mHae7F)hjgbs$0|r!g>y&I19udWP{%Dz*;IaAL4#nB8_zp& z@6^?eZ~CbR`l(BXj+J^AmmcdOfu2kMOY%|Ae!*J}0bxDh*mCMTxa>L)DeHLp!9|ZQ zpm0F<>b(`jIYyu1HWs_z- zRXWXG<%G%a!z6jC@O5^QKkpf zz1K^`xsp&5&ee(>FY6fnds15%I`V*A750RceL|NKFlCEqvnb@eiTf3I5K&JdaQ<_ov zxmd&WS-#+j-RzkjVE0m2Pn+a)CC-a>p`LLwe168Q=NQ*x*fbZQBGssv(?~D^S4OBN zFO&9ps8aB9%Hu2bMFXV?SA>C5LtP%^(~L-sv~y^Qb;mC@CHbZ#d?-BZo89DQGTfZ} z1EKKQ_So%->7)CX+S^X}=`1{hW6@lS1a-;BLa1#j>R)dv%ocrc*}RB4&y-+oZQTIZpSF8`3;T5A^h-XmoF&7L4Eq)-Mm-!Ebc2D+^A`#Cjf zE$3>c{Hqt(lpEik9wy6s+V>vB{AovtC%9%Fe>tfr{Z zKa}@vt095yZl{d)>+ZZqnoqj(KHmW^$8J67<&<8vm~i_;`@a~viK{S8 zthLBJMcru>wVY3O+&ZyntJC|sXZLet{k=u?7h=~n$%xHuot-;8%?9aQRD58Emu0E> zUXJg*hDxw0Mogj4dxIhzuoJ(bRHm*9~Ok6tn;b)L5xoBy|JiyKIt4T-t{x0)^xk;!*~A7JL}gI zqy0A)!Te9**gZAB`*lxOKatw*^s-FvLF)1I2^-lS@Zz-o_dNemb9XbGGvl1MZOxMOBJ`#l|@{g)Bp=pVaDARY3+%1q~tMfHtdR+=C|ge2S9 zO~vQC$4u}==wFAy(l?Z}eap)?)Bci9)?;7oYdKOBINz%#+bRjqnZEAx3E|sbr!Oq= zBhEX=iL}78>=lYIn{Fh0=QUJ^>1BD!@Zxu_mKHC&ksP?hEAYL0i->se`J?U9@4bsJ z@YQ%(^{B_oNWGhj8=oNj#AC30?**R71<)6Sqvz4T3Ur217aqM1pQz3BU`hXRLKI&O z-QXw9%lZMEB%qxi<15X?C2aV zs(&I|R9s&bc&@FdU-WLftGHGyfi=EHl^r2mB#3&R-dE;^2-Ep?(T?cWztEL*?`q$H zi8;UVclLPh{-jq-($O-h-rur>YR39LL8WgbUQWJ#C*8}zVI#|fT7t;jGH)up>$?c6 z%{a!wy;B;i0p#qj_cBZkw`>jiWDgOp_rV!>NYvr5uedx(17FU!)bXL<^IDHQweX}`|?ul|9_6!!l6@BhE|-~Wz-zb}2~pWpxQ z_sfYxop$*s@9|GLpQff?^`EY!NNZ*3Q`o$T{<)Qesm;$(o0BKr3sXn#a<{P1>EY9e z=~+5OFMX}P8DYP-wOu`;EFA!JJ#6K;qp;np(6yQL@4N4A7R zW!MSp4J5*s1aY*Rgj=*}G1Fn!0`xpoU)e^oFS3D0yfB8Ttg-eGYkO8|hp^X0^>K?QC#& zO~Vn#B6}?293Li6mfmSz4yB;c`vx~MV{L)@;E;tdw)b;waJi5hRz{Q3njJ? zu4NbHjFa8t(Ay+@ktJ|p#@SAu+D@9kK<3Y+ny;X4odbMnQAsoULQIyEW##17mq@cn zP5t=g^3$r7EsJ752~B5#kJTTa_Yt;8VrHO)AR$VMRb3j!gM6rIN&J8r){t;rEA~lP zmy>bG>)7YxWxJjvVzU5Nt@O{OT=K=X?M+}(qL>zz)sxI4dtM^_^+dhGzQBv2bk-63MT*S&;{yc>~PkT-7gS~^SaM@9`|hiMG@zC9y$Ef7fAnZPs?H0Z}%L^&3jDEA|kB+d{KAS z+cHZ2^RN$g*xW&kJ~}H&?tnOK`*4Ln`-h-K73S?I_&vVL#?z?d$%wr}FUk zJxLHd2{uj(k6ch$XTRX<93kDmpjzrl{}-sIvM{+jl`9|dR>On%Br7!^y(lQBS?0wV zE!`xD(twY=8X(*!=b+Wbo3ndou!}&@+(X|YbIsn}9ttDi_P9pdJfrxv#;p&7J&Gup z&d--rj(}Qo%EXrwNX&woR%X?;jFA3)zRIrf`@1g==DIzUszM#$xD%csLmz04KHuEYr#rum(eDxtz zKBBt+VIt}e2ME*lP&J2T!xkAo^pNLDZ&624olE_Za-}qzU0Md0RbLTcYA(rvh`WVP zT5l+N{L$;b>+kRNs6D$L-c#)DM{FG4z0Z??-=KD2wQq++_<^{pad(&N@AqO&&ZGJd zQI+)}7*R-0coSG&In67pU-s7jTX(U4_b*6gRy>rw$Ujt1xGYw0>nqw`zmn$r$BF`7 z+bF6k7>t6w$fzqzL!F4D!=8@A*PUOy=RtB0*2+`V@)EhSfeMUb%-mjzs9Rs{{FQGq z+NOi`;RmVMS0mHW&V2^M!&mJH{c#U*f4pzVbv06Ia!9|7_(x_ z+fQr@;e5jhkt^+NB-xFSX((KW@bzAT>(IS~Tq-{E^oe5z%exjV>gn2yV*{t3GB~-5 zJ!IxZoOi>CH%Unse33eA#3|!AXOP;^HPfHc#+{JojO$h0dDOiQ;p=3dfBm)cUh>tJ zC%m_PAm@CaVqUwm`s4u+C{euwB)rhOs>63zlY2B|N~Bvd z=)0(IQh7hM6*w@U072MUkyGOJOyB37zj#hvU4QY?)a=$k>N&S3@t@d&^DxCej1KD$ zAM<)Tyk$4NHRjyqk?!(1Ge5YxW;!#APhF4CbnY$v>#G+xpZBbM-s5}`2N*uMBz)gX zO}`}k__k-|+a4_KN-XW%$jbrx$Kl%Z!tGNVTs-!$pwGHzhVsrt0M}C!0Wv@PJSqEa z;>7MsS}qChp`Hv*+8E9~zT7=N=S9eEA6!{{Kk$*)HhlDau=e?&b6+5SU%=@k zfllnkPrtHK(YD1Uq_h8~;;K)SUB4_CT!Rxu&V9wWp1QAiTP5Y}_24?R*R$=|~qw z#^y=`Gk4o0v}mDlad)##{A+OLFAdT~we4LG`Gj~cx3`uIsQ)ml z)cH(N?lVQ(F7-GKMYs;(>jTB#f52(=;M#_-U!-sy!q<-o3*6s^kM1k_nAf9tGF<#o z*EW2lc~)wt6)_Keor-Ozr^D1&mL2c>UxKMw)lE|eeWu{)qzlLHHBX__2TnZh?lNRE z&Ni}s8*!c|E1y5j&wR_tr^T0^__#Rr0WM`a$|r$oizm0m<9v-eb=7~(@lpT3SF_J$ zEr))3bM;9e-E{+*1F`1$Z$FWIv17WdI?|K{V%oqf$%Q@;m`G~ zJojWY|Jw}b!>*s;<_(^eH+)Dm=T;XdP6ToMymIF{YWkJMj~^Yu_~@kpD%XN)zGB<@ z0OTsCu4wv|tt-0cSm4gL!Rp=X(EZdsMF@I#xpC>w6LLqSc;;=>fqU{;-z0ROiq?UF zlR-KwmOv=FTaV$Y2|1fqwI1i7=h#6{$3f>=?@P~m zou@ogm;RLJ&Yw_so==>oi*Oyn*N+ZMeDo4Ny{YJ9UM+ZXVewh6mlhUJXAl2=ZtQT$ z^r(EbTsaYxt{i^Z+_|g5ezL(AI^J3Px14~iO}b|wYd_==;Xr1O96_+f3*Ox8O6#MfV~ji=#YwMpkT61c4z-?|uEixb$J)06|jBS~6NPAyX( zefocNpfp`gqEoQ5c)Rl^Irb*;y-7v`Ki4kgeog|>` zPWy+#DZraL4S2>;otjTjH;|>dtiFTX3SDH8?}s~l4=!Bz!HL9^+-D#=MSiIN z%;J1-SLND+!4=cbd$`o;#2JO_ANS2ig`x&lwf)$;NZbFccgf)6$j^#$papSay=o9y_ zSCF69dPNTV%!SE=tZRmGs5g(p4sJ&!u`N{0lbAW}&owCmurV8da*_Uf} z|JpNdl)8sTwXEqL9>!boeV)qd%J(93{ME5wWsFpwT&S1_AI0zaA{BpTH&sdE{&^B1 zmDNy$NX!Gsne)PK>f|dQEauc(@6C-rP=t5z$eC~L-gD}$=?gyf-s`^j@4a{r56zR_ zqfYB?%Rioa@sw9gz4hmpsraiG;x#;SW_Pdt-r{4WAXP#=nX^;OPfd=sKnS;LPFL=LXa@jx1+o#&NE*yW;^#Z&w zFX6}X<4?5pbf+EV`hh!HJb!XfTX^J5 zdwlcW58gTn6H{;f>g!beUK(%Vku%?V_2E-*O~;a{7k_(h{FM^ChlkF1FaG9xeyj}K zBvCvD{L%7>>!MfH8aTW-l3jz7s;Cn4wav-PuBx>&*08z8#XS6+#Yv#1WbFu!?cgl1 z_Q9RgKgYSYu}y0Vo5tLCYDe`U%P7?1y{WEFeK3;QXqhP-ezWj~{Z)wCYnqa0Ottn@PCR>;r#<%f_c|@_p1t2Q9{iX+Pn!J0 zW_vQXpS{!RPkqcD&tl<|IpFMlPJim}@AG5|IeVYepZfdzoJNAq-t8F=e$1Xfa!pS( zcYiDrobLLB@kI2Ta<`pEtZS4$v zJNe0nfXiPGX)+K0twTEX(*N?1CK>X_AIz!8Panod0{_Qbt7%mHV-MwwcTOMA$@Tc3 zuGCcHld0~kS!mkgp8m?|!}&<_d}KgRZ}?=f@$pSF{f)nOBqw>z*?XV<)W_`cEUs~q z6`j4$=}-OreNL;-&fe`A5B{w^PjVl(@*K^9GF?@RU$=9At<0rQHi}`K7{6lNn&eO? z5gMOhOBiXQrD`#_0oF7)>dsxX|?@(agYCV62L&k-)@(F z43nAj-QV|lpZEE`*xuGYHb!F3byRHsPO34s$Ah1WV}3$@(DnYCR1qO$kB4f(KMc!C zwxn{5%qTps@;0y81}hm7uQ8fz>$Yi`x}tF$!wb5t7@T1%jKbQA$lA7Gn&WNovT10n z$f+XF@~kY_ysapPp-Mb!>Vl$5rXq8a#_JYuF@`CLmSk`uFK8ymStdW;hAIiRCbFU^ zND|L6BF|$)lBKDFEeZ@T$(G3|oMiKiY6`3^%B-nbf@P_KBv>}*w!yNZ&I%gC=_+gM z3~%VHB1xvC^DJxfykUwWt7xjJh#W?a8M1=Ss%Xg)I7VQE@iutI;Ls{(F+8KIiX|JW zY>O(xGBzimnrNE5!Wz7Sk8GQj6~<;oEDhEMosX{vE3mvQSUl#dsRjp4Di zjG!ozyMer}8#0Pz8Me%}RELf>%cx=4tRnKFs7s6~S*FPHil#`0tmvw3ikfUnCT}pN zsbY;dPT&N|QaGNKBun;fKiaJFvaGO*tg0%QmrlOmQ0^_p-ZAY6$5yMt6L|s;R?4x7|nxP4nsR@Q|iHga)`8Rh_pCoinkfjB3N86vZ|)gVC`aA}otzW!Q>X zx5$sx(QTo-Fsf2+`GH2N`JVWFeMd56v`eA{y1$aEeX*wL6$98OntHLK;kHof1HV1bU zu!brtX{M%WmZ55bidDmC1XRb?!+kMQMmID`bnTmiMarfQ!?$^Z1N30ESdGWRiy91C zXCy`tS-7hSZ!}fOKx4A*LW6F=H5IJHY=u)XBJ36xkdfeuHqQ&N0zuML-Gs%nSas8a z!!WwSSsdU*#mr>Uz~5A8j{-lIRYS$1+YD=n*nUp8V2r$_nyiLRz&2cfb@iwObC^b`IfKq~~2&!ROoCw=>&D~^0Y>cUEKv7-5w!y=6 zO;&Z^Q|nDmWklPs4B15gFm72?RS{E>6w%c6y|l^kBA{6?RZC!W0kEX$qAm(1qh|`6 z;N3h>N@4LKr?Kcn=6C>`BC|R=R{7RT2Nc!TVRVe3Dw4a}BHTllEe#$@ZLfm&^9;)= zTIJ)i0E1F!{7F>RCA;rFm|7wWJZg2EtVsiF>BqS}tm2GFUf!EtC@=XeWHAqb)dY-CIh zi^wQ214EEhS=M==Hri%^rxw;v)aycTODc_Q>@;IC zB4;2T2&!i8eb%>N6P8}mbq?_!(I5Sw9RX87$VCu!L4IHFLEc0Jf-$o!Cxar0maG^6 zYTmFpNz%}z2>bvrz@J#eo4qwe8v9vP&|r(~Z7*%dh6uc@fv2b}rYiHQWUCmE&gufd z8#ZfiexO^iVBvzS19>FTi+p?cBVuv|m|Mg;#+S&TqsG~l&iG7JN#2aOP6 z!!G4f;hTVNL|jlDfP$(~fABrkEpQggff}d+HbDow!Om)b*u%lmVMn@wIUyL?@KMf^ zL{I}0@etS!JVtxg!KlECXmIm^X8;o%5Q8%mRzRB!qw?Sgj0FRdY#TOi8;k^4XKd9C zFARb?C;-!s%>|V}2toJ)?1+d$yvb`Ey~}^}c2v>A|01eh3-{Twm4T^qM9Ey9GBUB9g1)ZAdc1 znksM;=!*z%%L1k?!lZc+O4q3Y0VZ$~OUsEE5o`}r(1#27$az`ZaYMp%_+89=sV81i_y$M|5#20TrL!3r!Zb1Ki9 z8gNVFG{uH<8u(f_4cLp$8!#7>6HSl?Oj_33lSi8Yl!(qiR=}&wX{HSS0Sgikn?Y?< zOdQ)Of*m55VZCjWRb^2T8N_wONyCK&bfSRhz<(q`Hvzqvn$8#?DhNlqX(Pg79c7p| z%uLaFzygCvCBgQ9=0;iDev_3=pebVutfeE$3knA+2Y59s8N>(s%Gomf3LkE+We^Dr zNdaxegsgqnB?JR>P*$sV_(7RlFD+QG49PZ3P)NWJB0hGBk-9udVbu{g51_qr+p4}s@NR9ihD z(*Va%Kt<_Ppbb15WCiX6p8~)N9JjY&9+1!E5wXBtb-0m@G@<=>UXI(g6~qtpn$;1v z&;n*Hm?G$gAV|E8eMj6?In}U%W{6Y*$UbW@HkMb{V4tuPb>B;9f)x}rY=XjrBpPr@ z8~ev&OJoN2h`0-gF@PB|h#Xu^L&5{Xj$8uNm)8T}j^H7@0`CB0MD8KTHlR|p8RR;) zZKDYeBm@CPQeeiiVIlS*Y^z9}K+ZS|0j8F8aRnrWB91G(eR(13Ww=A!RV>ua-Rn-~nmI>VZb;CLk9hkQ5EP0=Wos4Iqh(iU@&% zA%YVCOAYqXZ)qjlZQz~-LWc1vU@Y)4;DgTE22h<-!P0o;@Y%hx$*T%zH{6Qn(S{|# zTV3j^fLg=Y!Tkkr8n~5=<(7G{bubJ8Kqn~{{0A5g{)e>9)I@L=cnuFERvBO0JQXI! z+2DIT=o-fxlEjR?x(Cr2>=fLQgA=+H5Q>r7X*y5_uH+_}Hr8(3o>cG&3F#=t4qm9( za2(x6xJ4uf^uZtSDgH&q#o;Hk4;l-P20MlasE=077LgBvAV?bQg@ZHET;N)C2}DHx zrgOkD%tb+#!Gd>lD$+pYhTupRUFr9WitT$UiVPBUwL30DQVm84z=0y$VtpS5T zCIg3)rPhVBfup=C;%fz@6o?bp9>SP4mi}zn!|+5ACaY`UOR#R_Hvln3LNF9Sr-6DP zgYMvA4I0*ivB&1T)fkl!dKiX&&p!Z=XTcx96R;NW8>C&}vEY~(Y$UV@uBC&eh*&=r zK#VzZNJo6z$Ij`tIglY(y$jmG+lDE?U3}$ z-r=4Gz*xnHCI}HCn4lhBjQk0vq9SFNRKwKb{(v9mM3>OD@GgiGARi)qMKB7=gPqts zB?$n7BPu-W`%)XCFXjrb7r_UhAlS;b7C1Aj>hzovKck7%ulHkhd8Ba+QWm%ss0$KK zq|C?$K%HDQ0>KvCUs42f^ULkYDC7yO8@(#92>1lUH!Va*EUt*%*AaMWu{?;hK&Q8q z&a(jT3Q{>)LVQEU3_2F^2S9m2lzAWm0s}&W4624~mVqlmvB0Wm5(trOL1R%7+X4JQ z738#_Y)I4uj&C;~2AM|ic8NUl1B785FI)i)$6NVgQV^$`I6rQ!AMZgvf#AUE{7FNoc79V)Z zYZ}#ms23~&JOZoFaASYIi9r^PY)AroHzCv@s|BzF%#oIX^dU#Y6gljg7#S${$`<`( zc`Yapai+91K2r40cdVI90U3UNSsI; zWsE2w9_Wyr6vQujL$FceK&FsJ19qjl5cM)K=-H)>FbzXRFQ_I_dyq{5i7j|8;*Y@| z9zu3x0qsE0AQXt=;Sn#dxR|aWC4vnh7J)w@_#ye?5D#JgIv5>P6gZe{BE&H004!1E zv4AXK1%U=@{^&(S*_>pc{U9yi;q@lVAD)(knW#wGbZPABrPy!m8@e_i6+#w;#s%J^ z(DSFp9}ZrmGBPr9D5nV5NLMAqL_`bO7RG+Z=*XFMq~juppiVdW;o>TY=U8=>%>gzL zNUIk?A%oA@XdFg@*&$j17C>7N|57nF$Ctge8P%&`QKz2J`_kn`Q*s+FTw7 z?6najM64mNvaL=O^S3pd4ooeG*m9)y0w|Cv@(8nF9EJ=8MII(IaHOR`F9>Sr59EUf z4FS7`8l>#~hJxG(f*zD2Ob>Y(?en)-;CCu;LPyYm8sVmBjj$7wW$`2+uvPPF`r$*@ z;&Yh?0|l+nMXW!Ms0#=K%SNJ$Fu+2-Q#MB;N-&9iN7x0=riE}Dk{(1YXi5+#;F<<+ z)7O^O!W7_u$WFNG*|pdQ1NsEwXmw?~nS?`w;31o$zY?y(2%y~A0{xVKJAj@6l}7Rp z{m@bYVI24#Bt{()oyod!<#&wFUA)T{E5+5RdB4ho|QLS(Vuk1ZZ+t2HIf6@n3&=)ab>zye%J3#l1E z2y(GS|H`jD=0}>}u;?Wad=r@iLa_xI0_q+19=>OT3}E*`c?@)j;DUrtaEUAQ4=e;% z{ejo!7MN8~Su`1X4SjC;MIbB+&>f3}y+Mi&rA7oS+sfWqkgO5GpoQp?D&fP((Xbb$ zRzRjBAUjbQfT96bil7eh5~&hK1ocOPMg+M9_6T+YX%Ef>rC8MQ2oyvKa^1GARhl9& zs-&<89FMzU#*MbHW?qJ1Ac3_4MzBD@an%BS1f_#+0GsEaAy@$3ZCh(KFiPmM$SG+t z=0~ciMeBi0NLs=FWtA36>0Ctu`Zfrw}gWbW_}yJ0(!>ygMIej(*Y4$K>MixN76E4GR zG2BR0Iv0111OSFai;B^qNEGPWH6dBB5I~3?#EK8(;x&UqSUVf>C4&Akp+Yfo`xL z*cKK9oFDTCXXDuTKzS5;0mv3zc1AtYa6~EOFM>kv3J{roy(9tY8C-{pEC~2TPNHio z0Cg-FC=yq2PD^?8Z3V0s(?V7RItkO+`@A3GC3RLUcsck2Hc5#LmClB8D-L%L+rURPC0Q-6C(83u$ zYx{y#I<#w0REB;u=5C^`Q}ZDG;W^}#P|X3%dygb+_&w5U`j#`Quk`~Z>5WsprVwa5 ze8o%PqR^YbicMC6ZQ?)z${j>pU=-*KG7n%P_qQ4dauGXMy7I#1V4TMBIr8K!|_00bqZ`7j{MQ26+t5>W%R$(Hxp ziy#;S?jZ!LunDkEz%Y2i=6eQ^BB`LoI?&G6F(_z7DwqoFk=fUqMCye&0QiegQ;7iA zi9#2Iv^KVNJA_IBMuSr%mD2z%pnAYy9JMe2C1@Z9$M~LVk&*mDr$;z}LJOM8(_-`{ zB$^V`Scq8~SRCjpEC<3f)(A_@$*vv@^$T&KJ$ZP4iv-dRDGWOVULhNTwfP%<=-zZu zg6MVU(1|igN#I^Qk_KRxi}7~^uGvbA&DZ&n;L)=~RnR+F2&NW2F9OVDtoa3 zIMcGAH0q-1h8CQqh=;EUAZ(-g#{ABF>wT@jTs~0vN+B|EW%Nb1yUq~IYNtr z42e^cz;-W^*H?(xI&CRT8!HRu0g)4rx>BMD-Iz|5_ChJrvA*DuKs8V^K(Arazpkhb z^@2SC-*KJ_i65i|j7u=3x=jTWe8=D+R=`|sq*JgY8Nw@M9UerUo-)l3(F1kv&4|(-AVDzH3r-T>|HXpgqi6e+nTYu{!eMB=x~feBB|%al!{d-Wy6P!?K}iBaHO~6@x;=}asX*q0MhO%^ zR*jre0?DKvug98dI4Ht)n)J@HMH;67Qou?iw5Va9u^T!I>IoQ()+0BTb*K$cO%WOj zFiT{crVXow9ELMI5t9cI&;d(~dicjxNYD)xntXg98MI`9r~9VUdI&kC-TD;(HdYnM z$zQ4(fh-{VtORXaqyKHX7dgP!tLm|gu1v+j?^{g_;I%*qNwz9R-cR^p2Xt$^3TZt| zN9QQVs~Cqb4N9`XM^ZGg=`E2UCM8#IC1&Jc6n1OKh~cnv8w0`$VN}>;C?520g0+BB z1adf(Kwsz&AurVBv8xlRORu0njFkAcw}I&D&?~?Sq5a`x+}0w|sEKO>5N|*ocpQ9T z@gXY6SP!TS)c;9>L?M%eklg<3rBLg@oiq&_3_S>V067msAN$uT9_gtJeT;gv5gHjp zXOLT*$J0LvAwQd1;kE7f8)vrQ$P~D1F#v2#0)jogBisTe37Hp4GsFofRY0=RiZ&1v z)q+Ng0}@Z?gs%3loFCEPB3r;$O3(!e1R57a`lgALyv*-j}vzsL*X1& zXuU0gyhCOcy>ovQ`6yTnJ^##lNQvNfJa$fr{8M>SgYX8O&PM828pYWTP9m#$uPV{k zAm`^fx<3a0N!SdOD_NocDOB$sj3QEFyUopV2=@p;#x9Td0@y4_*6<))5CDCKe!#2r z&3-?!sff3%7Gwdz4O*i_zg+6IdFtm01}8p1V_NgCcNx2g2nRU>r#hfDpkq*5As7K~ zSvlSo?#8Hb_W>Ftf|SI#O1>=8T~ixz+=#G&+!=mLzxSCoh($QF!+|WgC*(#bxHMH- zw!IBVjh}%`P>g`!pu+T?X$kOR2G~Vgk?Ni*3DOl08Hr9I%(6T^wJM6OU>H5}K*($B zbf$`~sMPd}V8louRR!@8NBHhpDn^AnBmzw(sw99iayo;q2v$M0VPLg5%MRjXhM^1o zDx^{%n}X6hXC8tGFcycD2(5@bP$IOkS8I{P;lKc*sMczRK%-^ztr4mXkqssS(1Edl zX{z+=p9w;mL)iYd3F3haTTIQ_f9T7sx0<~3{Tyo*CZRL7CLpns_ME;Jl7EMI9 zO%?jIoR#dvaZok`lIpO?q$|)uN$0=3E=0z~Ehkdapy^|;QhUe({Q}IBZ zm$dl3WL}7nmQaPytrEoF-b{8?XVxBGoUzs=@N?U+v8GqcT7$`jqnU!0w1;!abdOc2 z!*{JCnlWG{2ZvV)S*wr?oN@Hp_C?8#oHk^w8_umsa%tuaw+U+ywF|>JZIzW=pk?t- zE;)BFV`U5IoU{)uv~p`RhP5Q8jf_}13ZEs@c)^leBbs^k*~#AFTtU+Ztz`Z2cda8M z`Lr=Sl$9Xx09%Dp{&)H-GpOVHwlv*tGS_xI+8S7E}* zj?AEyPu8zjq=x=}cgFqw?b(8r8_8wzCuZH>Ka|&2jb{4$2QzwqzpfQBYf>3j$)?ye z%cWOqxmn9EMAJtuBxM&i8Y62m>r<=EHLN&Ht@MgaU?sWOcmL73?dTVVS6Bz*>F*!G zj%Bc8Yq4V(&!qiJTkEY^jmcU4_>)Ox*Jy)UHp6lK{Z?)Nt*wMCcbl&oYMBTDc9aBbk(xX7E2%X!tz2$XP>tYnHCo)@tk1>xTx@ z`C)A&rQsnqEu>SokbcJ`WoDbPCO@1_t=87(^7uwgvwYw`$qMHp;=8C9bqDdKecV=3 zLYhsN>Eyhaezf!ayp_xM_pi$sYX&n}3oC`~Zqo`{e}DI|p$&EqW1{EgG-D9c??O}k z{i|~pn^w}yNkPo?PH8 zBh#0K@dOiD^_X*u@9tZy zWgY8^ov(X3zaG+zLS}9I|E+$tVVZLv3EY>!*ym_@tD~pLdEe9dK3RRoHDrD3?)$DH zkDo8yQNJl;4ghr-!5W2y9y5L{^GE*jU-d*?93|VASQ*>Oc8?CHmt?XX!?~gS`JHJO z2w+=jb8rwg_13IE{}pQxTjpIpulXsG9NK`U1tzaGzwc}5?_XpMjr8|t^Q+ofp*3Bg z$`ajLb`>1WcdPR&-yOg5!|C^4Q~i99W72HvZ+>&g`9UE5g8(MKUeDa_=hFP|9&{e_ z?s%*oK0Y*@&8ITMsl(?l_?6c~(Q8Yj2Ld;aQHf)~Q+LsVVyEEgEOcE!%B~9*3LE+c81J06?nk6MluVv+q zq0|?0!=vrHq&38`y*uo8?v3iXjJe9%TTQszYMifmI=@Er`+gb{QaG6i^gA1Uw`~mE zSEa2hq(%#w!Rg<3ZY#>%R+ZPZ)v3(T2(_%nE+q?{FL+3M&Ff{A0YBYXc4P?&ESWtH z1Ax`_g%k$|5E}-ZmMQPFGz@r+JRJ(2Hv?;&UPip@hpLV6GA9~{M+3h*r)Fv({lg$J zoJXm;EMpIDz`msN+NfdW0-1ygKNZt$Lvx&#l6Xr=BUUgyIJ{07hE-@ zYw=ghgyHPqh7^wxGbzx3-?Wpim{l!$^Zoa)rjprwTL#{}D&Mfi5$QPc!4cC=<*ck} z<{{#MOs0$I zu@=sx?q3*l=SJUH9<_3g9<r>YH z)MmXh8g!yl-ibC$OXSzCN?{UCl$sNzVk^9>tVnmH@}0nuSTKUpTT+$3cyKjtSEOnN zgU-92{^kp(IOhc7=LBX9mXe`IzZ}^dO=nA;qn^&Ae=z;|kxbLT6p|i2 zF9BFGhu7twJzKHyu6499U}YCsMw>-%jO}Q1s_A$&-AVfq?a~>K^O&devD$ngXK6$F zD1_gic*S((Lceo2)o^#!ke18fsj??W^ zopZc5oWqO^XJGeSs-v@~wL5Tub2kaxT|Y8Bm@ziM5asmHOU^7$=Pde}fPc^`MAS<9 zy{UCU$BpMftQF_GfW9k8gusQ)9f6uV0z~&MqrSVK!ud^U{5PeI2&RZSBLf*DpPI3| zlyKn(C%$QYnXHfh+Zj09s!WtQ6;!GsaIZJTw!U0>1x>y%%2ggJIk3Gvx^M%+_E7xU zl0)IrM2;WLZdh+r9xC@a&BE0L&p!pN}_nRCRdhFL|AqKsUIEU^6aQNk{(#| zfr32qifO|Oug$Kl4dKHJxCFD*)r022`-5gh6hK}1Dw{ijBE)~L|V3# zG_FFzm0O!zlU|)$+l8O!wyx~T7FM>;UD(R4sI2s|%Cdga$mBr5^i@ncr>*YlC-2f! zy*OwIgX=^#z2@T1A39^+YsM1mt(;-yJCUyuZsyBj=NrNJH-bAJj^Prd}F|yUsv`YzxnRW-l{`P<;-Ww<1X#!%Fc!D)RKcM7Z!5E*;PH@%_|4jacjA? zL;Sj-!X=lCSo+00ziNX%WDTz$U86Gshz}q6OSql^CmJmbFVxmr5q4%p`NQT)_i7;S zvkNI47sx4`ljtd29Fp*k6;%ZXzfkg4o}Vpb3WE@<(#|(SXMHmiTJMrV=d*#1&jx5Z z;RlPOhZ0^PJ>!cp($V~7N(yqi&VC(rUyJtF=dlppB^R)LSI3dlb{rw;`E1{WX3M+k)&c#koX}qVD(Gg|sOnzXs8_O%lf=*Rg93>mi z+)^_fk6#?sN}J9O_4bbD2U6$e%v}3OYoUH#cetoKw2~=hR#HeXa5n<+kR68FQ4Sg6KPg-WMmpVVC(m$oV#_-tL-fV&H z@rN&R+NREEn@a!lXX#P@HgmI1Gc&@LQ|gbG`je||EHscJS2=I$f@Wuz7iHHj@3pwv z381m96z*+Un60g(phuZ0sOz{xfs-^`G+Fu8U4-AU%ekIvxSl~&or`8x;po~})A7aN z_@|xs2S>DAK5}!6{gZR=wD`T#+~_;>O2-d~bHI1of#?8Yj;Tjpom$yc=B%Ca&f1y> zOUNL715mH*8+vZqt78p;e=Bcp?Zk?Sfe?}|A^-W^2=3=m8(75Uy7gjb(&KJ>>w^tU!9 z)~B^>cDNA#ewu!=gr4h6@JI{-2n6 zEZubz=nH2dg`9sZg`Bm#3mU?VIWvj3F-eJJO+X}KpGdmqkvH*0iEnds9!^17))^vO zhRB<@5=SMMs7UPVd<@z_yapL`y)L!A>p|+s^;GJ5GW*IA(uj1mGu1P9;eyUZ^Qba! zCgp4()COlBb;&%+SxIhONse4WrLKtmtJ6)=-J~n+IWm=$O?7T5y62W65^BG`F`LS- zDQFN3a-(@C?wu%Ic+*GS(?^}Z`beo~LFtih66n6*w~~)~;cMP12ncHd$Cgv;L9uH+ zq^$j!`{qA1m%;_z%XUvC&JikogzCzX+)5(-l#1P#6NoeO<4e!XlXQfaX2xzhNr3sz z)c#}3S~k9{CsL^je62fLHHY|7@n#QiF^~ITr!7vMR86wQ8;{x{42>SO|1Lu z9E^>suII!gBQ%LD8t9or7%9aGNk(oGnI=(1H6l=lYFRv^Gznajh+4iwwHObY;N&K@ zV=G2U&8g>2G2MJmzI&-#*mg<(_?{;pz~VWQC^I^Ly4%>3w9e zpQ@5m3_53;S`T6{3Z{>VV!hNRPHf^k8mP{`S~81-K4U6hse_wJ*vxVZtmvNY5dD z2JiM2H7vx6{s>nHvAP_UKqqX9XR2THa$?WEB42fDQ31geL*(Ka+{wfET%(P?U&S{5SCwU>bk+Rt)UjP zWyK~@8gF;{A>0qc;?U!A7k2HsL<$b<=UXI;-hnG`&)MCQz4ekA2RA|CF zvmL+1sKzeEG_ltr_cV2@QPg}E*>>aD{LN0!+n${-k+pXg)t!S=*CZo0wRUuD^E4Tx zV}9|zZC;k8=6E^2=W;5+rWi4WKJN^QFu)Et*VZbS9xPjwdj2%UXJ~igZpn*XM~kJm zJ%s7Fv#4n+={Q;=cVDXL@iCW#| z?hoJbqIdc)$A2#5dFMFQ!N2dm6j(g1nFGAlM43@sSr1g7VzKQmibg&-#GGFtdqQF^RHQ8E0c+T{7 zoka-W`Zj$|i64I6F-oMlp2cragxPQn;X5v;+D$LZQ-&A6bG4{=@ik=M`CftV*wg3BZXBFK%1y^rxRGZ4Oh?gVOkFYiF$rSwmm+^6OLZ%Pj4)W{U{btzm3`b3PY=Y zr^}+GKLa~DhKuSR&lVNeRR&&a?d}u3TlN>%h$UE!Z&PK52p0(=pQrbfxh}$VyjQd> zy7{kk1>Lj4w{L9bulya|p4&d>6_a$dOsexYFQl5VzmHStYlxSVui8%ca4^`&lAx9# zGPl^93h#IXZnY8DSh)8~W7UA1y>(uOspb~1M4#*d!u8xY1vP$FLgeZ~kcFdmJn3uj z*Zi!c{;Ot z99q2>tylZUhKW4Z(>1*$eVK=-SN^Ol&3Yz>u-8JdM^5^6_J8yDkB6`iKm73je)!=J z9Q=Ll2mkWne}7m`9O|Uvqr68y?|gxpTj@;n7vbAbIN{xNULc9L`@{2a(w7MP!`oy2vQ4C=Y#mHwa6@3Ld=(k0jB7pTw>$OXA7L!+#3D5l)6L@@|@!@~6;HD&!?y0UWBK z#d&yQPpqZvZ9I_(x5Pqad&tA#J!J};4A+avvSjmJB)lo?XO}k5BP@fbnC4y*J{n$+ z!6d?a!WYF7;hR{d>6wKCvEaqN@gEp0xsW~-*fJg z9w$I1%B=wsb@|r$J^y_qzlC%x zB-2}`mv+>5bEW074Jaqb}DJ5DjUn@<|cC+z(x2KTo=_EE&O!52M~3nqN1I(FnF z`uVfap3_)$DW*Ed%Hkk630B6GI^{$!Cwr#h;}cp>QY#>%FIZ;M#-U&gUnM6FtCCy= zac&?t-$3rkkkwC;d*%@*b*yyYO(li$2wv|dyYF^c@@{bDb3Heo>v4WWcK?XHX_M6| zS$zg^nkliFaLqd?XO!$5h2AFNMV7#Y8D}ebdMj!A8ksYVYPy)ZaVGGkStU*A3qDy+ z7MGJ7Un5N-HSyy&%TLNyHqDPc7n;lhAFew(`!s8j#LPeoK|+)itGYCd2l-IblK2rb ztR~^w7Mzo?E+^v<*Ky9r%XS^9N0% z;f@-oR16>RP%fhqU4jABV?ctl9%|P?qIy<$Q+-`z=RxAsqPyojo*)>E(mtO^pUZZ1 z5tp#CQkugp!moAIk*|x zr11+=_H|@e7pcW~#U=r)TIribx#Wv&-JQUsL@_Nat|OTTcfCgX>WF%=eYO`v>8K_4 zs}!03_3sC2iP}mLzR#g*6_+Do0xa8FgLw40cIO@vzK84ZtQhoib;Qdi7Y|SvW)&DL zi(^xMb(b$GxLi%(aKc$fcD_O|&MUv-dDOG^>>3!3j1+;*VFS3;`6)p; z#i@sT64*`-Be>)ZUx%-Fr_ZyqmNd_&cD;h9dUC}(vjiVFyGX?@u8Y*YsvU+IKH$e3 ztUX=d_f#Bw!jlBCld#5V;lZ;jYVB8i9Ydt+r&Mzt>H8Y>bQVkQPUVsZy;ZOvKFLZ= zhtCblX_k3)N^=(pA~oP6Zw3hWxtVCS;kxYZDeQa@H22cC$XvdAr-#A_xLxj|ZJbj4 zR>S58z#c^;OlRdwDuzI9$!Ug_`{v&1#?}V-#wH-KtzJ2 zEWSSY%{mf7`hvU0^MgWKVAdA-vh_Z2xk5?3%PfT^oX`vG=U!1~1r?l((F@DK2%C5n zhvI$3CBC{4G9OXh`v4L32Lgm?y}ydXw&943Uwyyl5^qs^QLRh;5ptz8n_W}}lU3gk zu+&_V0}*!u`{@u=N99@tgv?SpR|+_}e-fZZT>V72duMA(72ykTdj zYwverPd-ES9iS@eLRds0Ip$4Zd*w8*ta#m9_wQZB{+&N16_FVt!I>KeKdz;_T zcKeky-#1be=-fh4mBC;X>_tXiSsLnqA070xAH4Fc;$8QV+p$-kqUP7gCG}Kb7-Qyk zQ$*eTX2;KccP74+YQSX zI!nl6T*sImTheyySP1tUj)`1pXFbWThfG7E9Kh?H1m(b;gj^s#|ID##21`2U&hPHr zh-(8U-!eFUioM#*i@5KG8*h@5F8Cs~IEYh5anB&Nu5+3{rHwiv&ne|ieDaW64&ZgX z&%b@GxRZRV`El<}AIUkVIhDsz;CMoxixNN1wzvHdO3YigRvo_p0wt=apM>Xmm$&=& zH@a6tCPcc01HN;6$CdXJM}htQ3J`>y9yuXiPxF1%`K#wd>HMpgre?GRQZKnZiT}(N zoChfO0d!b*@QByb?k&6aHzUq|kF?+8O#7&GPIIOepD2$`bM7qt+tPy%U-m3}+2ed2 z7Z^S&65jVvlZ%8O-}5Yc&x5U9hOM0yc|AZs8?O0GxNYKqi^mxj^jY`LP~I5}pgcVm zAak-Wld@kYj-9SVz86WXh4bNl3>6`HD&o9Pa__t07bS<+)t+UmkM-b4{*NuU0A7jO;8SW8^Ahew)#Els@ojC4Db@nV=)Y{$M-UkDNp2Vc3R9|~{ zd+WmXbYW;@mefCOr%gih=LzR^HQB_!5_cZ66=9v4;oM(w*8LUEA3P{q{@@{>74PJB z*N}eoOVdl8FBav#ShVE=k5gZSasaRQ6hCo~)8awdg4eH8C0VmF8Kdos`7f{~ao}m7WY!H!MEd@xKI9)2kXMF8WNs({U4y-D#dcr;m(y z)IDX$W}Gc#?H1y^OqRWTlAZaMkS~a@J^pEN>LXmrw3m+q(XEOnyXkN4m6Ec@OuFU`G5`PXH#&bj3%ui>@L|5}?L2>%)o z{!GuZGmm@ozfW;Kt~`eiul6jv`eVE~x1u<4%!%WlDR-`L>D>}vy@qeEE&7zD8BfkD{)F<{yyD61;Xlue z9W0sbm2Z|S$DGoY!!MjQYkAmD*7-t5J8J%(8;~_g_YP#u$6SKEr;Ws}AYR`UHqIA* z?@J!-t8uS%{;yp>tVx>58mEu=`l__iGz_dJ>D)vDH&x-Si?KDhfxR(JIS@ROq#5bd zV)dbC{zn%|(^Vuo0Xqw}I`5Jr?-Jj;WH|5>?HukWB=9^laTn^??KbYmBylW!wmvp^ z{4$h#%8;IP8>$~y^a3-F--hzNf8;$9c#rTE-)%d=Cyrmn?eCaMd}~Sa$T|{Ox8gcP z1m9P*FBMJz-o$OdQ?BY%f0nwMB%Lo4`^#j-E#yY%BJ+Je+~&J)-n@@)Bp&BJ{n-if zL;WI)`@x+RtL_LcoqXTJrB280C|vcZZw@jPHL$$(S?_#p?+f0A1CN%U<_^Nfd&mkT zX3e=F;v4+9!~NHCWW`m)NgOMa?e)oxvA>)YMfQFE=-gulD<3DjAGe$1w}U_Ca`436 zV41vm4zA|<*8cC@^Ig_ToEOOpFA`_1TOL_UNLAf-6Lvmf<|ob?kF#IrS%UHiULir8 zrbxKr^R0`|97^u*|J3xgzwguCEY+^L;rZRm!1}`bGmm}5V=jKIe&X`)_}x;cx(MZw z>LT)J9T;}=3*D%-c7y!>`q!zC$?v!6nF1h1!= z8$QSMoaej~C5tz&kcpDTn_}+^#a?p$k88O@LEJMO3!dy-HUAN$|1-G#n0vW*m`~$h zvhM5K$iMON;@jsFXNPB^+_}R;q_3Xyh)9!~a8vvj z^fG_Q>84)j#wk(wpUZAw`X@Ue-4jk6b3iE&cfLbj_zomp-*-Yl>iHVICJry8_s0E* zYPa9*x&3Ss$kuF&i3i^O0M`h7V}6XbIb51N5%1nzP6Bsz%%I*~NZvh%^kt?vfg+S_ zpy=ISf6UZ#SdW6|bmeJ$751J|a$)bgH%z(!;i>o_IpY3#`~dzt zL=t3?@gD;tqxv8&_*kw`GX6=aX^r0jcQ1+`|IF{Iep%e*I`IJrQ{ki!T;4bNgVK@Q zusLd+^bmdQGaUZqC$&B`hl?YH@tf%@2XRY3kK0RbM%Zb&N_ z1E2JOF+7?rOw1=dxjK3o%};7OKIzK>u2E~aNQP?@6E$Oh^X23TMkjxZyDzvmIy7=( zeMT@@y0M}TBnKH)?!tub(~ zc__OQm)Id77NUu_wM8q}NU>ckgAne~>L!o64vzk*kD`EoolF@lflx@IEyxy_um`$^Ay${~zq zGwyFm)m+|~JY}jiC!*^ocX`rd|9G#HBKRlwd&+~Kvgh$7|G3#6X9=I&>Ex$AWsje* z!pB3$C-*t|seioBJ?YthwD(CI z>o_y~cXo$sHM%(OGf3Ow*lEgGc z1nD+dxCH?b5PMxg>RPw(5m#Adt1d{qmdm<`=&mesfwk;*fxTR;rzyCj7KQO8_i{^)(Rhqx>gwoS|cP&57Yt9Mr$M667vr4TH z;_h0dpMMP9a$Gw~^w@W8&5II4H66!P<0!Iy+pulNigm-bVka>S%}q?p3gSQuLPIr7 zKXlSDRL?dO-_k70v~5FIEyHkB*N%P9Oe|A1Y$uLXSGO74i%c!C94+!=GmbseHseG; zHio9ziS6kscN&IgB!-`anjPAPuli0BBvBj%uCMDnHb~r14-;2)wZyfwBr&7t*cgTr zg}!F#o@Ho;=9r0*xNaDFwxLCV>3VkLI=bx}L2Sfo7_lll)GgK#>3SR)=@^=31)Axr zdf;hEpc-MIxwakIfuU)UVT6%oX|C@@uBG!-W~Z5n=CPvK)Kyb8kBwodq0Z{`ST)qZ zb7Lp;oW$}}O-*!@+pH)uTrD(Q-bxb9an(e#SQhKz;m6jZnVR94vB6wD&#^fh&DSH7 zX)y~P=c}O=@ByEPz8C6I=&7EnMl9D&9NVcpb+lh|9My7E-wu2$bRFMxJS$ZFIN*4h zla<6)%+4g~A!t$hsju<~$MNjIHG`nPQasw{IEI$QhOYUJ?}VWdSaujV>66XCjYHi_ zeAVDsRMU0sbn}fM2pwK=943yI-*a>Y*N2JbS_ZabtC1Z?mS(uvTj;ofmqeEDM0R9^ zY7}|wkgl7$X~(W^Xto`%idcweIF75ij^}y0=CZ4%&m1F8!3xYU){NNKbW7(zR4;TA z#<6rQa)ZcqF`J}cdE`#dvY55Y3*KlLojeO5?*q1dri-*B->7V8Gb#xPy%Mr99@ z0PAI*dSZB9%oTPV1lYT!>XGW0f$f-HqT_%}B1+7_vsEKXj*a1{AvPRpv2AL);hRxF z1i;DcnN7G^oH+P~WvH&JC!G(PdSc?POgq3Ujn34v2pU9(G&XSbcA^s)Og7TfY(MgS zKMpJ4V{$*oPat8cY7qLil^;CX=Q~amVEBm<>Vyq8O!E!)-tsZ%K($rV(s0)Z zZ;U)UWGE*{LsSsrnr?q(!_huh_m~kU#ty1BzDS%iu>;fgy&%HmHFiFV@fbC5^;jpa zc`VGaLjFcccF$fHS9ZM6W8V{13oVR54`M9Rh`mVjIR{R{*OVixSsRn#cpS%$;v@>A zsGE&&u@FCwjYM||bbjQjL`*YsO)rdN-NJ%XqmML;vxx$qC>WTW99|aqju&M29PNvA zPqmUT4xNY@VB(JDc^1pDT`LNRW45Ck7Qxkwyx3F&li=hBR$!Tt8pMt=*p3eys;0XG zk8g2I4%Nj|lh_P2Hb!Mj5=NTs*`VXv8vCF|mTvj3XSyNLCswx_7^IW9n#M-(0E0Nd z;WAgEioVP74Gu64I2PTBB8T`wj83%J;%!y4qU@f2gYEYdH`0C8F&suwPK^>3XAXk^ z+jmXfjgrU+@Lnu+=C8WgPSaIM8J>0Z!$V$7LiPwg0(5t=->@k0qW8Jw|8tTRYcj?U5gj;Yy>rjZP0|HO0* zouGv8bCcucANddqBLf(^%|4o@7sS4v;N`Ziu|nKo_6r>jTd9)a)L`GGJsQ?ZL{k~S zTy=m2xY!|9!#Sp2$YK++Zs2Q#be*iMa^U0>(^T2Ygt+Gtj?Bm~9m1}eq>+-8l9;L$ zCcbS4Ohh$Jmx+>49df75C`1V>a%~f1QbWUvRYtYdI0)U?u)Kb`BDWTw(>NJC{J;NXUYOe0Km z+xB^;g%jhSn6yUVH)H=TWm1LdV@}##>z~JVh^MLr1n@LQ@Km437e=b85;V!i7FLvI zeGls<0+P7M@;H{~D__d)S!?RCrjubklf4W`@SKp}-K66ysxFV_rel?;p6Dcu*tW>9 z5s8HmNmOGzec(WoX;_Tt|I=f*nvU1$p{tn;s;Ztru2o|U!A=qkEeTbd=%^-M8mU#1 zqHV5h8bL=^iLPb1BM3j6@XjjP-`YK6h7Bj+lSXp2bd~M5K6&*A^jq?mcz?R7o0F_vyBotAu)@XY3~0<7pYoPiFtMy9(n0#AErYfQNti1LK>E-X^!q0M&uJUeBE~w z{43<+APRBbzzDIuNVg&~FAH|k=;(tdETWB1ymE9uaxr-KZ#6>z zmE%>e%>jM~u9%Lo2|EcRKo}9kwn{l$h8`(ecHkQRw-CRc%$Y-O+u+!B(cUErMbbAw=2@;$zT zL+QjwU7tC!n(!4F8d;9$hz}*ev7$;WZg{eJSn&~of1P%sjg*arw5gMF|qhgKZEdoSnc(wx| z!q0pVKd2W#4uUiS`}i0!mITxb)HEu%EV%NNnSfb*k6epk`_|#Z8v<}CWCetWlVMze z89+W#FiJ}D;VswzuotZ96EIi`>?6T7nXv~RBWf6AU=6ehNg=I8RtR3y*St7z)t-ci z6N4xi+$Gy$;do}CB_Z)p_kbCOJA2`JCo()2SwRF<&hp*b~I@70dRxkne~TGFmV5y)h zz>kg(q&JYt;3j^6e`Coh!%0|p{PNL0%OjWCfHdX~u5lCWHb_WV0bA}9Ts7Y1Unqml zPmB)=!=b=-*q^um))f|nhFl6oY9Vz4@(KPU=(1AKv&VweGm+F}Ddf*6z30mRuy_DwvW=oUEF zBDN(F;Wmm*vOge~Q;c0)oVSQa$uS0{8US4&GrSd!sW-08AMImXiDjV|=%#PQI2)MV z2mRr6gl5hLd<1?5s3lNY&(dH@F|I=J)Yzj{@xz_0LSyv=Rdx}eo2ju@Uf@NW;NL>NpHX>Jt6{I&H6=LEw=q;?hd z4c9Z=)KyZ#XkuAb%NOg9Znph|nR|q3Ehc(}i49r+J>noC0nOvh2s}UrFugRNxEcrU z!5nQb#5S$eD=~|d0mLprA|ibge>5-%d?@z+uuK$yeY%F0{V#*$FV>6eStL}bELL=| zXvdltNIjoZeM@=qAe(GJCRBhk?tz;_ejsl;TMhGt7L%?#!k!D|uzhD$`9r`6b`OGz zCj*!LC??CW#XwJxO_<2r8@7UNgAgVa6DD0ag@fEd$PR!cjVp4{5u5ypZxdh%u?}zr zVx{6#kY~2Ww*eJS4Bhw0kHk+Out)>}!w_h6V-={@jflG`9tGu+&Ip;n?g+Xn|9-)0 z7axSJlXuC*i47+5U%0G9Rv1t*td_&b|m*1(v=YaG!KsG`%fL_@oy_l3{ z1DxP0EK%p&tj?!0PAqj(69(r1=Y4#x}lj@ zzoW6MelNk;<9Ok<06^dZsaz++*e=iukYjURaHdGUqtK)q1W`?Xx7dM|Fh2qwF=vkp z54J#B8vA3hwgiW<)KE3p?8wp5a6Ef`0b{lgf4vKjh#*)gMV`G%1gpviuu;H-&&lEU zc(8*Cf#9PON#GGasl~^;ZB(K_UbqmzhP8(pY|V;%`M8|f-2_@jlaL=>uoidY# zY75}Om48+edgq2Mp6Wmfk>ALfP%fL?M$~r_bM_uJfanE|1`dPN9=>-F69&BjFQKkP z4iaL@s6p&N-Y~{WSRPr2ut4f33B&UuKmy?lY!75bjq4M~uav5g?;=m^4zbt5H253NuDF<_V3Dqii60(C1 z6?=pq9mIoH6(IIRTACSHmzI5`HG#YX5tOYxC~pB8CK5yJ$e}u6$d5EM5%P(Chrhvc zaY!PW9tL(`$y4hxo^j;M?XX@~^-c50qd87UURUTq%uNMFl8gMGb^RP*Dvdx*h#<(0 zu?%zmhYRpk|LXpBsJidK`Q@(~wvhQme?%2V1J}&{dMyWt^a`aQ0l+&UV$hD_HZp-nlEc^te$bnUwc)1_-_VvHu4@8% z0_^0+b8E@w_%1VxpfVs16E|;J-LM|=2zW@9a7Y;;H}(iVvM(nb`H?&txJl}U?vk4= z-Ii_(eyahiATt1|*xi4t3lt;DI6NMm*AHiQY#W! z*fvW6jhomH7y%&7f*c~=1gMF`iJ6Uq35E<=N;P%#3V?dMnJ!r0`7Le6^PxnE0KnLOiIx;{4?7;ql5?4D=5@t+*Lf!%TKpf?L zje7yU2HXv(f$^kTeuSC^^kTboCq^YhkpN_M?%nrDzYP>bo&b=Ms+4(2}i7GbGqP(5(4iWKHUEx?b=S6*LS56OU9VWGqiunj4PoHBDw zmkAweF%8@mmZ1&jsHG*ej$&=vdgzLquR z9=0oh*5QvlbVa?1>ZcJ~0vsCCo%yR)z!9YiTb@xr2y6x%07Vc;kRQ>1^LsM3x^GZe z1B*5RZrEC~8Oo92$Em(!p~=a2<=4aE12!0Jf|rx-2_|7AFKek3*OQTnSk!qu3^#&) z0f+6*UDFXcG&CqeIly61I;P~HX2G}(l8Zd0DTgOF4weXK@}bh8MS+LYr5J{Kk(L%> z`9vGB4{n2Bx-n5e-rI6`yNNOi1Awx-AS$Erg1V-dEEJjh) zi{$nBA|nKjzbS`S2hhr)tjg2ti%_4yJ@otrzzgIIN*$nk5?M&qQ2Yv$V8STI6f`_& z2?9(&3`D&4?Mi1WMGz9HdT7fwLM$2>`|_6fGUcb zDJPnWl&PFR{;*yojoa$w^2J?AK=q2)8yT_uvtq`#(Vr-X5UL;m4k*>ZsJ~euJ;O=-s4Bn-P7^ znbQcgLt8{Fzf|gibvXe<6e&x-r*Rsygv1~YlX9bk@`T0eK^6hBvg*ywl%am1htioe zezCqic2Ef6p7I)*vx8*dqpfIWfIzG9nzliL3lLHxdQlhy8YH%?v~{tQ5DP8~?SY6X z4CRV=p=UMbT5?!|{I3h!p^O+$peu73H=Mn=U^}7F_^yITWKb-yET^(tM2*EpEH`w> zOIUisl-MKY#W6#NWvPBOgaRoJm*Q}Nr4~xZY^K#qQ@*Oo$y|2NAm}N83(eagL)zg zJ^Y)5jv{~zr@6tJ1MA^9)Rxool*1$u$vHZ=@#_s`pDG3NXcEcVx+bJ^sw@>Fr0f3`WS-P4@0(oVdeE%ZEWo#H$;<;o< zN|Z7=rIkrhs5j+%nmcTwGDHELSN>B=lcr*{Mt*PwdO5`}0upOBDdG*RTul}s$Wpu^ zxsrK63;yiW9S{SgTqw3b5EVg&PIP2a8QcZzLCZFwx8tK;lwsfF)49gzQkKkTXr0IFU;VU5Ho!UY2J2 zN50$|sOYV6EN`jr(UAnfv8n^Tkk1$8$O2Hsef1eHln>OkY7|J(ljSelX^;6~X2#)X;Gj0yRemZb|7)(Z*n!ZZ zar|-Y%3Br`bi^EaU#Zn(ARzNB`4@sreOV=FMS=Y6qEnzlgW04N|U)HVzGCoR07A)wv7jQWQO1G{N_&;p?6 zCIU4RPy0YPQnI^F@fLY~_P^(d)AGtj`J+YcNV{0LqjwgYsPs|xl1E!MQS|V^T<{5) z7t{i^S;eXc9`2|1kjiMPi4v7obS+tJDQO$)jhjyevixZ@3cxhw5Q zLHHuUMRI;y7m_jXT8n|fEk_riI>KdPK;X=@r{$KL$isLB%_-z9Kwk)nLvy2wM1%tZ zBAx=hqm%k= z{m_;&-3$narseIsu8`{D@{bB@=^==y9G{9d#vJpZN){zw-!a5-O~iaK^c{+ z7Rv9OQefL0`Q6-|CNdl6?EttD-6KYWB!!f72u$z;H?c`K76dm|*OKlC>o8RsSb$z= zR*7C2ZfCDqByRKWQjY4la#t%m4-__~RxayAM$~&dXzWMvn~JIVxi01PeTYH z*HR6qDhCF;x}C}>-tQ*zqo;}p5ZBJEsLY@ug!xLbKy26Kh24QXdggTjetw^@@R;PP-WtLXK@emFf|cM!?-3;NV7l*h>tie7$1`dJ?#Bk~TJ616m{ z?7dT^oQPr34?@X+4aY|?5(=_#bZSkAj3MhnmXUWg^#cZo(UdTNT0YW)iC|9chEf}* z1+1Z3mdLpU#k5YS%l}a?=PjG|bdm-hNk?aH^bPjhVo zAOWcwbm(C902r#x&<-lTZg$TGcs#WM+JVp!AY*jq0i=?Fuir%EqX7*Ar9BGKj!k28 zh!zQ2rpA$Dvb1y!HW3UFu2%iyL9jp8OUn{LBqBrws8*^286j5C1BkMOazoPs6(v;P zSe8nMwsbIOx;H2stNy>Orwxf7KFct`_1uP%$;mK4Dd>|Fd)}>%83THZn9ON0Bl03E1fg6BJl+hTGyh)umj9=z%X{pg6@NU4A3wcaJs-2Pdoy_Y+JEKmiFIMh&O3m5z24GK59lnpw6QsG>qCKq5dT z7#MV2K7VE|Rkm{ZR>BMir2BtOUke>Z0q4$fsq*FK96dF1>5_iP0L4C7F-Sh`FN0() zZlVf%tW?uMOD8>qC@`UXqE4V)HBkqk$Rj^l5}thibfF%;umCj)XFpxw9$lW@EUb!^ z@vKAbvlm~06OauPkS3IbmJw8a>YYy1INgrC*wZ5KSR$`j)I_@zEq#sOJVTbN87Elv zVk^OoEab?yngfkOySiW4GZ(Ce zBM@5HbU-u8rJp#KJhGrbyp8wW4Sq(IGUZcs@{(m4_{DP#yhYQHk>9hHq6+07mIV6) z6VMYw$?Go*O$ghR59RgET`(jAO&wt8$?(h$4wpkj2JP|ebj&EWR2+}+?$qY-(t&*caM^2Z$@jm1S_`R`qe z?$Mm(RUO?YGbCM0|A044SjOti@7c!0@)YnM@?+e z8BGZ2^psQdeA2gdbo^y{7TOLdG=*mQpQ%0sYk(8BLRCb)aV^a(7b) z;2pIbnb@1TzXKM6O}mjBNxjrgvj8=s$e~DS2K&EW1eqareXntl`U2S;$(D#IhA)a3AQSU=DLVv^rs5Zk#EcwJzcE?7j#v#DLRwyqh6v6A@#qV?} zcNNeA68YuE>?2*EIEzX-v+?Bhi^`PN4R9WH0P`%DYy=(Ql&}k0l?EPbLNeqj@{e-^ zU(Lk+{#(;eob%$2c;EDH11L8QEAhsqYbyF)r3w-h&VzX%#dz0N~@p)5FW}FnZX@+v4?S)CprvXn*BvT z^;O#ZXn{o-*HFqFd1&zpKq%gWJnYajLUCN)wWtWzHt3*{SCt3R4bZ#+aCAn}sf3Oo zJIeArAUxbGqzehD8CCXYr2;xYB!`!0LSJ5e3W9E9E}sGG{x@(k-6R!lHN9nVLWW`m zY2y)n@`>EExQP%4P>~Nbtw0`x%2D=2nPhfq=TkY#M)Hq32$O$NDv;MAdHyN%t^!p6 zZlo>Ck-t~~+@LoXatGn_J^#pP6YV)D>D?RJA^UWWMZrvmoNSVZa%tIwrUWdBc0*Op zEMZ2(AMOW8m;h2j7QHb9LDgwIx}Xrbp4Zr*Z()y+?;TJJzuSPcKyS85kE-t}H+3-! zWET1g5_R7XI{?anUMQElDk5YEi5+E2Uv#NOqY6{CCxa0bz-pB5p>053wvxWAC`^Az zBdr#M@~zzkyg@tiWqGizh*N3tzz@k=lx*n50Nm1RHTy*Bj6X=FkF5=IU;7}ai{c5# zM3n_ehu*<~GQVwr97Kx%UJCKqzcypoC=f)=JB$53kPf^C2&Sw7f{f%?BcJrDMUr9| zey4p9q@F69@FOG|n1ISDHG{h-LJ@jsLgNB?!O|w0ULghwAQ2c%i#c-#$7J^a%qX0r zrV!g43MzkhN)M_%9Tg~c2-WgW@*VUQVy(22h0^N)r31Jyvw%W7Tb>{60TmLrAuVW8 z@<i8??K&o5{KvY;`@qg8OZ z8OeX48G(Wmz1uX%_?97C+B;xj)L!Yq4dip>0(!YAXHO9{G%~^|rwjM+w~Lg)9AADb zN6Ud~bfv$df=mS+aQ!76*ehiSz+5u>k5FbF*4vb$l3m%mg}!FGr9xV5eH01U4&C0= zP~zb5U9C7Gp6kn(I?5OqJtRrs$eVIyiai8Ww7~qH9Lk#9)3SyB36LMnT_8oxMA`;Q zVd1eZy9oD`O37-5eBex!X`~`L*4R+$t?{AfD{IO$ks@57ILh;juwOb}FeAbMy%ez= ztdxtosT8!cCp)iMO;S5eC6fREJy>i5%hQ04#lS-WqyE>=XMaKry(x@HB z@_#ktXycWgT{$M#xZ+f0a6KG_a=K5e1KI|$7;F!0dTB`y!beEIGr!(~J?>uCML#i*7GGeYrOD6%4UI!8ZZOuG`G(ba$>Qb2N zSPO?Iq;ghZLwdK4{o&Wc{${B8#_Wl|Dt7njU##Ureo?H6e^yTUm&WCDCz9z8_)~FD zdChoO&GY`q*i`y%JXNPObWBW_&mDW;cpTMHLim62`k535B~Kk?4&^mOuI=TuYu|nv z@0>p|aY=dOSQJl`-#&54B|FB)LVtQ}Vto4xkItPg{y)FIf4XRAPRIVRwYM#9zBhm3 z)_$bn!IQW4)txP$HyQcUae;f+kBz@?&3H1gaV-9T5OXze@Or#P6csKlXS1sp@UOG{ z{IN;SX8W|iZCgAwyinZP$=d^yez-L*Z<~0ZIUY}!lZmNvb!63s^3arjN&JC{sf){c zRsBr2_|Pd_JQ#1=Rz7!nV#9}Dk z6HgBu`q1FS2gbKe_)&Rq?b;%Pth(gfcru?Z7`X6gJ zy%GVvCXx`kqV|r}c*z^ZWiz|1vzH>4jKlj|V z7cCT()5;sB{PFFR%&_6!_6!e8t!*wRPI^7SFIdXu2S0d^Xec$7*TwNPQ`}x(Dh(_i z%UAxXTt0WJKgC<6(rFFFVtMt%_UVBqo5JN7^Y-kbLL8OXuKDv97czdx@s$%+o|>@F zUJstr#@p}PHZgHoc{oMbQ*YU{ZvFc5E6d}vV}CHVFSj&*cHW7`_R0GHBxCzU4R*$3 zju}~VzH2_;zhY8L>i<2{S)iQu#OqBbHIp^xZYuwKrc>y>x#no!>rJPTdw<(>cvEl$ z$8BVEa(W)$A2*A6Q*~lfy0IH@gI7+rykTNu+r?wk=Pwe<4+c++A8bB{oLzX*@$%y< zC*1KH7t_8e>Pw3UC>%`<|6IZ025uWzZ5}_m&5NOVu^1cAS)^XIeBOq)FKMo*=5p02 zt9Gwt^s4U4iddm9*YxGOT~>`=ojYvaYc-Z@+H&1dRu*)v*W6hV8OvI^Qn)%dFV~#1 z=JslQFtnTfRw}@PvTF8PTCc8+tQ4xfTsMJ3y_VW*c??H)`~D7%YusK_@3n?jiUM;q zmFHR+M0a|%bR1n-*`>RjTCc@r>dH{q4>9_;E23a5SH0|RVJN#da;wL!m5YlO4|Ili zi!M!Ny=7JF)r^e~iO*fEWDIkJ0Zk>OuePjJmgRailPfc-ligonN1T!UqWk)?Ue?TB zc0wPySgGz88*@s#vs`5gYVW`&n9>@p!zt?qH?vvXa_RP(R(8)_PDkd-oW-;+R(Q&D zIo&JA%_9}@wPMZiztp_9SYV<0(Bn1fD((3GCasrMX}nQgDRL^`T~XW0M{K60JXGMA z%%N_jz|dOfPnuK~->b4m)llR-#_3iBg&qI?CcT$E)rUTu5oY!wVOAb3n0Bu*^pNNt z7TV0A^r*C&wTAvN zvqn2MgppoU5!sb911!)O{cJ|)1EV}!?KNDU^>|Hp?xL>jRTYunUC_!1#h)4;t+7{% z;jXOEXFj`cO%q${F^@-?$Nn|K%7(%kxku>@#r<8!V(mzLX*~6v`>*ca_xQ}UBe&P| zo+F0-R-{!p`55 z-jGwq7~J{t562g4WTs>K?%Go4&#cSf@h z4;1h|ZD?3&`Fz^?_<1@r^xomrn&c1i17FD)y>co)q}5zS*sEl`@<5UQ)}WZ}d#E;l zRM?H5qM(5xY!h~G&Bnh~uEaIYp5C}kT>YbrX^d>EZ7kMf>jO)LIeJH?`$}QVo>{=t ztR>sLZ!}(9m!atMysjL+G;R~wY70ov^=i3ewC)+csT^SrcEbKqWU5DCP?v%luG%=1{Wi(t6Bj)nl?YFRaGd z+|G`9Y}Um}fxxNldlvq_@g;?QlI!X+syB1`@JHw8AG+wj5=SGe@>&bWMI+_P)2aEo4TTH}F`FI5qro zp>Z;o(Tv&4GSDH8N3|M1mczfSVz(~5{dGds&(2nNi-wBOM*h4u^~;~uEUDxSr+2t6 zTO|_PBTv+(|2iW#Em%^?nA-V79u}=D&t<40TsVLDIsOZc%O4Ws-AZ#fTC5R{HcZSi zhTfVX9uMDk>~2-RF*{6j*3RG8uw*x8(^+qa;?hTz%EeO;iONr|3dQDbMH?Re(t_Uo zVsvS?`8oN&8b>}=TdL6SoymjL_r6vgGcXzW& zeJ4Bi@w)u(=9QOTpBmBkic40qFFSuQPw3ao&tCqKEYJGh!X>*ira97Gmp)s&?$(;2 zus~?P=#S=GkM6uEJA7U#A2PyMcx13(9@g1-V1ZDleqAf9O83SeXEW|{xw{}#xuSV^ zxGul{T^f1q%GS$$%=-LC@>kw})tYSeQ07F!wQF(n(bxUAC%YP&($Ae=XO*s>{QB3w z{`yaT`FFqm^^4h}qGV2c9jyA9A~HwcHupB=wb#$yrT{AY=lYe$`<1za>FbVz$}I{Gk2SY8Y|89fo&Qm( zoDsu$z`EAo&@cK+jMnf(sa$F;^*0wA_J{|UGa;==lV-8BslnxwU8S71x^K16%KV`A ztrw+9X0Ww+{kmM~!REcX-{cOb53j3HkDplp3~OzfYtons_iLF z_H7beu&H@<>0rZTsocDJd5#$zXec&cR%&hNFLjmDDQkD~rPS5eD*B4zjxN#Xin*eA zrYJUlQEYA%a|guc17hc-U^cm(d&K)6d)L;Iy0c&Ol?D5dE3Mv~J4PEgtOrkRzPsi` zxOnG+6|ca>l=+-9^3HdU%;m*zzn0{W!SM4&<{npGdwGxFR#a|VCWg+a{hBM5yk$xK z(7VN4qbN1b#p32z%-th~?-5f6#ncipcY`S1Ft=K~+3WGuuagw8s%QT%E&L5_^`tkm zO6mmjGjI0VJU_#3{pcOdpL(5XA3c4;2_$A^JdPMtR;%Fp1>!Rc#NI{h;kvPKYGOM& zQrVxLj<-+4dXuqjamww>@0{{O6ac+V%-t?NbGx{AOkDJBaWA{FJbgXN*O$}RH~IP{ zasHQtzb-fOmVvp=;{45GZgI_L7T3%@C~kXDJe!D%JaN$}Vy;iI`h?zhtuprurJ?`c zed2R3h(|Yz-j9few>Qkc;|lD$?;WCdqhN~30?}~Sk9~2+5ixhx{JYPZ|Ksn9-W6hb zrD1;W5}_lo=%pULMa=y|Ecu0S>`Afme6cI#5vl6sPwzmK+89rbC1WhAYjEs+V{ebA zrn~1V;{V(0la<$*$?i*=A8$L+p09fAtD+vk_&4+iaPRb*AaA#7t0z#PN^|F+c??~W z)Ii>9l|G$vbEn|%3YT141}PbUbgyb#Z5^W0+>u|?rT6NTmZ45Dytbz8sf@Y2@^lAe3$kWZsdTLoqidADadAzj zfYQNCbSQvZ)tsqJ?amry&Bt4lS6l2@3`6_9)%(vd! z7u6lV?)a_dZ*a@4uv_jL(Md;>KXU1 z>+2+O_bL-GZ@1bhZhT7gtzrAG8V59%uj>^0(>3=`J$j4yx*LbDObuSYRIEC$9l~f@Rl~aI%K2TK0$|^P`fLCCt<30y;>K?( zH+Bg9DKS>K2B@izypX+dT=3T1&7$pQeOPoJ^zVRt8ad`0pErD2P20h{?kGcJZ1%5e zK7D6fM{-$q=n}E>ym^~%Q63!^H{Vh-I?iS79K2E1>|VJmUvR3LdjGfDI=edyP+X(& zJ$a#@y^JxtZynd?Yv*KiL++{*R`thqH`W}R(#`3f?)+Bv&XJ z{>q!z){b%{f2*{Ow{ozMSj|_87AIvrz3#>}sr7xKL$rOR`}E5XDMi+9miG;}viDBa zaBuHSrhz^y&z3hnEBZbuMvp4YN*`y(XO{b?<=m>V`Ij|^MyHNs-+x0Zd!{;wFyEC! zw}|UD=dXEMT=RkK&9e&A8qL@CJtHnxYw{DEvwoX${@)aj8UDIYHOz1O7B;7=a-;;6 z>ovTpXP$YEY`dcI{!&?o0H<<7wc0v=<$7^wYe&k$yH=Y0 z+23|sw{`jXO7`o;RM+5lwK$#ePsq#vzR2=*)C!|g`|n+N~nRyPiB!YQ@cU zta;-HXl6uIkk2)?P zqn%M8ZmJvm7M;zAPSx3XM*e{bQP8cbwsHTw>V!x|y1>Xbe^nUv`STx|t!*9_>gMa) z?s!IY{>9vA?dL{ovlG`XuU&N(Ot`9Vd{CY}Rj}-;8ca&9tH4t1;H;W^Zx!kEOndWz z`8N-XZ0FpR(m7RnM*gaK<3H!l?kehb)$z{EEYNq50zY2G(?W`BdjiO8$xZAZMn#BXjD&4tdI)_L2v@*jHGIN`A$^OHM*ZDZS!_g{Ud zK8m-8Q)82C$H#`L zYu=?a*R(D=;p6S0KTZJv^*`Jyn&13_aAL>!^zrGIPQ0C`?AV@8=apMqPWW(o>s0Jd zZ$rD;cKpuf-}>;x#WbDx>DVQJB8nFb-EwzrTYK9h%X00_g|=qV_UiUE*YHWp&z@CU zo_s=S6D_$Fwh(RYATrThLt0<<>=VkXxBO;{kKgt3P|JN;?%|S?@7nv!Yj>S^49D+# zU~$WndG6z)lkfZ4bHBOogrhos-%~9ukIdsfE;{+X2Y&q8eJ35~@msH3-11mDRjxbv z)*FBR+O2PNt8%#L>6C>0%$=_u8c1*uIaCx@UFEx6-9@ z`N$sw#>CL09T(hK+7*aG7nea2wLY&QWEsHw|-wEyVurN51Z||M*i+2;;x|xhGxtAAj-*5$Jb6`J@Z~)1LfF zO8UJXe!{i?@#mkAMPAK)zk3pIa>IY>OioO*zxQlTzUlQdN@z5gw#{_3lRWX&Pu{={ zPFU+JqaTaL|EE)W?WX_aDIG%-zyD-jyZrUjc+(K|JL1C$8*>6|`Msxd(mk)A&#UM0 ze|u8L2R{~+e`mb>tu?%Q%j>7}AKji;q1o@hIVaxne>#_Ac_hV=6H}z0E0(^}>XD|R z1ZX?yPrZLfd@LWm8b$bof;PGfye~}!OOIv13r|Q!>6owh%!xPAZJ?!#V$A8W6nekz to-0Lb^@JxbpZwtT)`{`*D+9nkUwLG?E7&o%Eh?+s;$@l`)(?zo{~JT=D|!F` literal 0 HcmV?d00001 diff --git a/parquet/condensed_executions_Developers_Dev Audit.parquet b/parquet/condensed_executions_Developers_Dev Audit.parquet new file mode 100644 index 0000000000000000000000000000000000000000..31dd2ea8241482ed8d36ad7b73fc32621c7cca8d GIT binary patch literal 27087 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%0ALwG~H*AYSW&w^&3tyzf+QaaL~k3Ru-mCQKNZf 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 bPtbY(BRj7MrWm^GRM&{@aGssryS4uhb!jn) literal 0 HcmV?d00001 diff --git a/parquet/hashes_rep_bad_Developers_Dev Audit.parquet b/parquet/hashes_rep_bad_Developers_Dev Audit.parquet new file mode 100644 index 0000000000000000000000000000000000000000..88e61d88fc0b75e278fe57e615fb7d406bbd1db3 GIT binary patch literal 15725 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 literal 0 HcmV?d00001 diff --git a/parquet/hashes_rep_good_Developers_Dev Audit.parquet b/parquet/hashes_rep_good_Developers_Dev Audit.parquet new file mode 100644 index 0000000000000000000000000000000000000000..5b0d4d8f447b5fd24ff8e92b90021377b9d1992b GIT binary patch literal 23459 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 RXvUcuayhC@o%r8#|39k*^tk{4 literal 0 HcmV?d00001 diff --git a/parquet/hashes_rep_unknown_Developers_Dev Audit.parquet b/parquet/hashes_rep_unknown_Developers_Dev Audit.parquet new file mode 100644 index 0000000000000000000000000000000000000000..8e04b75bacda056d39fd8898a3122a116031a14b GIT binary patch literal 7325 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 w&?(*OVf literal 0 HcmV?d00001 diff --git a/parquet/path_needs_approved_Developers_Dev Audit.parquet b/parquet/path_needs_approved_Developers_Dev Audit.parquet new file mode 100644 index 0000000000000000000000000000000000000000..880520789ec39d7e2c26e1f4a559cfbc09c2ec67 GIT binary patch literal 3514 zcma)94Qw0L9e;PZIA_PcT35$)QmeS8Y0}}logF7lO9ePzB_(Y`({!zqI^3O~?YrDp z@6L`LXh+K!B0$H7hJcQZmURrY!K!H*15Kc*o%N46CUmB3sH1Z6W1Wpn}JuwPT4;i52^4U;1?rkQtKv&zY)4LQ-#Fgh`d&NS{g(?|`8nf?BP>A;l_gB0Sa z0#8wr41bNbdFHlxf}-py6}UAMLcK(`mxy4TeWC-=v4**04aZ&u)y!MyM5B75ksj2? z_J2gY>Q4!LGUG>~rb4KRs!GFup;LSpYHpI6n>uAv*GS>@yAC6H#%-<;t$2p;v(M3Wz$QsB(&K5fFXs-Sn|{^?LtH_tLNmQOLh3 z4NKZ9HaCy%-oPGRK^q#lyp11CSxjztscBTjobc6Tc z4c=JZ)YB?%fgZHWC++g3D~?sd$T%lI&2@9kxu9R*p^i)-nIM5Tz`fRQ8V0V{TZ8xA z8VvU9+PH$AX!!mU4QD>2G54TNo&%daUNz|2B1U&82y8UrGbVgN%`B$XGw=Ixe%7MR z0cmp}>bPQ+gH>*S2fCxVaz}H-sT4U333U@jH?ih$5dSYic2y9q_U2Z5qs|^p%}X+e zK4{+bL30}ufqjvF%xQRQ^oi%dC!Q52eIZ@6ENHWbSaix~pYqK&(vGDdZ__?+)9_MS zG!#@L?HaktacwB-Qn^sLF-&#y=yX%=bW>CpZAHvW96LY*nSCt8K1!pRNNy%l$3Lww zeIaH&3siJh+qS#f1j|%#f>Yek@RrO7$^$76Vwxh?a7NbhC`3si3dg&mL6?0l!XOrL z#14)){1`|z=9z2!AdPu1TL3_1o?ps*t(ABIO^~?>GJ%;3vxikuWQSX^uNgP=Ye0Ps zFpn)~uV!OE{dI;w2=J5L=svk1^MJUJ2<(L;Dlrt0f6ADwgFcqwdxXe(Mva1yH50=K<$xJMz zFnQ`hNe_m<k$p6JIzMJVB;qi*_0H|@7X z+hN}cpeqRJiiO73C(ubScM^n3xPtT2(G$qy&3U}@r+~(^ciwbgmXGVwnMhJTMH$D6>`QU;MVP^T*c_~5!LW^RgvDsf&Bka?>zph7!Xv}bm zgUNJ;cfCtGM=;wBjEwMkO-tP!Kf4Pw?jkb&VWVK8EEviHzu^oh%-AyEpb0QE0YYOn zEDQ9rJ3(M4NUfX>PEC!Djj_c`z$p7<=$h@&ai@f0t(q3nkk4B+-g1&1iC9PY24Q8Y z{l%DUCxz6y6f6^i#)||<7K$JtsVP`V%O-Caa<&MLbdiO+OetY*v(kHb$Fgzz{^%tD z1mf@8(nMmqoD%W%U*R3Oc(w={iy$o(L1$S{ImvR~;!D$K4-sn)fo?pSs7(tqj$EGR zYk4XAGKebq5*BMhdai*4NvQ-9vqD~WO|8tAQew6Qj@(ax9try|rX<;}*wegfSFr!i z{>;=S!<`!JAIl70Wxqy(UP%QB!N%%PDhj+Us#z7_i@&|Mvs;5{ZKgZPPw!DK<)7{< zA3bteLsW6N%{vCVMvvJ+#i{1C8|9&YH9R^Ff;+C>G15CU4*vO5uzrOH3^S)0zou=q z7&mszitRqHAj#GZS9%<|1a+~60xkY_GUCHRs)%DQ7p!)$I7An)hBdIXYF`b)RBN;~ zv6_yy_*+{*>xIi($S@T?Na9Z`2-6#S0BDV3jS5=oigfkexCtu@%< zZt@Ez;pa{fVG3^&@mQjf7oEs{>e{%B1FIWT3ciY~(21{)O8Wkt)!gf-x8Tz;eYsqNqPFmkj2 literal 0 HcmV?d00001 diff --git a/utils/hashfunctions.py b/utils/hashfunctions.py index 8cec0f9..1a7810b 100644 --- a/utils/hashfunctions.py +++ b/utils/hashfunctions.py @@ -41,23 +41,28 @@ def aggregateHashes(executions_json) -> pd.DataFrame: return agg_df + def augmentAggregatedHashes(url, agg_df: pd.DataFrame) -> pd.DataFrame: """ Takes output of aggregatedHashes, queries API for those hashes, flattens response while keeping one row per hash, aggregate applications and baselines into lists, then merges results back into agg_df to create a """ + if 'sha256' not in agg_df.columns or agg_df.empty: + print("⚠️ 'sha256' column missing or DataFrame is empty. Skipping API query.") + return agg_df.copy() # Return as-is to avoid breaking downstream logic + endpoint = url + '/v1/hash/query' payload = { - "hashes": agg_df['sha256'].tolist() + "hashes": agg_df['sha256'].tolist() } - + headers = {"X-APIKey": os.getenv('APIKEY')} payload = json.dumps(payload) - + response = requests.post(endpoint, headers=headers, data=payload, verify=False) - data = response.json() + data = response.json() results = data.get("response", {}).get("results", []) - + rows = [] for res in results: row = {"sha256": res.get("sha256"), "result": res.get("result")} @@ -80,10 +85,24 @@ def augmentAggregatedHashes(url, agg_df: pd.DataFrame) -> pd.DataFrame: df_api = pd.DataFrame(rows) + if 'sha256' not in df_api.columns: + print("⚠️ API response missing 'sha256'. Skipping merge.") + return agg_df.copy() + df = agg_df.merge(df_api, on="sha256", how="left") - aug_df = df[['sha256', 'filename_x', 'description', 'productname', 'productversion', 'publisher_y', 'publisher_x', 'netdomain', 'hostname', 'username', 'reputation_lastseen', 'reputation_scannermatch', 'reputation_scannercount', 'reputation_status', 'reputation_threatlevel', 'reputation_threatname', 'reputation_timestamp', 'pprocess', 'gprocess', 'commandline', ]] + + # Only include columns that exist to avoid KeyErrors + expected_columns = ['sha256', 'filename_x', 'description', 'productname', 'productversion', + 'publisher_y', 'publisher_x', 'netdomain', 'hostname', 'username', + 'reputation_lastseen', 'reputation_scannermatch', 'reputation_scannercount', + 'reputation_status', 'reputation_threatlevel', 'reputation_threatname', + 'reputation_timestamp', 'pprocess', 'gprocess', 'commandline'] + + available_columns = [col for col in expected_columns if col in df.columns] + aug_df = df[available_columns] + return aug_df - + def categorizeHashes(aug_df: pd.DataFrame, threat_tolerance: int, untrusted_publishers: list): if untrusted_publishers is None: @@ -94,29 +113,29 @@ def categorizeHashes(aug_df: pd.DataFrame, threat_tolerance: int, untrusted_publ def reputationtool(row): val = row["reputation_scannermatch"] if pd.isna(val) or val == "N/A": - return row["publisher_y"] == "Not Signed" + return row["publisher"] == "Not Signed" try: return int(val) > threat_tolerance except (ValueError, TypeError): - return row["publisher_y"] == "Not Signed" + return row["publisher"] == "Not Signed" df["reputation_flag"] = df.apply(reputationtool, axis=1) mask_needsreview = ( - ((df["publisher_y"] == "Not Signed") & df["reputation_flag"]) | + ((df["publisher"] == "Not Signed") & df["reputation_flag"]) | (df["reputation_status"] == "UNKNOWN") ) mask_approved = ( ( - (df["publisher_y"] != "Not Signed") & - ~df["publisher_y"].isin(untrusted_publishers) & + (df["publisher"] != "Not Signed") & + ~df["publisher"].isin(untrusted_publishers) & ~df["reputation_status"].isna() ) | ( - (df["publisher_y"] == "Not Signed") & + (df["publisher"] == "Not Signed") & ~df["reputation_flag"] & - ~df["publisher_y"].isin(untrusted_publishers) & + ~df["publisher"].isin(untrusted_publishers) & ~df["reputation_status"].isna() ) ) diff --git a/utils/pathfunctions.py b/utils/pathfunctions.py index a33318a..470de10 100644 --- a/utils/pathfunctions.py +++ b/utils/pathfunctions.py @@ -17,6 +17,7 @@ import pandas as pd import os from itertools import chain import ast +import re @@ -134,3 +135,28 @@ def filter_and_drop(approved, eligiblepaths, min_hashes): filtered = filtered[filtered['sha256'].apply(len) >= min_hashes] return filtered + + +def inspect_parquet(path): + try: + df = pd.read_parquet(path) + print(f"✅ Successfully read: {path}") + print(f"📄 Columns: {df.columns.tolist()}") + print(f"🔢 Rows: {len(df)}") + return df + except Exception as e: + print(f"❌ Error reading {path}: {e}") + return pd.DataFrame() + + + +def regulator(paths, case_insensitive=True): + """ + Build a Python raw string regex that matches any of the given Windows path fragments. + """ + escaped = [re.escape(p) for p in paths] + pattern = "(?:" + "|".join(escaped) + ")" + if case_insensitive: + pattern = pattern + print(f"Regulator is providing {pattern}") + return f'r"{pattern}"' diff --git a/utils/pretty.py b/utils/pretty.py index 58d89d5..6ea7fa8 100644 --- a/utils/pretty.py +++ b/utils/pretty.py @@ -136,3 +136,78 @@ def style_dataframe_dark(df, output_html_path=None, overwrite=True): print(f"✅ Styled table saved to temporary file: {temp_path}") else: return styled_html + + +def displayIntro(): + + print(colorText(r""" + ███ + ████ ░████████ + █████████████ ███████████████ + █████████████████████ █████████████████████ + ███████████████████ ██████████████████████▓ + ███████████████████ ██████████████████████ + █████████████████████ ███████████████████████ + ████████████████████████████████████████████████████████ + █████████ ██ ██ █████████ + █████████ ██ ███ █ █████████ + █████████ ██ ████ █████ █████████████ + █████████ ██ ██████ █████████████ + ████████ ██ ███████ ████████████░ + ███████ ██ ██▓ ██████ ████████████ + ██████ ██ ████ █████ ███████████ + █████████████████████████████████████████████████ + ▒████████████████████ ██████████████████ + ███████████████████ ███████████████▒ + ███████████████ █████████████ + ██████████ ███████████ + ████████ + ████ +""", "yellow")) + print(colorText(r""" + _____ .__ .__ __ ___________ .__ + / _ \ |__|______| | ____ ____ | | __ \__ ___/___ ____ | | ______ + / /_\ \| \_ __ \ | / _ \_/ ___\| |/ / | | / _ \ / _ \| | / ___/ +/ | \ || | \/ |_( <_> ) \___| < | |( <_> | <_> ) |__\___ \ +\____|__ /__||__| |____/\____/ \___ >__|_ \ |____| \____/ \____/|____/____ > + \/ \/ \/ \/ +""", "cyan")) + print(colorText("=================================================================================", "cyan")) + print(colorText("======================== Welcome to the Airlock API Tool ========================", "cyan")) + print(colorText("=================================================================================", "cyan")) + + +def areYouSure(): + print(colorText(f"*******************************************************************************************************************************************","red")) + print(colorText(f"*=========================================================================================================================================*","yellow")) + print(colorText(f"*=========================================================================================================================================*","red")) + print(colorText(f"*-------------This program will now begin to make changes to the Airlock Console. Do you understand and agree to proceed? ----------------*", "yellow")) + print(colorText(f"*=========================================================================================================================================*","red")) + print(colorText(f"*=========================================================================================================================================*","yellow")) + print(colorText(f"*******************************************************************************************************************************************","red")) + +def locked(): + + print(colorText(r""" + ████████████████████████████████████████████████████████████████ + ███ ██ + ██ ██████ ███ + ██ ████████████ ███ + ██ ████ ███ ███ + ██ ███ ███ ███ + ██ ███ ███ ███ + ██ ▒████████████████████ ███ + ██ ██████████████████████ ███ + ██ ██████████████████████ ███ + ██ ██████████████████████ ███ + ██ ██████████████████████ ███ + ██ ██████████████████████ ███ + ██ ███ + ███ ███ + ████████████████████████████████████████████████████████████████████ + ▒██████████████████████████████████████████████████████████████████▒ + ▒████ + ▒████ + ▓██████████████████████████████████████████ + █████████████████████████████████████████████░ +""", "yellow")) \ No newline at end of file