diff --git a/examples/common/utils.py b/examples/common/utils.py index e4fb1a2..ec0d364 100644 --- a/examples/common/utils.py +++ b/examples/common/utils.py @@ -8,6 +8,9 @@ import nada_numpy.client as na_client import numpy as np import py_nillion_client as nillion +from cosmpy.aerial.client import LedgerClient +from cosmpy.aerial.wallet import LocalWallet +from nillion_python_helpers import get_quote, get_quote_and_pay, pay_with_quote def async_timer(file_path: os.PathLike) -> Callable: @@ -54,6 +57,8 @@ async def wrapper(*args, **kwargs) -> Any: async def store_program( client: nillion.NillionClient, + payments_wallet: LocalWallet, + payments_client: LedgerClient, user_id: str, cluster_id: str, program_name: str, @@ -74,23 +79,35 @@ async def store_program( Returns: str: Program ID. """ - action_id = await client.store_program(cluster_id, program_name, program_mir_path) + quote_store_program = await get_quote( + client, nillion.Operation.store_program(program_mir_path), cluster_id + ) + + receipt_store_program = await pay_with_quote( + quote_store_program, payments_wallet, payments_client + ) + + action_id = await client.store_program( + cluster_id, program_name, program_mir_path, receipt_store_program + ) + program_id = f"{user_id}/{program_name}" if verbose: print("Stored program. action_id:", action_id) print("Stored program_id:", program_id) + return program_id async def store_secret_array( client: nillion.NillionClient, + payments_wallet: LocalWallet, + payments_client: LedgerClient, cluster_id: str, - program_id: str, - party_id: str, - party_name: str, secret_array: np.ndarray, - name: str, + secret_name: str, nada_type: Any, + ttl_days: int = 1, permissions: nillion.Permissions = None, ): """ @@ -99,43 +116,44 @@ async def store_secret_array( Args: client (nillion.NillionClient): Nillion client. cluster_id (str): Cluster ID. - program_id (str): Program ID. party_id (str): Party ID. party_name (str): Party name. secret_array (np.ndarray): Secret array. name (str): Secrets name. nada_type (Any): Nada type. permissions (nillion.Permissions): Optional Permissions. - + Returns: str: Store ID. """ - secret = na_client.array(secret_array, name, nada_type) - secrets = nillion.Secrets(secret) + stored_secret = nillion.NadaValues( + na_client.array(secret_array, secret_name, nada_type) + ) + store_id = await store_secrets( client, + payments_wallet, + payments_client, cluster_id, - program_id, - party_id, - party_name, - secrets, + stored_secret, + ttl_days, permissions, ) + return store_id async def store_secret_value( client: nillion.NillionClient, + payments_wallet: LocalWallet, + payments_client: LedgerClient, cluster_id: str, - program_id: str, - party_id: str, - party_name: str, secret_value: Any, - name: str, + secret_name: str, nada_type: Any, + ttl_days: int = 1, permissions: nillion.Permissions = None, - ): """ Asynchronous function to store secret values on the nillion client. @@ -143,7 +161,6 @@ async def store_secret_value( Args: client (nillion.NillionClient): Nillion client. cluster_id (str): Cluster ID. - program_id (str): Program ID. party_id (str): Party ID. party_name (str): Party name. secret_value (Any): Secret single value. @@ -156,60 +173,76 @@ async def store_secret_value( """ if nada_type == na.Rational: secret_value = round(secret_value * 2 ** na.get_log_scale()) - nada_type = nillion.PublicVariableInteger + nada_type = nillion.Integer elif nada_type == na.SecretRational: secret_value = round(secret_value * 2 ** na.get_log_scale()) nada_type = nillion.SecretInteger - secrets = nillion.Secrets({name: nada_type(secret_value)}) + stored_secret = nillion.NadaValues( + { + secret_name: nada_type(secret_value), + } + ) + store_id = await store_secrets( client, + payments_wallet, + payments_client, cluster_id, - program_id, - party_id, - party_name, - secrets, + stored_secret, + ttl_days, permissions, ) + return store_id async def store_secrets( client: nillion.NillionClient, + payments_wallet: LocalWallet, + payments_client: LedgerClient, cluster_id: str, - program_id: str, - party_id: str, - party_name: str, - secrets: nillion.Secrets, - permissions: nillion.Permissions = None + secret: nillion.NadaValues, + ttl_days: int = 1, + permissions: nillion.Permissions = None, ): """ - Asynchronous function to store secret values on the nillion client. + Asynchronous function to store secrets on the nillion client. Args: client (nillion.NillionClient): Nillion client. cluster_id (str): Cluster ID. - program_id (str): Program ID. party_id (str): Party ID. party_name (str): Party name. - secrets (nillion.Secrets): Secrets. + secret (nillion.NadaValues): Stored secret. permissions (nillion.Permissions): Optional Permissions. + Returns: str: Store ID. """ - secret_bindings = nillion.ProgramBindings(program_id) - secret_bindings.add_input_party(party_name, party_id) - store_id = await client.store_secrets(cluster_id, secret_bindings, secrets, permissions) + receipt_store = await get_quote_and_pay( + client, + nillion.Operation.store_values(secret, ttl_days=ttl_days), + payments_wallet, + payments_client, + cluster_id, + ) + + store_id = await client.store_values(cluster_id, secret, permissions, receipt_store) + return store_id async def compute( client: nillion.NillionClient, + payments_wallet: LocalWallet, + payments_client: LedgerClient, + program_id: str, cluster_id: str, compute_bindings: nillion.ProgramBindings, store_ids: List[str], - computation_time_secrets: nillion.Secrets, + computation_time_secrets: nillion.NadaValues, verbose: bool = True, ) -> Dict[str, Any]: """ @@ -226,20 +259,26 @@ async def compute( Returns: Dict[str, Any]: Result of computation. """ - compute_id = await client.compute( + receipt_compute = await get_quote_and_pay( + client, + nillion.Operation.compute(program_id, computation_time_secrets), + payments_wallet, + payments_client, + cluster_id, + ) + + _ = await client.compute( cluster_id, compute_bindings, store_ids, computation_time_secrets, - nillion.PublicVariables({}), + receipt_compute, ) - if verbose: - print(f"The computation was sent to the network. compute_id: {compute_id}") while True: compute_event = await client.next_compute_event() if isinstance(compute_event, nillion.ComputeFinishedEvent): if verbose: - print(f"✅ Compute complete for compute_id {compute_event.uuid}") + print(f"✅ Compute complete for compute_id {compute_event.uuid}") print(f"🖥️ The result is {compute_event.result.value}") - return compute_event.result.value \ No newline at end of file + return compute_event.result.value diff --git a/examples/complex_model/main.py b/examples/complex_model/main.py index 47c1471..1dcddbb 100644 --- a/examples/complex_model/main.py +++ b/examples/complex_model/main.py @@ -3,7 +3,7 @@ import os import sys -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))) +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import asyncio @@ -12,36 +12,55 @@ import numpy as np import py_nillion_client as nillion import torch +from common.utils import compute, store_program, store_secrets +from cosmpy.aerial.client import LedgerClient +from cosmpy.aerial.wallet import LocalWallet +from cosmpy.crypto.keypairs import PrivateKey from dotenv import load_dotenv -# Import helper functions for creating nillion client and getting keys -from nillion_python_helpers import (create_nillion_client, getNodeKeyFromFile, - getUserKeyFromFile) +from nillion_python_helpers import (create_nillion_client, + create_payments_config) +from py_nillion_client import NodeKey, UserKey -from examples.common.utils import compute, store_program, store_secrets from nada_ai.client import TorchClient -# Load environment variables from a .env file -load_dotenv() +home = os.getenv("HOME") +load_dotenv(f"{home}/.config/nillion/nillion-devnet.env") -# Main asynchronous function to coordinate the process -async def main(): +async def main() -> None: + """Main nada program""" + cluster_id = os.getenv("NILLION_CLUSTER_ID") - userkey = getUserKeyFromFile(os.getenv("NILLION_USERKEY_PATH_PARTY_1")) - nodekey = getNodeKeyFromFile(os.getenv("NILLION_NODEKEY_PATH_PARTY_1")) + grpc_endpoint = os.getenv("NILLION_NILCHAIN_GRPC") + chain_id = os.getenv("NILLION_NILCHAIN_CHAIN_ID") + seed = "my_seed" + userkey = UserKey.from_seed((seed)) + nodekey = NodeKey.from_seed((seed)) client = create_nillion_client(userkey, nodekey) party_id = client.party_id user_id = client.user_id + party_names = na_client.parties(2) program_name = "complex_model" - program_mir_path = f"./target/{program_name}.nada.bin" - - if not os.path.exists("bench"): - os.mkdir("bench") + program_mir_path = f"target/{program_name}.nada.bin" + + # Configure payments + payments_config = create_payments_config(chain_id, grpc_endpoint) + payments_client = LedgerClient(payments_config) + payments_wallet = LocalWallet( + PrivateKey(bytes.fromhex(os.getenv("NILLION_NILCHAIN_PRIVATE_KEY_0"))), + prefix="nillion", + ) - # Store the program + # Store program program_id = await store_program( - client, user_id, cluster_id, program_name, program_mir_path + client, + payments_wallet, + payments_client, + user_id, + cluster_id, + program_name, + program_mir_path, ) # Create custom torch Module @@ -50,7 +69,7 @@ class MyConvModule(torch.nn.Module): def __init__(self) -> None: """Contains some ConvNet components""" - super(MyConvModule, self).__init__() + super().__init__() self.conv = torch.nn.Conv2d(kernel_size=2, in_channels=3, out_channels=2) self.pool = torch.nn.AvgPool2d(kernel_size=2, stride=1) @@ -70,7 +89,7 @@ class MyModel(torch.nn.Module): def __init__(self) -> None: """Model is a collection of arbitrary custom components""" - super(MyModel, self).__init__() + super().__init__() self.conv_module = MyConvModule() self.my_operations = MyOperations() self.linear = torch.nn.Linear(4, 2) @@ -90,44 +109,64 @@ def forward(self, x: torch.Tensor) -> torch.Tensor: # Create and store model secrets via ModelClient model_client = TorchClient(my_model) - model_secrets = nillion.Secrets( + model_secrets = nillion.NadaValues( model_client.export_state_as_secrets("my_model", na.SecretRational) ) + permissions = nillion.Permissions.default_for_user(client.user_id) + permissions.add_compute_permissions({client.user_id: {program_id}}) model_store_id = await store_secrets( - client, cluster_id, program_id, party_id, party_names[0], model_secrets + client, + payments_wallet, + payments_client, + cluster_id, + model_secrets, + 1, + permissions, ) # Store inputs to perform inference for my_input = na_client.array(np.ones((3, 4, 3)), "my_input", na.SecretRational) - input_secrets = nillion.Secrets(my_input) + input_secrets = nillion.NadaValues(my_input) data_store_id = await store_secrets( - client, cluster_id, program_id, party_id, party_names[1], input_secrets + client, + payments_wallet, + payments_client, + cluster_id, + input_secrets, + 1, + permissions, ) # Set up the compute bindings for the parties compute_bindings = nillion.ProgramBindings(program_id) - [ + + for party_name in party_names: compute_bindings.add_input_party(party_name, party_id) - for party_name in party_names - ] - compute_bindings.add_output_party(party_names[1], party_id) + compute_bindings.add_output_party(party_names[-1], party_id) print(f"Computing using program {program_id}") - print(f"Use secret store_id: {model_store_id} {data_store_id}") + print(f"Use secret store_id: {model_store_id}, {data_store_id}") + + # Create a computation time secret to use + computation_time_secrets = nillion.NadaValues({}) - # Perform the computation and return the result + # Compute, passing all params including the receipt that shows proof of payment result = await compute( client, + payments_wallet, + payments_client, + program_id, cluster_id, compute_bindings, [model_store_id, data_store_id], - nillion.Secrets({}), + computation_time_secrets, + verbose=True, ) # Sort & rescale the obtained results by the quantization scale - outputs = outputs = [ + outputs = [ na_client.float_from_rational(result[1]) for result in sorted( result.items(), @@ -135,13 +174,12 @@ def forward(self, x: torch.Tensor) -> torch.Tensor: ) ] - print(f"🖥️ The result is {outputs}") + print(f"🖥️ The processed result is {outputs} @ {na.get_log_scale()}-bit precision") expected = my_model.forward(torch.ones((3, 4, 3))).detach().numpy().tolist() - print(f"🖥️ VS expected plain-text result {expected}") - return result + + print(f"🖥️ VS expected result {expected}") -# Run the main function if the script is executed directly if __name__ == "__main__": asyncio.run(main()) diff --git a/examples/complex_model/tests/complex_model.yaml b/examples/complex_model/tests/complex_model.yaml index 9a30a2c..95492b1 100644 --- a/examples/complex_model/tests/complex_model.yaml +++ b/examples/complex_model/tests/complex_model.yaml @@ -1,161 +1,151 @@ ---- program: complex_model inputs: - secrets: - # We assume all values were originally floats, scaled & rounded by a factor of 2**16 - - # For simplicity's sake, we assume all coefficients and inputs are 2.5 - # 2.5 * 2**16 = 163840 - - my_input_2_1_0: - SecretInteger: "163840" - my_input_2_2_0: - SecretInteger: "163840" - my_input_0_0_2: - SecretInteger: "163840" - my_model_linear.bias_0: - SecretInteger: "163840" - my_model_conv_module.conv.weight_1_0_0_0: - SecretInteger: "163840" - my_model_linear.weight_1_1: - SecretInteger: "163840" - my_input_0_1_2: - SecretInteger: "163840" - my_model_conv_module.conv.weight_0_1_1_0: - SecretInteger: "163840" - my_model_conv_module.conv.weight_0_2_0_1: - SecretInteger: "163840" - my_model_conv_module.conv.weight_1_0_1_0: - SecretInteger: "163840" - my_input_2_1_1: - SecretInteger: "163840" - my_input_1_1_2: - SecretInteger: "163840" - my_input_2_1_2: - SecretInteger: "163840" - my_input_1_2_2: - SecretInteger: "163840" - my_input_2_3_0: - SecretInteger: "163840" - my_input_0_2_0: - SecretInteger: "163840" - my_model_conv_module.conv.weight_1_2_0_1: - SecretInteger: "163840" - my_input_1_1_1: - SecretInteger: "163840" - my_input_2_2_1: - SecretInteger: "163840" - my_model_conv_module.conv.weight_0_1_0_0: - SecretInteger: "163840" - my_input_0_2_1: - SecretInteger: "163840" - my_input_0_0_1: - SecretInteger: "163840" - my_model_linear.weight_1_2: - SecretInteger: "163840" - my_model_conv_module.conv.weight_1_1_0_1: - SecretInteger: "163840" - my_model_linear.weight_1_3: - SecretInteger: "163840" - my_input_0_0_0: - SecretInteger: "163840" - my_model_conv_module.conv.weight_0_0_1_1: - SecretInteger: "163840" - my_model_conv_module.conv.bias_1: - SecretInteger: "163840" - my_input_1_1_0: - SecretInteger: "163840" - my_model_conv_module.conv.weight_1_2_1_0: - SecretInteger: "163840" - my_input_1_3_0: - SecretInteger: "163840" - my_model_conv_module.conv.bias_0: - SecretInteger: "163840" - my_model_conv_module.conv.weight_1_1_1_1: - SecretInteger: "163840" - my_input_0_3_1: - SecretInteger: "163840" - my_input_2_0_0: - SecretInteger: "163840" - my_input_2_2_2: - SecretInteger: "163840" - my_model_linear.weight_0_0: - SecretInteger: "163840" - my_model_linear.weight_0_3: - SecretInteger: "163840" - my_model_conv_module.conv.weight_0_2_1_1: - SecretInteger: "163840" - my_model_conv_module.conv.weight_1_0_0_1: - SecretInteger: "163840" - my_model_linear.weight_0_1: - SecretInteger: "163840" - my_input_2_3_1: - SecretInteger: "163840" - my_model_conv_module.conv.weight_0_1_1_1: - SecretInteger: "163840" - my_model_conv_module.conv.weight_0_0_1_0: - SecretInteger: "163840" - my_input_2_0_1: - SecretInteger: "163840" - my_input_1_3_2: - SecretInteger: "163840" - my_input_1_0_1: - SecretInteger: "163840" - my_model_conv_module.conv.weight_0_0_0_1: - SecretInteger: "163840" - my_model_conv_module.conv.weight_1_1_0_0: - SecretInteger: "163840" - my_model_linear.weight_1_0: - SecretInteger: "163840" - my_input_2_0_2: - SecretInteger: "163840" - my_model_conv_module.conv.weight_0_2_0_0: - SecretInteger: "163840" - my_input_1_0_2: - SecretInteger: "163840" - my_model_conv_module.conv.weight_0_0_0_0: - SecretInteger: "163840" - my_model_conv_module.conv.weight_1_2_1_1: - SecretInteger: "163840" - my_input_0_2_2: - SecretInteger: "163840" - my_model_conv_module.conv.weight_1_2_0_0: - SecretInteger: "163840" - my_model_linear.bias_1: - SecretInteger: "163840" - my_input_1_0_0: - SecretInteger: "163840" - my_input_0_3_2: - SecretInteger: "163840" - my_model_conv_module.conv.weight_1_0_1_1: - SecretInteger: "163840" - my_model_conv_module.conv.weight_1_1_1_0: - SecretInteger: "163840" - my_input_1_2_0: - SecretInteger: "163840" - my_input_0_1_1: - SecretInteger: "163840" - my_input_0_3_0: - SecretInteger: "163840" - my_model_linear.weight_0_2: - SecretInteger: "163840" - my_model_conv_module.conv.weight_0_2_1_0: - SecretInteger: "163840" - my_model_conv_module.conv.weight_0_1_0_1: - SecretInteger: "163840" - my_input_1_2_1: - SecretInteger: "163840" - my_input_1_3_1: - SecretInteger: "163840" - my_input_0_1_0: - SecretInteger: "163840" - my_input_2_3_2: - SecretInteger: "163840" - public_variables: {} + my_input_2_1_0: + SecretInteger: '163840' + my_input_2_2_0: + SecretInteger: '163840' + my_input_0_0_2: + SecretInteger: '163840' + my_model_linear.bias_0: + SecretInteger: '163840' + my_model_conv_module.conv.weight_1_0_0_0: + SecretInteger: '163840' + my_model_linear.weight_1_1: + SecretInteger: '163840' + my_input_0_1_2: + SecretInteger: '163840' + my_model_conv_module.conv.weight_0_1_1_0: + SecretInteger: '163840' + my_model_conv_module.conv.weight_0_2_0_1: + SecretInteger: '163840' + my_model_conv_module.conv.weight_1_0_1_0: + SecretInteger: '163840' + my_input_2_1_1: + SecretInteger: '163840' + my_input_1_1_2: + SecretInteger: '163840' + my_input_2_1_2: + SecretInteger: '163840' + my_input_1_2_2: + SecretInteger: '163840' + my_input_2_3_0: + SecretInteger: '163840' + my_input_0_2_0: + SecretInteger: '163840' + my_model_conv_module.conv.weight_1_2_0_1: + SecretInteger: '163840' + my_input_1_1_1: + SecretInteger: '163840' + my_input_2_2_1: + SecretInteger: '163840' + my_model_conv_module.conv.weight_0_1_0_0: + SecretInteger: '163840' + my_input_0_2_1: + SecretInteger: '163840' + my_input_0_0_1: + SecretInteger: '163840' + my_model_linear.weight_1_2: + SecretInteger: '163840' + my_model_conv_module.conv.weight_1_1_0_1: + SecretInteger: '163840' + my_model_linear.weight_1_3: + SecretInteger: '163840' + my_input_0_0_0: + SecretInteger: '163840' + my_model_conv_module.conv.weight_0_0_1_1: + SecretInteger: '163840' + my_model_conv_module.conv.bias_1: + SecretInteger: '163840' + my_input_1_1_0: + SecretInteger: '163840' + my_model_conv_module.conv.weight_1_2_1_0: + SecretInteger: '163840' + my_input_1_3_0: + SecretInteger: '163840' + my_model_conv_module.conv.bias_0: + SecretInteger: '163840' + my_model_conv_module.conv.weight_1_1_1_1: + SecretInteger: '163840' + my_input_0_3_1: + SecretInteger: '163840' + my_input_2_0_0: + SecretInteger: '163840' + my_input_2_2_2: + SecretInteger: '163840' + my_model_linear.weight_0_0: + SecretInteger: '163840' + my_model_linear.weight_0_3: + SecretInteger: '163840' + my_model_conv_module.conv.weight_0_2_1_1: + SecretInteger: '163840' + my_model_conv_module.conv.weight_1_0_0_1: + SecretInteger: '163840' + my_model_linear.weight_0_1: + SecretInteger: '163840' + my_input_2_3_1: + SecretInteger: '163840' + my_model_conv_module.conv.weight_0_1_1_1: + SecretInteger: '163840' + my_model_conv_module.conv.weight_0_0_1_0: + SecretInteger: '163840' + my_input_2_0_1: + SecretInteger: '163840' + my_input_1_3_2: + SecretInteger: '163840' + my_input_1_0_1: + SecretInteger: '163840' + my_model_conv_module.conv.weight_0_0_0_1: + SecretInteger: '163840' + my_model_conv_module.conv.weight_1_1_0_0: + SecretInteger: '163840' + my_model_linear.weight_1_0: + SecretInteger: '163840' + my_input_2_0_2: + SecretInteger: '163840' + my_model_conv_module.conv.weight_0_2_0_0: + SecretInteger: '163840' + my_input_1_0_2: + SecretInteger: '163840' + my_model_conv_module.conv.weight_0_0_0_0: + SecretInteger: '163840' + my_model_conv_module.conv.weight_1_2_1_1: + SecretInteger: '163840' + my_input_0_2_2: + SecretInteger: '163840' + my_model_conv_module.conv.weight_1_2_0_0: + SecretInteger: '163840' + my_model_linear.bias_1: + SecretInteger: '163840' + my_input_1_0_0: + SecretInteger: '163840' + my_input_0_3_2: + SecretInteger: '163840' + my_model_conv_module.conv.weight_1_0_1_1: + SecretInteger: '163840' + my_model_conv_module.conv.weight_1_1_1_0: + SecretInteger: '163840' + my_input_1_2_0: + SecretInteger: '163840' + my_input_0_1_1: + SecretInteger: '163840' + my_input_0_3_0: + SecretInteger: '163840' + my_model_linear.weight_0_2: + SecretInteger: '163840' + my_model_conv_module.conv.weight_0_2_1_0: + SecretInteger: '163840' + my_model_conv_module.conv.weight_0_1_0_1: + SecretInteger: '163840' + my_input_1_2_1: + SecretInteger: '163840' + my_input_1_3_1: + SecretInteger: '163840' + my_input_0_1_0: + SecretInteger: '163840' + my_input_2_3_2: + SecretInteger: '163840' expected_outputs: - # If you go in and crunch the numbers of this one, the result should be 1542.5 - # 1542.5 * 2**16 = 101_089_280 my_output_1: - SecretInteger: "101089280" + SecretInteger: '101089280' my_output_0: - SecretInteger: "101089280" + SecretInteger: '101089280' diff --git a/examples/linear_regression/main.py b/examples/linear_regression/main.py index 81a987a..efdb3cd 100644 --- a/examples/linear_regression/main.py +++ b/examples/linear_regression/main.py @@ -3,7 +3,7 @@ import os import sys -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))) +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import asyncio @@ -11,39 +11,59 @@ import nada_numpy.client as na_client import numpy as np import py_nillion_client as nillion +from common.utils import compute, store_program, store_secrets +from cosmpy.aerial.client import LedgerClient +from cosmpy.aerial.wallet import LocalWallet +from cosmpy.crypto.keypairs import PrivateKey from dotenv import load_dotenv -# Import helper functions for creating nillion client and getting keys -from nillion_python_helpers import (create_nillion_client, getNodeKeyFromFile, - getUserKeyFromFile) +from nillion_python_helpers import (create_nillion_client, + create_payments_config) +from py_nillion_client import NodeKey, UserKey from sklearn.linear_model import LinearRegression -from examples.common.utils import compute, store_program, store_secrets from nada_ai.client import SklearnClient -# Load environment variables from a .env file -load_dotenv() +home = os.getenv("HOME") +load_dotenv(f"{home}/.config/nillion/nillion-devnet.env") NUM_FEATS = 10 # Main asynchronous function to coordinate the process -async def main(): +async def main() -> None: + """Main nada program""" + cluster_id = os.getenv("NILLION_CLUSTER_ID") - userkey = getUserKeyFromFile(os.getenv("NILLION_USERKEY_PATH_PARTY_1")) - nodekey = getNodeKeyFromFile(os.getenv("NILLION_NODEKEY_PATH_PARTY_1")) + grpc_endpoint = os.getenv("NILLION_NILCHAIN_GRPC") + chain_id = os.getenv("NILLION_NILCHAIN_CHAIN_ID") + seed = "my_seed" + userkey = UserKey.from_seed((seed)) + nodekey = NodeKey.from_seed((seed)) client = create_nillion_client(userkey, nodekey) party_id = client.party_id user_id = client.user_id + party_names = na_client.parties(2) program_name = "linear_regression" - program_mir_path = f"./target/{program_name}.nada.bin" - - if not os.path.exists("bench"): - os.mkdir("bench") + program_mir_path = f"target/{program_name}.nada.bin" + + # Configure payments + payments_config = create_payments_config(chain_id, grpc_endpoint) + payments_client = LedgerClient(payments_config) + payments_wallet = LocalWallet( + PrivateKey(bytes.fromhex(os.getenv("NILLION_NILCHAIN_PRIVATE_KEY_0"))), + prefix="nillion", + ) - # Store the program + # Store program program_id = await store_program( - client, user_id, cluster_id, program_name, program_mir_path + client, + payments_wallet, + payments_client, + user_id, + cluster_id, + program_name, + program_mir_path, ) # Train a linear regression @@ -65,50 +85,69 @@ async def main(): # Create and store model secrets via ModelClient model_client = SklearnClient(fit_model) - model_secrets = nillion.Secrets( + model_secrets = nillion.NadaValues( model_client.export_state_as_secrets("my_model", na.SecretRational) ) + permissions = nillion.Permissions.default_for_user(client.user_id) + permissions.add_compute_permissions({client.user_id: {program_id}}) model_store_id = await store_secrets( - client, cluster_id, program_id, party_id, party_names[0], model_secrets + client, + payments_wallet, + payments_client, + cluster_id, + model_secrets, + 1, + permissions, ) # Store inputs to perform inference for my_input = na_client.array(np.ones((NUM_FEATS,)), "my_input", na.SecretRational) - input_secrets = nillion.Secrets(my_input) + input_secrets = nillion.NadaValues(my_input) data_store_id = await store_secrets( - client, cluster_id, program_id, party_id, party_names[1], input_secrets + client, + payments_wallet, + payments_client, + cluster_id, + input_secrets, + 1, + permissions, ) # Set up the compute bindings for the parties compute_bindings = nillion.ProgramBindings(program_id) - [ + + for party_name in party_names: compute_bindings.add_input_party(party_name, party_id) - for party_name in party_names - ] - compute_bindings.add_output_party(party_names[1], party_id) + compute_bindings.add_output_party(party_names[-1], party_id) print(f"Computing using program {program_id}") print(f"Use secret store_id: {model_store_id} {data_store_id}") - # Perform the computation and return the result + # Create a computation time secret to use + computation_time_secrets = nillion.NadaValues({}) + + # Compute, passing all params including the receipt that shows proof of payment result = await compute( client, + payments_wallet, + payments_client, + program_id, cluster_id, compute_bindings, [model_store_id, data_store_id], - nillion.Secrets({}), + computation_time_secrets, + verbose=True, ) + # Rescale the obtained result by the quantization scale outputs = [na_client.float_from_rational(result["my_output"])] - print(f"🖥️ The result is {outputs}") + print(f"🖥️ The result is {outputs} @ {na.get_log_scale()}-bit precision") expected = fit_model.predict(np.ones((NUM_FEATS,)).reshape(1, -1)) - print(f"🖥️ VS expected plain-text result {expected}") - return result + print(f"🖥️ VS expected result {expected}") -# Run the main function if the script is executed directly if __name__ == "__main__": asyncio.run(main()) diff --git a/examples/linear_regression/tests/linear_regression.yaml b/examples/linear_regression/tests/linear_regression.yaml index 9b4892c..fbebae9 100644 --- a/examples/linear_regression/tests/linear_regression.yaml +++ b/examples/linear_regression/tests/linear_regression.yaml @@ -1,58 +1,47 @@ ---- program: linear_regression inputs: - secrets: - # We assume all values were originally floats, scaled & rounded by a factor of 2**16 - - # All coefficients are scaled random floats between 0 and 1 - my_model_coef_0: - SecretInteger: "30669" # e.g. 30669 = 0.4679718017578125 * 2**16 - my_model_coef_1: - SecretInteger: "22411" - my_model_coef_2: - SecretInteger: "61182" - my_model_coef_3: - SecretInteger: "23548" - my_model_coef_4: - SecretInteger: "52068" - my_model_coef_5: - SecretInteger: "49177" - my_model_coef_6: - SecretInteger: "60541" - my_model_coef_7: - SecretInteger: "55932" - my_model_coef_8: - SecretInteger: "7771" - my_model_coef_9: - SecretInteger: "61119" - my_model_intercept_0: - SecretInteger: "45040" - - # Inputs are an array of 2.5 (2.5 * 2**16 = 163840) - - my_input_0: - SecretInteger: "163840" - my_input_1: - SecretInteger: "163840" - my_input_2: - SecretInteger: "163840" - my_input_3: - SecretInteger: "163840" - my_input_4: - SecretInteger: "163840" - my_input_5: - SecretInteger: "163840" - my_input_6: - SecretInteger: "163840" - my_input_7: - SecretInteger: "163840" - my_input_8: - SecretInteger: "163840" - my_input_9: - SecretInteger: "163840" - public_variables: {} + my_model_coef_0: + SecretInteger: '30669' + my_model_coef_1: + SecretInteger: '22411' + my_model_coef_2: + SecretInteger: '61182' + my_model_coef_3: + SecretInteger: '23548' + my_model_coef_4: + SecretInteger: '52068' + my_model_coef_5: + SecretInteger: '49177' + my_model_coef_6: + SecretInteger: '60541' + my_model_coef_7: + SecretInteger: '55932' + my_model_coef_8: + SecretInteger: '7771' + my_model_coef_9: + SecretInteger: '61119' + my_model_intercept_0: + SecretInteger: '45040' + my_input_0: + SecretInteger: '163840' + my_input_1: + SecretInteger: '163840' + my_input_2: + SecretInteger: '163840' + my_input_3: + SecretInteger: '163840' + my_input_4: + SecretInteger: '163840' + my_input_5: + SecretInteger: '163840' + my_input_6: + SecretInteger: '163840' + my_input_7: + SecretInteger: '163840' + my_input_8: + SecretInteger: '163840' + my_input_9: + SecretInteger: '163840' expected_outputs: - # If you go in and crunch the numbers of this one, the result should be 16.877471923828125 - # 16.877471923828125 * 2**16 = 1106085 my_output: - SecretInteger: "1106085" + SecretInteger: '1106085' diff --git a/examples/multi_layer_perceptron/01_model_provider.ipynb b/examples/multi_layer_perceptron/01_model_provider.ipynb index cfd6e71..c6f2639 100644 --- a/examples/multi_layer_perceptron/01_model_provider.ipynb +++ b/examples/multi_layer_perceptron/01_model_provider.ipynb @@ -7,13 +7,6 @@ "# Multi-layer perceptron" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This demo shows MLP" - ] - }, { "cell_type": "code", "execution_count": 1, @@ -44,22 +37,44 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/vscode/.local/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", - " from .autonotebook import tqdm as notebook_tqdm\n", - "Importing plotly failed. Interactive plots will not work.\n" + "/Users/mathiasleys/projects/venv/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "import json\n", "import os\n", - "from typing import Dict\n", + "import sys\n", "\n", - "import os\n", + "sys.path.append(os.path.abspath(os.path.join(os.getcwd(), os.pardir)))\n", + "\n", + "import json\n", + "import nada_numpy as na\n", + "import numpy as np\n", + "import py_nillion_client as nillion\n", "import torch\n", + "from common.utils import store_program, store_secrets\n", + "from cosmpy.aerial.client import LedgerClient\n", + "from cosmpy.aerial.wallet import LocalWallet\n", + "from cosmpy.crypto.keypairs import PrivateKey\n", + "from dotenv import load_dotenv\n", + "from nada_ai.client import TorchClient\n", + "from nillion_python_helpers import (create_nillion_client,\n", + " create_payments_config)\n", + "from py_nillion_client import NodeKey, UserKey\n", + "\n", "from torch import nn\n", "from torchvision import transforms\n", - "import py_nillion_client as nillion\n", "from sklearn.metrics import (\n", " confusion_matrix,\n", " ConfusionMatrixDisplay,\n", @@ -69,24 +84,15 @@ "from PIL import Image\n", "import numpy as np\n", "\n", - "from dotenv import load_dotenv\n", - "\n", - "# Using Nada AI model client\n", - "from nada_ai.client import TorchClient\n", - "import nada_numpy as na\n", - "import py_nillion_client as nillion\n", - "from nillion_python_helpers import (\n", - " create_nillion_client,\n", - " getUserKeyFromFile,\n", - " getNodeKeyFromFile,\n", - ")" + "home = os.getenv(\"HOME\")\n", + "load_dotenv(f\"{home}/.config/nillion/nillion-devnet.env\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Train an Covid classification model\n", + "### Train a Covid image classification model on CT scans\n", "\n", "Before this step you must install kaggle" ] @@ -100,12 +106,13 @@ "name": "stdout", "output_type": "stream", "text": [ + "Warning: Looks like you're using an outdated API Version, please consider updating (server 1.6.14 / client 1.6.12)\n", "Dataset URL: https://www.kaggle.com/datasets/mehradaria/covid19-lung-ct-scans\n", "License(s): Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)\n", "Downloading covid19-lung-ct-scans.zip to data\n", - "... resuming from 331350016 bytes (767065127 bytes left) ...\n", - "100%|█████████████████████████████████████▉| 1.02G/1.02G [00:30<00:00, 21.3MB/s]\n", - "100%|██████████████████████████████████████| 1.02G/1.02G [00:30<00:00, 24.9MB/s]\n" + "... resuming from 846200832 bytes (252214311 bytes left) ...\n", + "100%|█████████████████████████████████████▉| 1.02G/1.02G [00:31<00:00, 9.06MB/s]\n", + "100%|██████████████████████████████████████| 1.02G/1.02G [00:31<00:00, 8.05MB/s]\n" ] } ], @@ -157,23 +164,22 @@ "outputs": [], "source": [ "# Create custom torch Module\n", - "class MyNN(torch.nn.Module):\n", - " \"\"\"My simple neural net\"\"\"\n", + "class MyNN(nn.Module):\n", + " \"\"\"My brand new model\"\"\"\n", "\n", " def __init__(self) -> None:\n", " \"\"\"Model is a two layers and an activations\"\"\"\n", - " super(MyNN, self).__init__()\n", - " self.conv1 = torch.nn.Conv2d(\n", - " in_channels=1, out_channels=2, kernel_size=3, stride=4, padding=1\n", + " super().__init__()\n", + " self.conv1 = nn.Conv2d(\n", + " in_channels=1, out_channels=2, kernel_size=3, padding=1, stride=3\n", " )\n", - " self.pool = torch.nn.AvgPool2d(kernel_size=2, stride=2)\n", - "\n", - " self.fc1 = torch.nn.Linear(in_features=8, out_features=2)\n", + " self.pool = nn.AvgPool2d(kernel_size=2, stride=2)\n", + " self.fc1 = nn.Linear(in_features=18, out_features=2)\n", "\n", - " self.relu = torch.nn.ReLU()\n", - " self.flatten = torch.nn.Flatten()\n", + " self.relu = nn.ReLU()\n", + " self.flatten = nn.Flatten()\n", "\n", - " def forward(self, x: np.ndarray) -> np.ndarray:\n", + " def forward(self, x: na.NadaArray) -> na.NadaArray:\n", " \"\"\"My forward pass logic\"\"\"\n", " x = self.relu(self.conv1(x))\n", " x = self.pool(x)\n", @@ -181,7 +187,6 @@ " x = self.fc1(x)\n", " return x\n", "\n", - "\n", "my_model = MyNN()" ] }, @@ -219,95 +224,95 @@ "output_type": "stream", "text": [ "Starting epoch 1...\n", - "Loss after mini-batch 100: 0.541\n", - "Accuracy after mini-batch 100: 88.938\n", - "Loss after mini-batch 200: 0.516\n", - "Accuracy after mini-batch 200: 87.812\n", - "Loss after mini-batch 300: 0.487\n", - "Accuracy after mini-batch 300: 89.500\n", - "Loss after mini-batch 400: 0.471\n", - "Accuracy after mini-batch 400: 88.375\n", + "Loss after mini-batch 100: 0.692\n", + "Accuracy after mini-batch 100: 56.812\n", + "Loss after mini-batch 200: 0.671\n", + "Accuracy after mini-batch 200: 89.125\n", + "Loss after mini-batch 300: 0.649\n", + "Accuracy after mini-batch 300: 87.812\n", + "Loss after mini-batch 400: 0.617\n", + "Accuracy after mini-batch 400: 89.062\n", "Starting epoch 2...\n", - "Loss after mini-batch 100: 0.442\n", - "Accuracy after mini-batch 100: 88.688\n", - "Loss after mini-batch 200: 0.441\n", - "Accuracy after mini-batch 200: 87.562\n", - "Loss after mini-batch 300: 0.404\n", - "Accuracy after mini-batch 300: 89.375\n", - "Loss after mini-batch 400: 0.403\n", - "Accuracy after mini-batch 400: 88.938\n", + "Loss after mini-batch 100: 0.579\n", + "Accuracy after mini-batch 100: 87.375\n", + "Loss after mini-batch 200: 0.531\n", + "Accuracy after mini-batch 200: 89.562\n", + "Loss after mini-batch 300: 0.500\n", + "Accuracy after mini-batch 300: 87.750\n", + "Loss after mini-batch 400: 0.462\n", + "Accuracy after mini-batch 400: 88.812\n", "Starting epoch 3...\n", - "Loss after mini-batch 100: 0.381\n", - "Accuracy after mini-batch 100: 89.500\n", - "Loss after mini-batch 200: 0.383\n", - "Accuracy after mini-batch 200: 88.938\n", - "Loss after mini-batch 300: 0.380\n", - "Accuracy after mini-batch 300: 87.812\n", - "Loss after mini-batch 400: 0.376\n", - "Accuracy after mini-batch 400: 88.312\n", + "Loss after mini-batch 100: 0.437\n", + "Accuracy after mini-batch 100: 87.250\n", + "Loss after mini-batch 200: 0.404\n", + "Accuracy after mini-batch 200: 88.375\n", + "Loss after mini-batch 300: 0.389\n", + "Accuracy after mini-batch 300: 88.875\n", + "Loss after mini-batch 400: 0.350\n", + "Accuracy after mini-batch 400: 89.875\n", "Starting epoch 4...\n", - "Loss after mini-batch 100: 0.369\n", - "Accuracy after mini-batch 100: 88.562\n", - "Loss after mini-batch 200: 0.352\n", - "Accuracy after mini-batch 200: 89.312\n", - "Loss after mini-batch 300: 0.363\n", - "Accuracy after mini-batch 300: 88.375\n", - "Loss after mini-batch 400: 0.372\n", - "Accuracy after mini-batch 400: 88.062\n", + "Loss after mini-batch 100: 0.347\n", + "Accuracy after mini-batch 100: 89.500\n", + "Loss after mini-batch 200: 0.371\n", + "Accuracy after mini-batch 200: 88.000\n", + "Loss after mini-batch 300: 0.357\n", + "Accuracy after mini-batch 300: 88.688\n", + "Loss after mini-batch 400: 0.381\n", + "Accuracy after mini-batch 400: 87.875\n", "Starting epoch 5...\n", - "Loss after mini-batch 100: 0.340\n", - "Accuracy after mini-batch 100: 89.625\n", - "Loss after mini-batch 200: 0.362\n", - "Accuracy after mini-batch 200: 88.438\n", - "Loss after mini-batch 300: 0.365\n", - "Accuracy after mini-batch 300: 88.312\n", - "Loss after mini-batch 400: 0.369\n", - "Accuracy after mini-batch 400: 87.938\n", + "Loss after mini-batch 100: 0.360\n", + "Accuracy after mini-batch 100: 88.625\n", + "Loss after mini-batch 200: 0.365\n", + "Accuracy after mini-batch 200: 87.938\n", + "Loss after mini-batch 300: 0.363\n", + "Accuracy after mini-batch 300: 88.562\n", + "Loss after mini-batch 400: 0.332\n", + "Accuracy after mini-batch 400: 89.812\n", "Starting epoch 6...\n", - "Loss after mini-batch 100: 0.354\n", - "Accuracy after mini-batch 100: 88.688\n", - "Loss after mini-batch 200: 0.366\n", - "Accuracy after mini-batch 200: 88.312\n", - "Loss after mini-batch 300: 0.342\n", - "Accuracy after mini-batch 300: 89.562\n", - "Loss after mini-batch 400: 0.365\n", - "Accuracy after mini-batch 400: 87.812\n", + "Loss after mini-batch 100: 0.343\n", + "Accuracy after mini-batch 100: 89.312\n", + "Loss after mini-batch 200: 0.362\n", + "Accuracy after mini-batch 200: 88.250\n", + "Loss after mini-batch 300: 0.358\n", + "Accuracy after mini-batch 300: 88.438\n", + "Loss after mini-batch 400: 0.362\n", + "Accuracy after mini-batch 400: 88.438\n", "Starting epoch 7...\n", - "Loss after mini-batch 100: 0.373\n", - "Accuracy after mini-batch 100: 87.812\n", + "Loss after mini-batch 100: 0.352\n", + "Accuracy after mini-batch 100: 88.875\n", "Loss after mini-batch 200: 0.348\n", - "Accuracy after mini-batch 200: 88.938\n", - "Loss after mini-batch 300: 0.338\n", - "Accuracy after mini-batch 300: 89.438\n", - "Loss after mini-batch 400: 0.350\n", - "Accuracy after mini-batch 400: 89.062\n", + "Accuracy after mini-batch 200: 89.000\n", + "Loss after mini-batch 300: 0.357\n", + "Accuracy after mini-batch 300: 88.312\n", + "Loss after mini-batch 400: 0.345\n", + "Accuracy after mini-batch 400: 89.000\n", "Starting epoch 8...\n", - "Loss after mini-batch 100: 0.352\n", - "Accuracy after mini-batch 100: 88.938\n", - "Loss after mini-batch 200: 0.354\n", - "Accuracy after mini-batch 200: 88.438\n", - "Loss after mini-batch 300: 0.341\n", - "Accuracy after mini-batch 300: 89.500\n", - "Loss after mini-batch 400: 0.373\n", - "Accuracy after mini-batch 400: 87.812\n", + "Loss after mini-batch 100: 0.342\n", + "Accuracy after mini-batch 100: 89.188\n", + "Loss after mini-batch 200: 0.366\n", + "Accuracy after mini-batch 200: 87.938\n", + "Loss after mini-batch 300: 0.357\n", + "Accuracy after mini-batch 300: 88.562\n", + "Loss after mini-batch 400: 0.343\n", + "Accuracy after mini-batch 400: 88.812\n", "Starting epoch 9...\n", - "Loss after mini-batch 100: 0.358\n", - "Accuracy after mini-batch 100: 88.438\n", - "Loss after mini-batch 200: 0.367\n", - "Accuracy after mini-batch 200: 88.062\n", - "Loss after mini-batch 300: 0.360\n", - "Accuracy after mini-batch 300: 88.625\n", - "Loss after mini-batch 400: 0.340\n", - "Accuracy after mini-batch 400: 89.062\n", + "Loss after mini-batch 100: 0.334\n", + "Accuracy after mini-batch 100: 89.875\n", + "Loss after mini-batch 200: 0.364\n", + "Accuracy after mini-batch 200: 87.938\n", + "Loss after mini-batch 300: 0.363\n", + "Accuracy after mini-batch 300: 87.812\n", + "Loss after mini-batch 400: 0.343\n", + "Accuracy after mini-batch 400: 88.938\n", "Starting epoch 10...\n", - "Loss after mini-batch 100: 0.351\n", - "Accuracy after mini-batch 100: 88.812\n", - "Loss after mini-batch 200: 0.347\n", - "Accuracy after mini-batch 200: 88.875\n", - "Loss after mini-batch 300: 0.370\n", - "Accuracy after mini-batch 300: 87.938\n", - "Loss after mini-batch 400: 0.342\n", - "Accuracy after mini-batch 400: 89.250\n" + "Loss after mini-batch 100: 0.336\n", + "Accuracy after mini-batch 100: 89.812\n", + "Loss after mini-batch 200: 0.351\n", + "Accuracy after mini-batch 200: 88.312\n", + "Loss after mini-batch 300: 0.361\n", + "Accuracy after mini-batch 300: 88.000\n", + "Loss after mini-batch 400: 0.355\n", + "Accuracy after mini-batch 400: 88.375\n" ] } ], @@ -355,7 +360,7 @@ { "data": { "text/plain": [ - "[]" + "[]" ] }, "execution_count": 8, @@ -364,7 +369,7 @@ }, { "data": { - "image/png": "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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAh8AAAGdCAYAAACyzRGfAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAABGIUlEQVR4nO3deVhU5eIH8O+wDSibimyKiLgr7kq4tUiKmWl6TctK0zKNMrUs7ZeaWaG2mV7TFjNbtLSrVrer5oqaiKgorgiKAsqiIDMIzAAz7+8PYARFZWDmHOR8P88zzwMzh+E9c2De77yrSgghQERERCQRG7kLQERERMrC8EFERESSYvggIiIiSTF8EBERkaQYPoiIiEhSDB9EREQkKYYPIiIikhTDBxEREUnKTu4C3MpoNOLKlStwcXGBSqWSuzhERERUBUII5ObmwtfXFzY2d2/bqHXh48qVK/Dz85O7GERERFQNKSkpaNq06V2PqXXhw8XFBUBJ4V1dXWUuDREREVWFVquFn5+fqR6/m1oXPsq6WlxdXRk+iIiI7jNVGTLBAadEREQkKYYPIiIikhTDBxEREUmK4YOIiIgkxfBBREREkmL4ICIiIkkxfBAREZGkGD6IiIhIUmaHj9zcXEybNg3+/v5wcnJC7969ERMTY3pcCIG5c+fCx8cHTk5OCA0NRUJCgkULTURERPcvs8PHiy++iO3bt+PHH3/EiRMnMHDgQISGhuLy5csAgMWLF2Pp0qVYuXIloqOjUb9+fQwaNAg6nc7ihSciIqL7j0oIIap6cEFBAVxcXPD7779jyJAhpvu7d++OwYMHY8GCBfD19cUbb7yBN998EwCg0Wjg5eWF77//HmPGjLnn79BqtXBzc4NGo+Hy6kRERPcJc+pvs1o+iouLYTAY4OjoWOF+Jycn7N+/H0lJSUhPT0doaKjpMTc3NwQHByMqKqrS59Tr9dBqtRVuREREVHeZFT5cXFwQEhKCBQsW4MqVKzAYDPjpp58QFRWFtLQ0pKenAwC8vLwq/JyXl5fpsVtFRETAzc3NdPPz86vmqRDd2V9xaVgZeR7nr96QuyhEVE0Go8CvMcmIvpAld1Gohswe8/Hjjz9CCIEmTZpArVZj6dKlePrpp2FjU72JM7Nnz4ZGozHdUlJSqvU8RJUxGgUWbjmL8LVHsXDLWQz4NBJhS/biix0JSMzMlbt4ddausxl4+JM9mLnhOM6ksTWTaq6w2Iip62Lx9n9O4LnvDiElO1/uIlVZdl4hwtcexeivopCdVyh3cWoFO3N/IDAwEJGRkcjLy4NWq4WPjw9Gjx6NFi1awNvbGwCQkZEBHx8f089kZGSgS5culT6fWq2GWq2uXumJ7kJfbMDMDXH44/gVAEC3Zu6IS9XgbHouzqbn4vMd59DK0xmDg3wwJMgHrb2cq7QVNN3doaRsTPnpKPTFRiRdy8OGI6noHdgIE/sG4OE2nrCx4WtM5skvLMbkn45i77mrAEqCyAd/ncZXz/WQuWT3Fpt8HeE/H8UVTcmkixnrj+G7cT0V/39Q7XU+6tevDx8fH1y/fh3btm3DsGHDEBAQAG9vb+zcudN0nFarRXR0NEJCQixSYLo7IQT2xGci64Ze7qLISpNfhOdXHcIfx6/AzkaFT0d1xsZX+uDIu4/i4391wiNtPWFvq0JC5g0s3ZmAQUv2YsBnkfj073icvqKFGeOwqZyz6VpMXBMDfbER/Vs3xpBOPrC1UeHA+SxMXHMYAz6LxA9RF5GnL5a7qHSf0BSU/C/vPXcVTva2mDe0PWxtVNh2KgP7Eq7KXbw7EkLg+3+S8NRXUbii0aF5o3pQ29lgT/xVrIg8L3fxZGfWbBcA2LZtG4QQaNOmDRITEzFz5kw4Ojpi3759sLe3x6JFi7Bw4UKsWbMGAQEBmDNnDuLi4nD69OnbBqpWhrNdaubXmGS8/Z8TaOfjij9e7QN7W+WtI5d6PR8vrI5BQuYNOKvtsOLZbujXqvFtx2kKirDzTAb+dyIde89dRaHBaHoswKM+5g1tj4faeEpZ9PtaSnY+Rq44gMxcPXr4N8CPE4Ph5GCLyzkF+OHARaw9lIxcXUnocHW0w9O9muH53s3RxN1J5pJTbXU1V49x3x3C6TQtXB3tsPqFnuju3xDv/XEK3x+4iJaeztjyer9a9z6Xpy/GrI0n8Gdpq+tjQd5YNLITtpxIx1v/iYONClj70gN4oEUjmUtqWebU32aHj/Xr12P27NlITU1Fw4YNMXLkSHz44Ydwc3MDUJL25s2bh6+//ho5OTno27cvvvzyS7Ru3drihaeKdEUGPPzJHqSVNu/NGtwWkx8MlLlU0jp1RYMXVscgM1cPL1c1Vo/vhfa+9/47ytUVYdfZTPzvRBr2xF+FvtiI+g62+OO1vghs7CxBye9vWTf0GLUyCheu5aGNlwvWvxwCt3r2FY7J0xfjtyOpWP1PEi5mlfTX29qoENbRGxP7BqBbswZyFJ1qqcs5BXj222gkXcuDh7MaP07shXY+Jf/LmvwiPPzpHmTnFeLdIe3wYr8WMpf2poSMXEz+6QjOX82DnY0Ksx9rhwl9mpu6dN/ccBy/HUlFYxc1/je1Hxq71J1hB1YNH9bG8FF9q/YnYcF/T0NtZwN9sRGO9jbYPv1B+DWsJ3fRJBF57ipe+ekI8goNaOPlgtUv9IRvNT5V39AX48U1MTh4IRttvFywObwPnBxsrVDiuuGGvhjPfHMQcakaNHF3wn+m9Ia3251bOY1GgV1nM/HdP0k4cP7mrIVeAQ3x72e6wtPl3i2kVLclZt7Ac6uikabRoYm7E356MRgBHvUrHPPLoWTM2ngCLmo77HrzoVpRif9+7DJmbzyB/EIDvFzVWP5MN/Ro3rDCMQWFBgxf/g/iM3LRO7ARfpwYDNs6Mv7Daut8UO2Vpy/Gl7sTAQDzhnbAAy0aQldkxLubTypi/ML6mBRM+D4GeYUG9A5shA1TQqoVPADAWW2HpU93hYezGvEZuZj7+0kLl7buKCw2YvKPRxCXqkHD+g74YWKvuwYPALCxUSG0vRfWvvQA/je1H0Z1bwoHWxscSsrGqJVR99UshvtNdl4hoi9k4aeDlxCx5Qzi02vfjK+TlzV46qsopGl0aOnpjN+mhNwWPABgVA8/BDVxQ66+GB9vOytDSW/SFxswZ/NJvP7LMeSXvgf9NbXfbcEDAJwcbLF8bDfUc7DFgfNZ+GLHORlKLD+2fNzB7vhMfPDf05g1uB0ebe917x8wgxACp9O0aOvtarHEu3x3Ij7eFg//RvWwY8aDSM7Ox+Al+1BoMGLp013xRGdfi/ye2kYIgSU7EvDFzpL9g57s2gSLRnaCg13Nc/WB89fw7LfRMApg8b864akeXIOmPKNR4PVfj+HP41dQz8EW6156AJ393Kv1XBev5eG576KRkl0AL1c1fpoYjFZeLpYtsEIIIXDtRiESMnORmHkDCRk3cC6j5OusW6Z5NqzvgA2TQ2pN1+KhpGxM/D4GufpiBDVxw5oJvdCwvsMdjz9yKRsjV5QsYLk5vA+6VPPvryZSr+cjfG0sjqfkAABefbglpj/a+p7v7b8fu4zXfzkGlQr4/oVeeLD17ePS7jfsdrGA2RvjsO5QCtR2Nlg36QGL9UcLIfD2f+Kw/nAqhgT54N/PdK3x9E5NfhH6Ld4Fra4YS0Z3wfCuTQAAX+xIwOc7zsHD2QE7Zzx0Wx/8/a7IYMQ7G09gw5FUAED4w4F4c2Abi06X/feuBHzy9zk42ttgc3gftPVmVyBQ8nc8/8/T+P7ARdjbqrBqXE/0r+GbZ7pGh+dWRSMh8wYa1LPHmgm90Kmpu2UKLDEhBLLzCpGm0SFdo0OaVod0TQHSNXoEetbHC70DLNqVV1BowLf7LmBfwjWcy8xFTn7RHY9t2sAJrb1ckJKdj4TMG2ji7oSNr/SGl6u83V27z2Zi8k9HoC82IjigIb4d1wMujvd+z5rx6zFsjL2Mzn7u2DSlt6RTWPfEZ2Lar8eQk18ENyd7fD66Mx5pW/UPq/+36QR+jk5Gw/oO+GtqX/i43d+Drxk+LGDaL7HYfKxkpHKj+g7Y9EofNGtU87ETi7aexYo9N6dZfTGmC4Z1aVKj5/x421ks330erb2cseX1/qbErS824LEv9uH81Tw83csPESM61ej31CZXc/WYsf4Y9iVcg40K+GB4EJ4Jbmbx32M0Coz/PgZ7z11Fi8b18cerfeGsNnt5nDqnrKUNsMzfcJnreYUYv/oQjqdqUN/BFt+O64mQwNo7IyDpWh72JVzFlRwd0jQFprCRrtWhsNh4x59r2sAJ7w3tgFALtKpuP52B+X+eQur1AtN9KhXg37AeWnq6oJWXM1p5OqOVpwsCPeujnkPJ3++10kHCSXcZJCyVP45fwYxfj6HYKDCgrSeWj+0GR/uqhbNMrQ4Pf7IHeYUGfPyvThglUQvlmgMX8d6fpyAEENTEDV+O7Wb2+DpdkQEjVxzAqSta9PBvgHWTHqh1M3fMwfBhAZN/PIKtp9JhZ6NCsVGgReP62DilN9zr3bkJ8F7KBoQCQO/ARjhwPgtuTvbYPr0/PKv5qePaDT36L96N/EIDvnquOwZ18K7wePSFLIz++iAAYMPkEPSspA+yqrLzCrFwyxl0bdYAT/eyfEVfFWfStPhufxJ+P3YFhQYjnOxtsXxsV7M+bZgrO68QQ5buQ5pGh6GdfbF0TBdFL0ZWNtAPAOYNbY8X+gRY9Plv6Ivx0prDiLqQBQc7G3z5TDeLVNKWkl9YjL/i0rDhcCoOXcy+67GNXdTwcXOEt6sjfNwc4V7PAesPp5hmpA1o64n3nuhQrUHhyVn5mP/nKew8mwkA8HVzxNQBrdCpqTtaNK5fpco7JTsfI1YcwNVcPXo2L5keXdVKvyYMRoGEzFzEJucg5mI2NsVehhDAsC6++GRUZ7Mr4K8izyNiy1l4ODtg15sPwbUKLSY1Uf69/Olefpg3tEO1X7dLWXl4fNl+5OqK8XL/Fpj9WDtLFlVSDB8WMH71IeyJv4qZg9rg54OXcEWjQ6+AhvhxYi+o7cz/I9scexnTfj0GAJg5qA0m9W+BEV8ewInLGgxo64lvx/WoVoX2/p+n8d0/Sejc1A2bw/tU+hxv/xaHXw+noJWnM/6a2q9a4yHSNAV4btUhJGaW7I2y+oWeeFiiNTCMRoHd8ZlYtb/i7IjOfu74YFhHBDV1s3oZjlzKxuivDqLYKLBgeEc894B/tZ6noNCATbGXEdTETZJyW9q2U+mY8tMRGEVJN9fMQW2t8nt0RQa8ti4W209nwNZGhU9GdcKTXZta5XdVhRACsSk5WB+Tgj+PX0FeoQEAYKMC+rT0QEtP55KQ4eZkChtero6V/q/l6YuxdFcCVu1LQrFRQG1ng/CHW2JS/xZVqsB0RQZ8FXkBX+5JhL7YCHtbFV7s1wKvPdLS1KphjjNpWjz1VRRydcUIbeeJlc92h52FP31n3dDjWEoOjiZfR2xyDo6n5JhewzLPPeCP+U90qFa3SWGxEWFL9uLCtTy82DcA7z7e3lJFv823+y7gg7/OAABeeSgQMwfVvKt368l0TP7pCADgm+d7WHycoVQYPixgzNdROHghG0uf7orWXs4YtSIKufpiDOviiyWjzfvkuyc+Ey+uOYxio8ALfZpj7uPtoVKpEJ+ei6HL9qPQYMQnozrjX93Ne3NN0xTgwY/3oLDYiB8m9Lpjn3tOfiFCP4vEtRuFeOPR1nhtQCuzfk/StTw8+200LucUmFqCGtV3wJZp/aw6LTJPX4z/HE3F6n8uIulaHgB514Uoe9NxsLXBf6b0Nis8CCFKm8dP43JOAWxtVJj6SCuEPxxosTf601e0iNhyBo2d1ZgZ1sbi/cfRF7Lw3HeHUFhsxJiefogYEWTVFqBigxFv/RaHjbGXAQDvD+uA50OaW+33VeZqrh6bYlOx/nCqKXgDgH+jeniqhx9Gdmt6z9k9d5KYmYs5m08hqnSTtOaN6uG9JzrcdWG7PfGZmPfHKVwqXSeld2AjvD+sI1p61mzAaPlr+1SPplg0slONru3ZdC2iL2QjNvk6YlNyTOUtr76DLTr7uaNrM3eEtPBAn5aNavQ798RnYvzqGNjZqLB1Wj+09LT8gOWyFhYAeO2RlpjxaGuL/Q8s+O9prNqfBFdHO/w1td99uUQCw4cFDF/+D46l5ODr57pjYAdv7E+4hvGrD6HYKPDaIy3xxsA2VXqe2OTreOabaBQUGTCsiy8+f6pLhWT/5Z5ELN4aDxdHO/w9vb9ZFcbsjSew7lAyegU0xK+THrjrP0HZyGoHOxtsfb0fWlRxdPvpK1o8/90hXLuhR4BHfawa1wOv/HwUZ9Nz0a+VB9a80MviA7zKVsRcdygZ2tIVMV0c7fCMzCtiCiEw6ccj2H46A34NnfDf1/rBzenezbuXsvLw3h+nsDu+ZCloF0c700qfPfwb4PPRXWr0RlNYbMTy3YlYvjsRxcaSf+d6DrZ4fUArTOgbUOM+5Jz8QizfnYg1By6h0GDEwPZe+HJsN4t/Oq6M0Sgw/89TWBN1CQDw5sDWCH+4pdVDT+S5q/g1JgW7zmaaXlNHexs8FuSDp3r4ITigoUXKIITAH8ev4MO/ziAzt2RLhLAO3pg7tH2FqeKXcwqw4M/T2HqqdOdwVzXeHdIej3fysdhr8fepkk/fRgFMeSgQb4eZ36qVmJmLhVviseNMxm2PtfR0Rlc/d3Rt1gDd/N3RytPF4utbvLgmBjvOZKJfKw/8MKGXRf9Oyt6rAeD1Aa0wLbSVRZ+/sNiI0V9HITY5B52aumHD5JBqtbLLieHDAsKW7MXZ9NwKLQrrY1Lw1n/iAACLR3bCUz3vPrApMfMGRq08gOv5RejfujG+fb7Hbc2wxQYj/rUyCsdSctC/dWOseaFnlf6gL2XlYcCnkSg2iiqN5RBC4PnvDmFfwjX0DmyEn18MvufvOXIpGy+sjoFWV4z2Pq74YWIveDirkZiZi8eX7YeuyGjRVVRPpGqwcu95bD2ZDkPpG36AR3280Kc5RnZrivq1YKCnJr8Ij/97H1KyCzCwvRe+eq77HV9HXZEBKyPP48s951FY2jz+Ur8WePWRlth2Kh1zNp/CDX0xXNR2+ODJjtUatHkiVYOZvx3H2dL1Gh5t74XsvEIcuXQdANDK0xnvD+tYrUGb+mIDfjhwCf/enQhNQcnsCXMHA1qCEAKfbz+HpbtK1rF5qV8A3nmsXaWvu67IgPNXS6aXJmTmIiHjBhIzb5jGWFSFwSgqLLXfxc8dT/Xww+Odfaw2liBXV4QlOxLw/YGLMBgFnOxtMXVAKzwf4o81URexbGciCooMsLVR4YXezTHt0dZWGfhcfjzPnMfbY2Lfqo3nyczVYcmOBPwakwKDUcDWRoU+LT3QrVlJ2Oji516loF5TF6/lYeDne1FoMFY6Bq66yma9AcD00NZ4PdS81uOqupxTgCFL9yEnvwjjQvwxf1hHi/+OIoMRB85noajYaPGxVAwfFvDwJ3uQdC0P618OQa+AmxX7p3/HY9muRNjZqLD6hZ6V7hkClHSJjPzyAK5odOjs5461LwbfsfJMzLyBIUv3QV9sRMSIoCoN5pz+6zFsir2MB1s3xpoJvap0TpeySv4x9cVGfDqqM0bepZtn77mrePnHIygoMqCHfwOsGt+zwptH2ZuUnY0Kv03pXeP59X/FpWHqL7Gm0FGbd0E9karByBUHUGgw3nFp591nS5rHk0sXzOrb0gPzh3WosJ5CSnY+Xv8lFkeTcwCUrFHy/rAOVZpeqCsyYOnOBHy19wIMRoGG9R0w/4kOeLyTD4QAfjuaioVbzpq27x7exRfvPNauSgObjUaBP+Ou4ONt8aYZFG28XDD7sbZ4sHVj2Qbblu9rf6pHUzz7gH9pyLiBxMxcJGTeQHJ2PizxjtawvgNGdG2CUT380MZbuvVGzqRpMff3k4i5WBIeHexsTLNmejVviPeHd7D6dO/yM5nKT92vTJ6+GN/su4Cv915AfukYjkfbe+HtsLY17gqqrrLZf00bOGHHjAdrHJTLliwASlreXn3EOsGjzO6zmXjh+xgAJUE7rKM3Ojd1r1FLY2GxEf8kXsNfJ9Kw/XQGNAVFaOPlgm3T+1uq2AAYPiwiJGIn0jQ6/Plq3wp9+0IITPv1GH4/dgUuajv8NqX3bW9OOfmFGLUyCgmZN9CicX38Nrn3XRfKAW6+sdZ3sMXWaf3v2gwfn56LsC/2QgjcVr57KWs6bFDPHjvfeKjScv3vRBpe/yUWRQaBB1s3xspnu9+2JoEQAq+ujcVfJ9LQrGE9/DW1b5Uqzcr8efwKpv16DAajwKPtvTDj0damPRxqqx8PXsKczSdhZ6PCry8/gO7+JQE19Xo+3v/zNP4+XdLs7OWqxpzH22NIUOXN48UGI5btSsSyXQkwCsCvoROWjO6K7v53Hs8Sm3wdM3+LM41BeLyTD+Y/0QGNnCsuL52TX4hP/o7Hz9HJEAJwUdth+qOt8XyI/x3fyA6cv4aI/53FicsaU/nfeLQNRnZvWiuWgF5/OAWz/hMH413etdzr2aO1pwtalpti2rSBk1nl93ZzlG3KoxACG49eRsSWM7h2oxAezg5457F2eLJrE0mCX/k1XOxsVFg1vudtC2AVG4zYcCQVn20/h6ul3UWd/dzxzuC2CJZ5s7Q8fTEGfBqJdK0OMx5tjalmjnErc+sChjMHtUH4wy0tWdQ7Wrz1LL4stySDi6Md+gR6oF9rD/Rv1bhK3bS6IgP2J1zD/06WBI6yrl4A8HB2wKAO3pg3tINFFmQsw/BhAV3f/xvX84uwfXr/21Za1Bcb8NyqQziUlA1fN0dsCu9jWqCnoNCAZ1dF48il6/B2dcRvU0LQtMG9/1AMRoExX0ch5uJ19A5shJ8mBt/xE//LPx7GtlMZGNzRGyue7W7WeRUZjHh86X7EZ+RiZLem+PSpzhUeXx+TglkbS97chwT54PPRXe74x6kpKMJjX+zD5ZyCag3EBUrGokz/9RiMAvhX95KBbrWhkrsXIQSm/lKyuqePmyM2h/fBb0dSsWxXAnRFRtjZqDChbwCmDmhVpebxwxez8fovx+46GFVXZMCnf8dj1f4kGAXg4azGB8M7Iqzj3ZuW41JzMGfzSRxPLQkUbb1d8MHwjhWWfj6XkYuFW85iV+m0TWe1HSY/2AIT+7aodfvabD2Zhnc3n4IQonQNi5K1LFqWBg0PZ4c6MRVaU1CEfxKvoU9LD0m6LMozGks+ZP1Runrt2pceQBc/dwhRsi/Pwi1nkVAafps1rIe3wtrcMWDLoWyMm6O9DXa+8ZDZ48SEEPhs+zksK+3qk3qTTqOxZCzQ9jMZ+Cfx2m2LxgV41Ee/ViVB5IHARqb3GF2RAZHnrmLLiTTsOJOJG/qbgaOxixqDO3rjsSAf9Gze0CrvswwfFtBuzlYUFBmw762HK02ZOfmFGLHiAC5czUPHJq74dVIIHOxs8PKPR7DrbCbcnOyxYXIIWpuxRPTFa3kY/MU+FBQZ7jiyPy41B0/8+x+oVMDf024PRlVx5NJ1/GvlAQgBrH0xGL1begCo2Kw9pqcfPnwy6J5/oEcuZeOprw7CYBRmz9jZFJuKN9Yfh1GUNKMvHNGp1nWx3M0NfTGeWLYfF67lwcHWxjROoFdAQ3wwvKNZ1x4AtLoizNl8Er+XLm5XfjBqzMVsvPVbnGnWz4iuTTDn8fZocI8WtTJGo8AvMSlYtPWsafzGyG5NMbFvAH6Iuoj1h1NgFICdjQrPBDfD1AGt4OEs/0ZddyKEqDUVXV1VWGzExDUx2JdwDQ3q2eOD4UH48eBFHLxQsraJez17TH2kFcY+0KzWDYwUQmD0Vwdx6GI2hnTywfJnupn1sx9vize1PPzfY+3wUn/5ds01GAVOXtZg77mr2JdwDUeTr5sGQQMl/7Pd/BvAw9kBkfFXK0xh9nZ1RFhHbwzp5IPuzRpY/f2V4aOGhBBo8c7/IARw6P8G3HE6aXJWPp788h9k5RXikbaecK9nj41HL8PR3gY/vxhsaoo3x5oDFzHvj1NwsrfF1mn94N+o4oZKz393CHvPXcWIrk3w2egu1Tk9AMC7m0/gp4PJCPCojy2v98Py3YmmlP9y/xaYNbhtld/cywZj1XOwxX9f61ulmTS/HUnFzN+OQ4iSRXo+HB50XwWPMmfTtRj273+gLzbCw1mN/xvSFsO71Kx5fFNsaoXBqA+39cSfcVcgREk3yEdPBmFAu+oNFMvOK8SiLWfx6+GU2x4L6+CNt8LaVHkmFNV9eaU7Fpe1mgEl41Be6NMcrzzUUvIWGXOcuqLB0GX7YRRAd/8G8HFzrLgWi5sjfN2c0NhFbfqQJYTAoq3xWBlZEjzuNKZLTrm6IkSdz8K+hGvYl3AVF2+Zxuzr5ojBQT54LMgbXf2sHzjKY/ioIX2xAW3e3QoAiHtv4F1HuMcmX8eYrw9CXzoozNZGhW+e717tFTeNRoGx30Yj6kIWejVviF8mPWD64zmUlI2nvoqCnY0Ku954qEbLvWt1RQj9NBKZuXq09nLGuYySJtSZg9rglYcCzao8DUaBZ0vL3MHXFRtf6X3XT0LrY1Lw9sY4CAGMDW6GBcM63pfBo8yhpGwcS7mOMb2aWWw2xK2DUQFgdA8/vDOknUXe8I8mX8eczSdx6ooW3Zq5453H2lW6AydR1g09Rn99EImZNzCiaxPMGNi6Sl3JtcFH/zuDr/deuOsxtjYqeLqo4e3mCAdbG0QnlbTsWGP1XmtIzspHZMJVZN3Q48HWjdHFz122VkGGjxrSFBSh8/y/AQDnPhh8zwE5W0+mYcrPRyEEqrVY2K1SsvMRtmQv8goNpuRdvhnxmeBm+OjJoBr9DqBkYOkrPx8FULIXxPvDqr9yZ7pGh8Ff7MX1/CJM7BuAOXdYYbD8VL7nHvDH+8M6sPn8DooNRqzYcx77Eq4h/JGWFt/10mAUSM7OR/NG9XgN6K50RQbk5BdVe0E1OZ1I1SA5Ox9pmoJym/zd3IPHUMnoZTkWtKsLGD5qKFOrQ6+PdsJGBZz/6LEqvTEfSspGsdGI3oEeFinD2uhkvLPpBNR2Nvjf6/2Qer0A4747BAc7G+yd+bBF3gSEEJix/ji2nUpHxIigGm8OtuN0Bl784TAAYPX4nni4bcWVGsvOCQDG926OeUPbs9IjItkYjALXbuhLNwQs2Riwg69bheUVqOrMqb/lX7WpFtIVlXShONrbVrlytPQf69O9/LDlZBr2JVzDmxuOo9hQkhGff8DfYp8+VCoVPnuqMwoNQRYZMBba3gvjezfH9wcu4o0Nx7H19X6mdSXKpqYCqLDEPBGRXGxtVPAq3YcHNVyriMxz/+7da0W64pLRwlKu4ngrlUqFRSM7wUVth9jkHJy4XLLF+JSHLDvdS6VSWXSk+qzBbdHOxxXZeYWYvv4YjEaBH6IumoLHi30DGDyIiBSO4aMSuqLS8GHBxVeqw9fdCXOH3hw7MaFvwG0LSdU2jva2WPZ0VzjZ2+KfxCw8/90hzP39FICSWTT/N6TyZbGJiEg5GD4qUb7bRW7/6t4UzwQ3Q6/mDWWda26Olp7OmP9EBwDA/sRrAEo2qjJn+i4REdVdHPNRibKWD3UtCB8qlcoiM1ukNqpHU0QnZeM/R1Px6sMt8cZAy209TURE9zeGj0qYul3s2TBUXSqVCp+M6oTZj7Wt1StlEhGR9Fi7VkJXumCYYy1bMvh+o1KpGDyIiOg2DB+VYMsHERGR9bB2rYS+SP6ptkRERHUVw0clatNsFyIiorqG4aMS7HYhIiKyHtaulShb4dSSK38SERFRCYaPSrDbhYiIyHoYPirBbhciIiLrYe1aCbZ8EBERWQ/DRyVMu9rKvLEcERFRXcTatRJc54OIiMh6GD4qwW4XIiIi62H4qAQHnBIREVkPa9dKmNb5YMsHERGRxTF8VMLU7cJFxoiIiCyO4aMS7HYhIiKyHtauleCAUyIiIusxK3wYDAbMmTMHAQEBcHJyQmBgIBYsWAAhhOmY8ePHQ6VSVbiFhYVZvODWxKm2RERE1mNnzsGLFi3CihUrsGbNGnTo0AGHDx/GCy+8ADc3N0ydOtV0XFhYGFavXm36Xq1WW67EEjAtMsZuFyIiIoszK3wcOHAAw4YNw5AhQwAAzZs3x7p163Do0KEKx6nVanh7e1uulBIyGAWKDCUtORxwSkREZHlmfbTv3bs3du7ciXPnzgEAjh8/jv3792Pw4MEVjtuzZw88PT3Rpk0bTJkyBVlZWXd8Tr1eD61WW+Emp7LBpgC7XYiIiKzBrJaPWbNmQavVom3btrC1tYXBYMCHH36IsWPHmo4JCwvDiBEjEBAQgPPnz+Odd97B4MGDERUVBVvb2yvziIgIzJ8/v+ZnYiHlw4eae7sQERFZnFnhY/369fj555+xdu1adOjQAceOHcO0adPg6+uLcePGAQDGjBljOj4oKAidOnVCYGAg9uzZgwEDBtz2nLNnz8aMGTNM32u1Wvj5+VX3fGpMV1wy08XBzgY2NirZykFERFRXmRU+Zs6ciVmzZpkCRlBQEC5duoSIiAhT+LhVixYt4OHhgcTExErDh1qtrlUDUgsKuaMtERGRNZlVw+bn58PGpuKP2Nrawmg03vFnUlNTkZWVBR8fn+qVUGI6TrMlIiKyKrNaPoYOHYoPP/wQzZo1Q4cOHRAbG4vPPvsMEyZMAADcuHED8+fPx8iRI+Ht7Y3z58/jrbfeQsuWLTFo0CCrnICl6YsZPoiIiKzJrPCxbNkyzJkzB6+88goyMzPh6+uLl19+GXPnzgVQ0goSFxeHNWvWICcnB76+vhg4cCAWLFhQq7pW7ubm6qbsdiEiIrIGs8KHi4sLlixZgiVLllT6uJOTE7Zt22aJcsmG3S5ERETWxY/3t+COtkRERNbF8HGLspYPNbtdiIiIrII17C10HHBKRERkVQwft7g54JThg4iIyBoYPm5hGnDKRcaIiIisgjXsLfSc7UJERGRVDB+3KNvbhet8EBERWQdr2FtwnQ8iIiLrYvi4BcMHERGRdTF83KJstouaA06JiIisgjXsLdjyQUREZF0MH7e4OeCU4YOIiMgaGD5ucbPlgy8NERGRNbCGvYVpnQ9uLEdERGQVDB+34PLqRERE1sXwcYubG8vxpSEiIrIG1rC34GwXIiIi62L4uMXNbhe+NERERNbAGvYWZS0fag44JSIisgqGj3KEENBznQ8iIiKrYvgopyx4AOx2ISIishbWsOWUdbkAbPkgIiKyFoaPcsoGm9raqGBvy5eGiIjIGljDlmOaZssdbYmIiKyGtWw5NxcYY5cLERGRtTB8lMOl1YmIiKyP4aMc0xofnOlCRERkNaxly9FxR1siIiKrY/goh0urExERWR9r2XL0HHBKRERkdQwf5XBHWyIiIutj+CiH3S5ERETWx1q2HA44JSIisj6Gj3LKWj7U7HYhIiKyGoaPcm6ucMqXhYiIyFpYy5bDAadERETWx/BRjmnAKcd8EBERWQ3DRzn6Ina7EBERWRtr2XK4qy0REZH1MXyUU9bt4sTwQUREZDVmhQ+DwYA5c+YgICAATk5OCAwMxIIFCyCEMB0jhMDcuXPh4+MDJycnhIaGIiEhweIFtwbuaktERGR9ZtWyixYtwooVK/Dvf/8bZ86cwaJFi7B48WIsW7bMdMzixYuxdOlSrFy5EtHR0ahfvz4GDRoEnU5n8cJbGme7EBERWZ+dOQcfOHAAw4YNw5AhQwAAzZs3x7p163Do0CEAJa0eS5Yswbvvvothw4YBAH744Qd4eXlh8+bNGDNmjIWLb1k3l1dn+CAiIrIWs1o+evfujZ07d+LcuXMAgOPHj2P//v0YPHgwACApKQnp6ekIDQ01/YybmxuCg4MRFRVV6XPq9XpotdoKN7mYBpzasduFiIjIWsxq+Zg1axa0Wi3atm0LW1tbGAwGfPjhhxg7diwAID09HQDg5eVV4ee8vLxMj90qIiIC8+fPr07ZLU7Plg8iIiKrM+sj/vr16/Hzzz9j7dq1OHr0KNasWYNPPvkEa9asqXYBZs+eDY1GY7qlpKRU+7lqimM+iIiIrM+slo+ZM2di1qxZprEbQUFBuHTpEiIiIjBu3Dh4e3sDADIyMuDj42P6uYyMDHTp0qXS51Sr1VCr1dUsvmXpuMgYERGR1ZlVy+bn58PGpuKP2Nrawmgs6a4ICAiAt7c3du7caXpcq9UiOjoaISEhFiiudemK2e1CRERkbWa1fAwdOhQffvghmjVrhg4dOiA2NhafffYZJkyYAABQqVSYNm0aPvjgA7Rq1QoBAQGYM2cOfH19MXz4cGuU32KKDEYYjCXrlXBvFyIiIusxK3wsW7YMc+bMwSuvvILMzEz4+vri5Zdfxty5c03HvPXWW8jLy8OkSZOQk5ODvn37YuvWrXB0dLR44S2prMsF4CJjRERE1qQS5ZcnrQW0Wi3c3Nyg0Wjg6uoq2e+9mqtHzw93QKUCLnz0GFQqlWS/m4iI6H5nTv3Nj/ilTEur29kweBAREVkRw0cpPXe0JSIikgTDRynT0uocbEpERGRVDB+luMYHERGRNFjTluKmckRERNJg+ChlGnDK8EFERGRVDB+luKMtERGRNFjTlmK3CxERkTQYPkpxwCkREZE0WNOWuhk+2PJBRERkTQwfpfTFXOeDiIhICgwfpdjtQkREJA3WtKXY7UJERCQNho9SZbNduM4HERGRdTF8lGK3CxERkTRY05bSccApERGRJBg+SnHMBxERkTQYPkqx24WIiEgarGlL6bm8OhERkSQYPkqZNpZjywcREZFVsaYtZep24YBTIiIiq2L4KMV1PoiIiKTB8FGqgANOiYiIJMGathSn2hIREUmD4aMUZ7sQERFJg+EDgMEoUGgoW+GULwkREZE1saYFoC+dZguw5YOIiMjaGD5wc6YLwPBBRERkbQwfuDnY1N5WBVsblcylISIiqtsYPsAFxoiIiKTE8AEuMEZERCQlhg9wXxciIiIpsbYFFxgjIiKSEsMHyi8wxpeDiIjI2ljbggNOiYiIpMTwgfJjPhg+iIiIrI3hAzdnu7DbhYiIyPpY2+Jmtwun2hIREVkfwwfKtXxwzAcREZHVmRU+mjdvDpVKddstPDwcAPDQQw/d9tjkyZOtUnBLujnVllmMiIjI2uzMOTgmJgYGw80dYE+ePIlHH30Uo0aNMt330ksv4f333zd9X69ePQsU07o44JSIiEg6ZoWPxo0bV/h+4cKFCAwMxIMPPmi6r169evD29rZM6STCdT6IiIikU+3atrCwED/99BMmTJgAlermTrA///wzPDw80LFjR8yePRv5+fkWKag1cZ0PIiIi6ZjV8lHe5s2bkZOTg/Hjx5vue+aZZ+Dv7w9fX1/ExcXh7bffRnx8PDZu3HjH59Hr9dDr9abvtVptdYtUbVxenYiISDrVDh+rVq3C4MGD4evra7pv0qRJpq+DgoLg4+ODAQMG4Pz58wgMDKz0eSIiIjB//vzqFsMiuM4HERGRdKpV2166dAk7duzAiy++eNfjgoODAQCJiYl3PGb27NnQaDSmW0pKSnWKVCNlA065zgcREZH1VavlY/Xq1fD09MSQIUPuetyxY8cAAD4+Pnc8Rq1WQ61WV6cYFsNuFyIiIumYHT6MRiNWr16NcePGwc7u5o+fP38ea9euxWOPPYZGjRohLi4O06dPR//+/dGpUyeLFtrSbi4yxm4XIiIiazM7fOzYsQPJycmYMGFChfsdHBywY8cOLFmyBHl5efDz88PIkSPx7rvvWqyw1sKWDyIiIumYHT4GDhwIIcRt9/v5+SEyMtIihZKavrhswCnDBxERkbWxnwFcXp2IiEhKrG3BbhciIiIpMXyAu9oSERFJSfHhQwhRbmM5xb8cREREVqf42rbQYETZ+FkuMkZERGR9ig8fZV0uAFs+iIiIpKD42lZfOthUpQIcbBX/chAREVmd4mvb8oNNVSqVzKUhIiKq+xg+ONiUiIhIUoqvcbnGBxERkbQYPoq4tDoREZGUGD5KWz7U3NGWiIhIEoqvcdntQkREJC2GD9OOtop/KYiIiCSh+BqXLR9ERETSUnz4KFtkjJvKERERSUPx4ePmbBfFvxRERESSUHyNy24XIiIiaTF8FDN8EBERSYnhg4uMERERSYrho4h7uxAREUlJ8TUuWz6IiIikxfBRNuaDy6sTERFJQvE1rp6zXYiIiCSl+PDBbhciIiJpMXxwwCkREZGkFF/jlo35ULPlg4iISBIMH2XdLtzbhYiISBIMH+x2ISIikpTia1wOOCUiIpKW4sMHp9oSERFJS/Hh4+bGcop/KYiIiCSh6BrXYBQoMggAHHBKREQkFUWHj7LBpgC7XYiIiKTC8FFKzb1diIiIJKHoGldXXDLTxcHOBjY2KplLQ0REpAzKDh9F3NGWiIhIaoqudXWcZktERCQ5hYcPLjBGREQkNUWHDz2XViciIpKcWbVu8+bNoVKpbruFh4cDAHQ6HcLDw9GoUSM4Oztj5MiRyMjIsErBLeHmAmNs+SAiIpKKWeEjJiYGaWlpptv27dsBAKNGjQIATJ8+HX/++Sc2bNiAyMhIXLlyBSNGjLB8qS2EO9oSERFJz86cgxs3blzh+4ULFyIwMBAPPvggNBoNVq1ahbVr1+KRRx4BAKxevRrt2rXDwYMH8cADD1iu1BZSNuBUzW4XIiIiyVS71i0sLMRPP/2ECRMmQKVS4ciRIygqKkJoaKjpmLZt26JZs2aIioq64/Po9XpotdoKN6lwwCkREZH0qh0+Nm/ejJycHIwfPx4AkJ6eDgcHB7i7u1c4zsvLC+np6Xd8noiICLi5uZlufn5+1S2S2TjVloiISHrVDh+rVq3C4MGD4evrW6MCzJ49GxqNxnRLSUmp0fOZwzTglIuMERERScasMR9lLl26hB07dmDjxo2m+7y9vVFYWIicnJwKrR8ZGRnw9va+43Op1Wqo1erqFKPG2O1CREQkvWp95F+9ejU8PT0xZMgQ033du3eHvb09du7cabovPj4eycnJCAkJqXlJrYDrfBAREUnP7JYPo9GI1atXY9y4cbCzu/njbm5umDhxImbMmIGGDRvC1dUVr732GkJCQmrlTBeAYz6IiIjkYHb42LFjB5KTkzFhwoTbHvv8889hY2ODkSNHQq/XY9CgQfjyyy8tUlBrYLcLERGR9MwOHwMHDoQQotLHHB0dsXz5cixfvrzGBZNCQdk6HxxwSkREJBlF17rsdiEiIpKessNHMbtdiIiIpKbs8MHZLkRERJJTdK1rmmrLjeWIiIgko+jwwdkuRERE0lN2+ChmtwsREZHUFF3rcrYLERGR9BQePsq6XRT9MhAREUlK0bWuzrTIGFs+iIiIpKLY8CGEgJ7rfBAREUlOseGjLHgA7HYhIiKSkmJr3bIuF4AtH0RERFJScPgoafmwtVHB3laxLwMREZHkFFvrmqbZckdbIiIiSSm25r25wBi7XIiIiKSk3PDBpdWJiIhkoeDwUbrGB2e6EBERSUqxNa+OO9oSERHJQsHhg0urExERyUGxNa+eA06JiIhkodjwwR1tiYiI5KHg8MFuFyIiIjkotublgFMiIiJ5KDh8lLR8qNntQkREJCnlhg/TgFPFvgRERESyUGzNywGnRERE8lBw+CgdcMoxH0RERJJSbPjQF7HbhYiISA6KrXm5qy0REZE8lBs+uM4HERGRLBRb83LAKRERkTwUHz7UHHBKREQkKQWHD3a7EBERyUGxNS8HnBIREclDseFDb2r5YPggIiKSkmLDh47rfBAREclCsTUvd7UlIiKSh3LDRzG7XYiIiOSgyPBRZDDCYBQA2O1CREQkNUXWvGVdLgBbPoiIiKRmdvi4fPkynn32WTRq1AhOTk4ICgrC4cOHTY+PHz8eKpWqwi0sLMyiha6psjU+AEBtp8j8RUREJBs7cw6+fv06+vTpg4cffhhbtmxB48aNkZCQgAYNGlQ4LiwsDKtXrzZ9r1arLVNaC7m5uqkNVCqVzKUhIiJSFrPCx6JFi+Dn51chWAQEBNx2nFqthre3d81LZyV6LjBGREQkG7P6HP744w/06NEDo0aNgqenJ7p27YpvvvnmtuP27NkDT09PtGnTBlOmTEFWVtYdn1Ov10Or1Va4WRuXViciIpKPWbXvhQsXsGLFCrRq1Qrbtm3DlClTMHXqVKxZs8Z0TFhYGH744Qfs3LkTixYtQmRkJAYPHgyDwVDpc0ZERMDNzc108/Pzq9kZVQF3tCUiIpKPSgghqnqwg4MDevTogQMHDpjumzp1KmJiYhAVFVXpz1y4cAGBgYHYsWMHBgwYcNvjer0eer3e9L1Wq4Wfnx80Gg1cXV3NOZcq259wDc+uikYbLxdsm97fKr+DiIhISbRaLdzc3KpUf5vV8uHj44P27dtXuK9du3ZITk6+48+0aNECHh4eSExMrPRxtVoNV1fXCjdr49LqRERE8jGr9u3Tpw/i4+Mr3Hfu3Dn4+/vf8WdSU1ORlZUFHx+f6pXQCrijLRERkXzMCh/Tp0/HwYMH8dFHHyExMRFr167F119/jfDwcADAjRs3MHPmTBw8eBAXL17Ezp07MWzYMLRs2RKDBg2yyglUh4472hIREcnGrPDRs2dPbNq0CevWrUPHjh2xYMECLFmyBGPHjgUA2NraIi4uDk888QRat26NiRMnonv37ti3b1+tWuuD3S5ERETyMWudDwB4/PHH8fjjj1f6mJOTE7Zt21bjQlkbZ7sQERHJR5Ef/fVlO9raMXwQERFJTZHhg90uRERE8lFk7ctuFyIiIvkoNHyUdLuoGT6IiIgkp9DwwW4XIiIiuSiy9tVxwCkREZFslBk+OOaDiIhINgoPH4o8fSIiIlkpsvbVc3l1IiIi2SgyfNzcWE6Rp09ERCQrRda+pm4XDjglIiKSnELDB9f5ICIikotCwwe7XYiIiOSiyNqXU22JiIjko8zwUczZLkRERHJRXPgwGgUKTSucKu70iYiIZKe42ldfGjwAtnwQERHJQXHho2y8B8DwQUREJAflhY/SBcbsbVWwtVHJXBoiIiLlUV74KOKOtkRERHJSYPgoafngAmNERETyUGz44AJjRERE8lBcDazjjrZERESyUl744I62REREslJcDaznjrZERESyUlz4KOC+LkRERLJSXPi4OeZDcadORERUKyiuBuZUWyIiInkpMHxwkTEiIiI5KTB8cLYLERGRnBRXA9+casuWDyIiIjkoLnzoOeCUiIhIVoqrgXVc54OIiEhWyg0f7HYhIiKShQLDB7tdiIiI5KS4GrhswCnX+SAiIpKH8sIHu12IiIhkpcDwUbbImOJOnYiIqFZQXA3Mlg8iIiJ5KS586IvLBpwyfBAREcnB7PBx+fJlPPvss2jUqBGcnJwQFBSEw4cPmx4XQmDu3Lnw8fGBk5MTQkNDkZCQYNFC1wSXVyciIpKXWTXw9evX0adPH9jb22PLli04ffo0Pv30UzRo0MB0zOLFi7F06VKsXLkS0dHRqF+/PgYNGgSdTmfxwlcHu12IiIjkZWfOwYsWLYKfnx9Wr15tui8gIMD0tRACS5Yswbvvvothw4YBAH744Qd4eXlh8+bNGDNmjIWKXX3c1ZaIiEheZrV8/PHHH+jRowdGjRoFT09PdO3aFd98843p8aSkJKSnpyM0NNR0n5ubG4KDgxEVFVXpc+r1emi12go3axFClNtYjt0uREREcjCrBr5w4QJWrFiBVq1aYdu2bZgyZQqmTp2KNWvWAADS09MBAF5eXhV+zsvLy/TYrSIiIuDm5ma6+fn5Vec8qqTQYIQQJV9zkTEiIiJ5mBU+jEYjunXrho8++ghdu3bFpEmT8NJLL2HlypXVLsDs2bOh0WhMt5SUlGo/172UdbkAbPkgIiKSi1k1sI+PD9q3b1/hvnbt2iE5ORkA4O3tDQDIyMiocExGRobpsVup1Wq4urpWuFmLvnSwqUoFONgyfBAREcnBrBq4T58+iI+Pr3DfuXPn4O/vD6Bk8Km3tzd27txpelyr1SI6OhohISEWKG7NlB9sqlKpZC4NERGRMpk122X69Ono3bs3PvroIzz11FM4dOgQvv76a3z99dcAAJVKhWnTpuGDDz5Aq1atEBAQgDlz5sDX1xfDhw+3RvnNwsGmRERE8jMrfPTs2RObNm3C7Nmz8f777yMgIABLlizB2LFjTce89dZbyMvLw6RJk5CTk4O+ffti69atcHR0tHjhzcU1PoiIiOSnEqJs/kftoNVq4ebmBo1GY/HxH4eSsvHUV1EI8KiP3W8+ZNHnJiIiUjJz6m9F9T+UtXyouaMtERGRbBRVC7PbhYiISH7KCh+mHW0VddpERES1iqJqYbZ8EBERyU9R4aNskTFuKkdERCQfRYUP0yJj7HYhIiKSjaJqYXa7EBERyU9Z4aOY4YOIiEhuygofpd0uana7EBERyUZRtbCOA06JiIhkp7DwUTbglOGDiIhILsoKH9zVloiISHaKqoX1nO1CREQkO0WFD67zQUREJD9F1cIccEpERCQ/ZYUPrvNBREQkO2WFD67zQUREJDtF1cJcXp2IiEh+CgsfpQNOOeaDiIhINooKHzen2irqtImIiGoVRdXCHHBKREQkP8WED4NRoMggADB8EBERyUkx4aNssCnAbhciIiI5KaYWrhA+OOCUiIhINsoJH8UlM10cbG1gY6OSuTRERETKpZzwwZkuREREtYKd3AWQipuTPaYOaAU7tnoQERHJSjHhw8NZjRmPtpa7GERERIrHPggiIiKSFMMHERERSYrhg4iIiCTF8EFERESSYvggIiIiSTF8EBERkaQYPoiIiEhSDB9EREQkKYYPIiIikhTDBxEREUmK4YOIiIgkxfBBREREkmL4ICIiIknVul1thRAAAK1WK3NJiIiIqKrK6u2yevxual34yM3NBQD4+fnJXBIiIiIyV25uLtzc3O56jEpUJaJIyGg04sqVK3BxcYFKpbLoc2u1Wvj5+SElJQWurq4Wfe7ahOdZdyjhHAGeZ13D86w7zDlHIQRyc3Ph6+sLG5u7j+qodS0fNjY2aNq0qVV/h6ura539QymP51l3KOEcAZ5nXcPzrDuqeo73avEowwGnREREJCmGDyIiIpKUosKHWq3GvHnzoFar5S6KVfE86w4lnCPA86xreJ51h7XOsdYNOCUiIqK6TVEtH0RERCQ/hg8iIiKSFMMHERERSYrhg4iIiCSlmPCxfPlyNG/eHI6OjggODsahQ4fkLpJFvffee1CpVBVubdu2lbtYNbZ3714MHToUvr6+UKlU2Lx5c4XHhRCYO3cufHx84OTkhNDQUCQkJMhT2Bq413mOHz/+tusbFhYmT2GrKSIiAj179oSLiws8PT0xfPhwxMfHVzhGp9MhPDwcjRo1grOzM0aOHImMjAyZSlw9VTnPhx566LbrOXnyZJlKXD0rVqxAp06dTItPhYSEYMuWLabH68K1BO59nnXhWt5q4cKFUKlUmDZtmuk+S19PRYSPX3/9FTNmzMC8efNw9OhRdO7cGYMGDUJmZqbcRbOoDh06IC0tzXTbv3+/3EWqsby8PHTu3BnLly+v9PHFixdj6dKlWLlyJaKjo1G/fn0MGjQIOp1O4pLWzL3OEwDCwsIqXN9169ZJWMKai4yMRHh4OA4ePIjt27ejqKgIAwcORF5enumY6dOn488//8SGDRsQGRmJK1euYMSIETKW2nxVOU8AeOmllypcz8WLF8tU4upp2rQpFi5ciCNHjuDw4cN45JFHMGzYMJw6dQpA3biWwL3PE7j/r2V5MTEx+Oqrr9CpU6cK91v8egoF6NWrlwgPDzd9bzAYhK+vr4iIiJCxVJY1b9480blzZ7mLYVUAxKZNm0zfG41G4e3tLT7++GPTfTk5OUKtVot169bJUELLuPU8hRBi3LhxYtiwYbKUx1oyMzMFABEZGSmEKLl29vb2YsOGDaZjzpw5IwCIqKgouYpZY7eepxBCPPjgg+L111+Xr1BW0qBBA/Htt9/W2WtZpuw8hahb1zI3N1e0atVKbN++vcJ5WeN61vmWj8LCQhw5cgShoaGm+2xsbBAaGoqoqCgZS2Z5CQkJ8PX1RYsWLTB27FgkJyfLXSSrSkpKQnp6eoVr6+bmhuDg4Dp3bQFgz5498PT0RJs2bTBlyhRkZWXJXaQa0Wg0AICGDRsCAI4cOYKioqIK17Nt27Zo1qzZfX09bz3PMj///DM8PDzQsWNHzJ49G/n5+XIUzyIMBgN++eUX5OXlISQkpM5ey1vPs0xduZbh4eEYMmRIhesGWOd/s9ZtLGdp165dg8FggJeXV4X7vby8cPbsWZlKZXnBwcH4/vvv0aZNG6SlpWH+/Pno168fTp48CRcXF7mLZxXp6ekAUOm1LXusrggLC8OIESMQEBCA8+fP45133sHgwYMRFRUFW1tbuYtnNqPRiGnTpqFPnz7o2LEjgJLr6eDgAHd39wrH3s/Xs7LzBIBnnnkG/v7+8PX1RVxcHN5++23Ex8dj48aNMpbWfCdOnEBISAh0Oh2cnZ2xadMmtG/fHseOHatT1/JO5wnUnWv5yy+/4OjRo4iJibntMWv8b9b58KEUgwcPNn3dqVMnBAcHw9/fH+vXr8fEiRNlLBlZwpgxY0xfBwUFoVOnTggMDMSePXswYMAAGUtWPeHh4Th58mSdGJd0N3c6z0mTJpm+DgoKgo+PDwYMGIDz588jMDBQ6mJWW5s2bXDs2DFoNBr89ttvGDduHCIjI+UulsXd6Tzbt29fJ65lSkoKXn/9dWzfvh2Ojo6S/M463+3i4eEBW1vb20blZmRkwNvbW6ZSWZ+7uztat26NxMREuYtiNWXXT2nXFgBatGgBDw+P+/L6vvrqq/jvf/+L3bt3o2nTpqb7vb29UVhYiJycnArH36/X807nWZng4GAAuO+up4ODA1q2bInu3bsjIiICnTt3xhdffFHnruWdzrMy9+O1PHLkCDIzM9GtWzfY2dnBzs4OkZGRWLp0Kezs7ODl5WXx61nnw4eDgwO6d++OnTt3mu4zGo3YuXNnhT67uubGjRs4f/48fHx85C6K1QQEBMDb27vCtdVqtYiOjq7T1xYAUlNTkZWVdV9dXyEEXn31VWzatAm7du1CQEBAhce7d+8Oe3v7CtczPj4eycnJ99X1vNd5VubYsWMAcF9dz8oYjUbo9fo6cy3vpOw8K3M/XssBAwbgxIkTOHbsmOnWo0cPjB071vS1xa9nzcfH1n6//PKLUKvV4vvvvxenT58WkyZNEu7u7iI9PV3uolnMG2+8Ifbs2SOSkpLEP//8I0JDQ4WHh4fIzMyUu2g1kpubK2JjY0VsbKwAID777DMRGxsrLl26JIQQYuHChcLd3V38/vvvIi4uTgwbNkwEBASIgoICmUtunrudZ25urnjzzTdFVFSUSEpKEjt27BDdunUTrVq1EjqdTu6iV9mUKVOEm5ub2LNnj0hLSzPd8vPzTcdMnjxZNGvWTOzatUscPnxYhISEiJCQEBlLbb57nWdiYqJ4//33xeHDh0VSUpL4/fffRYsWLUT//v1lLrl5Zs2aJSIjI0VSUpKIi4sTs2bNEiqVSvz9999CiLpxLYW4+3nWlWtZmVtn8Vj6eioifAghxLJly0SzZs2Eg4OD6NWrlzh48KDcRbKo0aNHCx8fH+Hg4CCaNGkiRo8eLRITE+UuVo3t3r1bALjtNm7cOCFEyXTbOXPmCC8vL6FWq8WAAQNEfHy8vIWuhrudZ35+vhg4cKBo3LixsLe3F/7+/uKll16678JzZecHQKxevdp0TEFBgXjllVdEgwYNRL169cSTTz4p0tLS5Ct0NdzrPJOTk0X//v1Fw4YNhVqtFi1bthQzZ84UGo1G3oKbacKECcLf3184ODiIxo0biwEDBpiChxB141oKcffzrCvXsjK3hg9LX0+VEEJUr82EiIiIyHx1fswHERER1S4MH0RERCQphg8iIiKSFMMHERERSYrhg4iIiCTF8EFERESSYvggIiIiSTF8EBERkaQYPoiIiEhSDB9EREQkKYYPIiIikhTDBxEREUnq/wEQ3LtyIi2bkgAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -385,7 +390,7 @@ { "data": { "text/plain": [ - "[]" + "[]" ] }, "execution_count": 9, @@ -394,7 +399,7 @@ }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -434,17 +439,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "precision: 89.389%\n", + "precision: 89.686%\n", "recall: 100.000%\n", - "f1: 94.397%\n", - "support: 1508\n" + "f1: 94.562%\n", + "support: 1513\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "/home/vscode/.local/lib/python3.12/site-packages/sklearn/metrics/_classification.py:1517: UndefinedMetricWarning: Precision is ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.\n", + "/Users/mathiasleys/projects/venv/lib/python3.12/site-packages/sklearn/metrics/_classification.py:1517: UndefinedMetricWarning: Precision is ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.\n", " _warn_prf(average, modifier, f\"{metric.capitalize()} is\", len(result))\n" ] } @@ -465,7 +470,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 12, @@ -474,7 +479,7 @@ }, { "data": { - "image/png": "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1Nk1jvV3v/udYmJiXJ7oO2bMGIWFhelvf/ubDMOQ1WrVAw88oAcffFCSdOrUKcXExGjt2rUaO3as9u/fr+7du2v37t3q27evJGnLli0aMWKEvvvuO59V5Gs0Z2DZsmU+eTMAAPzGR0sLbTaby+6QkBCFhIRUG37ttddq9erV+vrrr3XppZfq008/1QcffKAlS5ZIknJzc5Wfn6+EhATnOZGRkerXr58yMzM1duxYZWZmKioqypkISFJCQoICAgK0a9cu/f73v/fiA/1HjZKB5ORkn7wZAACNXVxcnMvruXPnat68edXGzZw5UzabTV27dlVgYKDsdrseffRRJSUlSZLy8/MlSTExMS7nxcTEOI/l5+erbdu2LseDgoIUHR3tHOMLtb7pkCSVlpaqvLzcZV9dlXkAAPCKjyoDeXl5Lt9156oKSNKrr76qtLQ0rV+/Xj169FB2dramTJkiq9Xa4H5ke5wMlJSUaMaMGXr11Vf173//u9pxu93uk8AAAPApHyUDERERNfrhO336dM2cOVNjx46VJPXs2VPffvutFi1apOTkZMXGxkqSCgoK1K5dO+d5BQUF6t27tyQpNjZWx48fd7luZWWlCgsLnef7gserCR566CFt27ZNK1euVEhIiF544QXNnz9fVqtV69at81lgAAA0ZmfOnFFAgOvXbGBgoBwOhySpY8eOio2N1datW53HbTabdu3apfj4eElSfHy8ioqKlJWV5Ryzbds2ORwO9evXz2exelwZ2LRpk9atW6dBgwZp3LhxGjBggDp16qQOHTooLS3N2QsBAKBBqedHGI8cOVKPPvqo2rdvrx49euiTTz7RkiVL9Mc//lGSZLFYNGXKFD3yyCPq3LmzOnbsqNmzZ8tqtWr06NGSpG7dumnYsGGaMGGCVq1apYqKCqWkpGjs2LE+vbePx8lAYWGhLrnkEklnSyVVSwn79++vSZMm+SwwAAB8qb7vQLh8+XLNnj1b99xzj44fPy6r1ar/+Z//0Zw5c5xjHnroIZWUlGjixIkqKipS//79tWXLFoWG/mcJZFpamlJSUjRkyBAFBARozJgxSk1Nrf0HOQePk4FLLrlEubm5at++vbp27apXX31VV199tTZt2uR8cBEAAGYXHh6uZcuW/eryfIvFogULFmjBggVux0RHR2v9+vV1EOF/eDxnYNy4cfr0008lnV02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83doLkgG4JGQkBDNnTu3SfTIgF/i3zd87Q9/+INOnDihOXPmKD8/X71799aWLVuqTSr0N4vRlG+2DAAAzos5AwAAmBzJAAAAJkcyAACAyZEMAABgciQDqLHG8BhOoDYyMjI0cuRIWa1WWSwWbdy40d8hAfWKZAA10lgewwnURklJiXr16qUVK1b4OxTAL1haiBrp16+frrrqKj3zzDOSzt5FKy4uTvfee69mzpzp5+gA37FYLHrzzTc1evRof4cC1BsqAzivqsdwJiQkOPc11MdwAgA8RzKA8/q1x3Dm5+f7KSoAgK+QDAAAYHIkAzivxvQYTgCA50gGcF6N6TGcAADP8dRC1EhjeQwnUBvFxcU6ePCg83Vubq6ys7MVHR2t9u3b+zEyoH6wtBA19swzz+iJJ55wPoYzNTVV/fr183dYgNfef/99DR48uNr+5ORkrV27tv4DAuoZyQAAACbHnAEAAEyOZAAAAJMjGQAAwORIBgAAMDmSAQAATI5kAAAAkyMZAADA5EgGAAAwOZIBwEt33XWXRo8e7Xw9aNAgTZkypd7jeP/992WxWFRUVOR2jMVi0caNG2t8zXnz5ql3795exfXNN9/IYrEoOzvbq+sAqDskA2iS7rrrLlksFlksFgUHB6tTp05asGCBKisr6/y933jjDS1cuLBGY2vyBQ4AdY0HFaHJGjZsmNasWaOysjK9/fbbmjx5spo1a6ZZs2ZVG1teXq7g4GCfvG90dLRPrgMA9YXKAJqskJAQxcbGqkOHDpo0aZISEhL01ltvSfpPaf/RRx+V1WpVly5dJEl5eXm65ZZbFBUVpejoaI0aNUrffPON85p2u13Tpk1TVFSUWrdurYceeki/fLzHL9sEZWVlmjFjhuLi4hQSEqJOnTrpxRdf1DfffON8OE6rVq1ksVh01113STr7iOhFixapY8eOCgsLU69evfT3v//d5X3efvttXXrppQoLC9PgwYNd4qypGTNm6NJLL1Xz5s11ySWXaPbs2aqoqKg27rnnnlNcXJyaN2+uW265RadOnXI5/sILL6hbt24KDQ1V165d9eyzz3ocCwD/IRmAaYSFham8vNz5euvWrcrJyVF6ero2b96siooKJSYmKjw8XDt27NCHH36oli1batiwYc7znnrqKa1du1YvvfSSPvjgAxUWFurNN9/81fe988479b//+79KTU3V/v379dxzz6lly5aKi4vT66+/LknKycnRsWPH9PTTT0uSFi1apHXr1mnVqlXat2+fpk6dqttvv13bt2+XdDZpuemmmzRy5EhlZ2fr7rvv1syZMz3+OwkPD9fatWv15Zdf6umnn9bzzz+vpUuXuow5ePCgXn31VW3atElbtmzRJ598onvuucd5PC0tTXPmzNGjjz6q/fv367HHHtPs2bP18ssvexwPAD8xgCYoOTnZGDVqlGEYhuFwOIz09HQjJCTEePDBB53HY2JijLKyMuc5f/3rX40uXboYDofDua+srMwICwsz3nnnHcMwDKNdu3bG4sWLnccrKiqMiy66yPlehmEY119/vXH//fcbhmEYOTk5hiQjPT39nHG+9957hiTj5MmTzn2lpaVG8+bNjZ07d7qMHT9+vHHrrbcahmEYs2bNMrp37+5yfMaMGdWu9UuSjDfffNPt8SeeeMLo06eP8/XcuXONwMBA47vvvnPu++c//2kEBAQYx44dMwzDMH7zm98Y69evd7nOwoULjfj4eMMwDCM3N9eQZHzyySdu3xeAfzFnAE3W5s2b1bJlS1VUVMjhcOi2227TvHnznMd79uzpMk/g008/1cGDBxUeHu5yndLSUh06dEinTp3SsWPH1K9fP+exoKAg9e3bt1qroEp2drYCAwN1/fXX1zjugwcP6syZM/rtb3/rsr+8vFxXXHGFJGn//v0ucUhSfHx8jd+jyoYNG5SamqpDhw6puLhYlZWVioiIcBnTvn17XXjhhS7v43A4lJOTo/DwcB06dEjjx4/XhAkTnGMqKysVGRnpcTwA/INkAE3W4MGDtXLlSgUHB8tqtSooyPWfe4sWLVxeFxcXq0+fPkpLS6t2rQsuuKBWMYSFhXl8TnFxsSTpH//4h8uXsHR2HoSvZGZmKikpSfPnz1diYqIiIyP1yiuv6KmnnvI41ueff75achIYGOizWAHULZIBNFktWrRQp06dajz+yiuv1IYNG9S2bdtqv46rtGvXTrt27dLAgQMlnf0FnJWVpSuvvPKc43v27CmHw6Ht27crISGh2vGqyoTdbnfu6969u0JCQnTkyBG3FYVu3bo5J0NW+eijj87/IX9m586d6tChg/785z8793377bfVxh05ckRHjx6V1Wp1vk9AQIC6dOmimJgYWa1WHT58WElJSR69P4CGgwmEwE+SkpLUpk0bjRo1Sjt27FBubq7ef/993Xffffruu+8kSffff7/+8pe/aOPGjfrqq690zz33/Oo9Ai6++GIlJyfrj3/8ozZu3Oi85quvvipJ6tChgywWizZv3qwTJ06ouLhY4eHhevDBBzV16lS9/PLLOnTokPbu3avly5c7J+X96U9/0oEDBzR9+nTl5ORo/fr1Wrt2rUeft3Pnzjpy5IheeeUVHTp0SKmpqeecDBkaGqrk5GR9+umn2rFjh+677z7dcsstio2NlSTNnz9fixYtUmpqqr7++mt9/vnnWrNmjZYsWeJRPAD8h2QA+Enz5s2VkZGh9u3b66abblK3bt00fvx4lZaWOisFDzzwgO644w4lJycrPj5e4eHh+v3vf/+r1125cqVuvvlm3XPPPeratasmTJigkpISSdKFF16o+fPna+bMmYqJiVFKSookaeHChZo9e7YWLVqkbt26adiwYfrHP/6hjh07Sjrbx3/99de1ceNG9erVS6tWrdJjjz3m0ee98cYbNXXqVKWkpKh3797auXOnZs+eXW1cp06ddNNNN2nEiBEaOnSoLr/8cpelg3fffbdeeOEFrVmzRj179tT111+vtWvXOmMF0PBZDHcznwAAgClQGQAAwORIBgAAMDmSAQAATI5kAAAAkyMZAADA5EgGAAAwOZIBAABMjmQAAACTIxkAAMDkSAYAADA5kgEAAEzu/wPsJmUhnsAIYAAAAABJRU5ErkJggg==", + "image/png": "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LUStPfXUU3rsscecj+HMzMxUYmJioMMCvPbee+9p4MCBNfanpaVp1apV9R8QUM9IBgAAMDnmDAAAYHIkAwAAmBzJAAAAJkcyAACAyZEMAABgciQDAACYHMkAAAAmRzIAAIDJkQwAXrrllls0atQo5+sBAwZo0qRJ9R7He++9J4vFoqKiIrdjLBaL1q1bV+trzp49W7179/Yqrq+//loWi0W5ubleXQeA/5AMoEm65ZZbZLFYZLFYFBoaqs6dO2vu3Lmqqqry+3u/+uqreuCBB2o1tjZf4ADgbzyoCE3WkCFDtHLlSpWXl+uNN97QxIkT1axZM91///01xlZUVCg0NNQn7xsbG+uT6wBAfaEygCYrLCxM8fHx6tixo2677TYlJyfr9ddfl/RTaf+hhx6S1WpVly5dJElHjhzRddddp5iYGMXGxmrkyJH6+uuvnde02+2aMmWKYmJi1Lp1a91777365eM9ftkmKC8v17Rp05SQkKCwsDB17txZzz//vL7++mvnw3FatWoli8WiW265RdLpR0TPmzdPnTp1UkREhHr16qV//etfLu/zxhtv6MILL1RERIQGDhzoEmdtTZs2TRdeeKGaN2+u888/XzNmzFBlZWWNcc8884wSEhLUvHlzXXfddSouLnY5/txzz6lbt24KDw9X165d9fTTT3scC4DAIRmAaURERKiiosL5etOmTcrLy1NWVpY2bNigyspKpaSkKDIyUtu2bdMHH3ygli1basiQIc7znnjiCa1atUorVqzQ+++/r8LCQr322mu/+r4333yz/vGPfygzM1N79+7VM888o5YtWyohIUGvvPKKJCkvL0/Hjh3Tk08+KUmaN2+eVq9erWXLlmnPnj2aPHmybrzxRm3ZskXS6aRl9OjRGjFihHJzc3Xrrbfqvvvu8/jfJDIyUqtWrdIXX3yhJ598Us8++6wWLlzoMubAgQN6+eWXtX79em3cuFEff/yxbr/9dufxNWvWaObMmXrooYe0d+9ePfzww5oxY4ZeeOEFj+MBECAG0ASlpaUZI0eONAzDMBwOh5GVlWWEhYUZ99xzj/N4XFycUV5e7jzn73//u9GlSxfD4XA495WXlxsRERHGW2+9ZRiGYbRr186YP3++83hlZaXRvn1753sZhmFcffXVxl133WUYhmHk5eUZkoysrKwzxvnuu+8akoyTJ08695WVlRnNmzc3tm/f7jI2PT3duP766w3DMIz777/f6N69u8vxadOm1bjWL0kyXnvtNbfHH3vsMaNPnz7O17NmzTKCg4ONb7/91rnvzTffNIKCgoxjx44ZhmEYv/nNb4y1a9e6XOeBBx4wkpKSDMMwjEOHDhmSjI8//tjt+wIILOYMoMnasGGDWrZsqcrKSjkcDt1www2aPXu283jPnj1d5gl88sknOnDggCIjI12uU1ZWpq+++krFxcU6duyYEhMTncdCQkLUt2/fGq2Carm5uQoODtbVV19d67gPHDigH374Qb///e9d9ldUVOiSSy6RJO3du9clDklKSkqq9XtUe+mll5SZmamvvvpKJSUlqqqqUlRUlMuYDh066Nxzz3V5H4fDoby8PEVGRuqrr75Senq6xo8f7xxTVVWl6Ohoj+MBEBgkA2iyBg4cqKVLlyo0NFRWq1UhIa4/7i1atHB5XVJSoj59+mjNmjU1rnXOOefUKYaIiAiPzykpKZEk/fvf/3b5EpZOz4PwlezsbKWmpmrOnDlKSUlRdHS0XnzxRT3xxBMex/rss8/WSE6Cg4N9FisA/yIZQJPVokULde7cudbjf/vb3+qll15S27Zta/x1XK1du3basWOH+vfvL+n0X8A5OTn67W9/e8bxPXv2lMPh0JYtW5ScnFzjeHVlwm63O/d1795dYWFhOnz4sNuKQrdu3ZyTIat9+OGHZ/+QP7N9+3Z17NhRf/vb35z7vvnmmxrjDh8+rKNHj8pqtTrfJygoSF26dFFcXJysVqsOHjyo1NRUj94fQMPBBELgR6mpqWrTpo1Gjhypbdu26dChQ3rvvfd055136ttvv5Uk3XXXXXrkkUe0bt067du3T7fffvuvrhFw3nnnKS0tTX/+85+1bt065zVffvllSVLHjh1lsVi0YcMGnThxQiUlJYqMjNQ999yjyZMn64UXXtBXX32l3bt3a/Hixc5JeX/961+1f/9+TZ06VXl5eVq7dq1WrVrl0ee94IILdPjwYb344ov66quvlJmZecbJkOHh4UpLS9Mnn3yibdu26c4779R1112n+Ph4SdKcOXM0b948ZWZm6ssvv9Rnn32mlStXasGCBR7FAyBwSAaAHzVv3lxbt25Vhw4dNHr0aHXr1k3p6ekqKytzVgruvvtu3XTTTUpLS1NSUpIiIyP1xz/+8Vevu3TpUl177bW6/fbb1bVrV40fP16lpaWSpHPPPVdz5szRfffdp7i4OGVkZEiSHnjgAc2YMUPz5s1Tt27dNGTIEP373/9Wp06dJJ3u47/yyitat26devXqpWXLlunhhx/26PNec801mjx5sjIyMtS7d29t375dM2bMqDGuc+fOGj16tIYNG6bBgwfr4osvdrl18NZbb9Vzzz2nlStXqmfPnrr66qu1atUqZ6wAGj6L4W7mEwAAMAUqAwAAmBzJAAAAJkcyAACAyZEMAABgciQDAACYHMkAAAAmRzIAAIDJkQwAAGByJAMAAJgcyQAAACZHMgAAgMn9f4ZzsopucC3IAAAAAElFTkSuQmCC", "text/plain": [ "
" ] @@ -541,23 +546,15 @@ "cell_type": "code", "execution_count": 14, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "/tmp/tmpqbvm6we8\n" - ] - } - ], + "outputs": [], "source": [ "cluster_id = os.getenv(\"NILLION_CLUSTER_ID\")\n", - "print(os.getenv(\"NILLION_USERKEY_PATH_PARTY_1\"))\n", - "model_provider_userkey = getUserKeyFromFile(os.getenv(\"NILLION_USERKEY_PATH_PARTY_1\"))\n", - "model_provider_nodekey = getNodeKeyFromFile(os.getenv(\"NILLION_NODEKEY_PATH_PARTY_1\"))\n", - "model_provider_client = create_nillion_client(\n", - " model_provider_userkey, model_provider_nodekey\n", - ")\n", + "grpc_endpoint = os.getenv(\"NILLION_NILCHAIN_GRPC\")\n", + "chain_id = os.getenv(\"NILLION_NILCHAIN_CHAIN_ID\")\n", + "seed = \"my_seed\"\n", + "model_provider_userkey = UserKey.from_seed((seed))\n", + "model_provider_nodekey = NodeKey.from_seed((seed))\n", + "model_provider_client = create_nillion_client(model_provider_userkey, model_provider_nodekey)\n", "model_provider_party_id = model_provider_client.party_id\n", "model_provider_user_id = model_provider_client.user_id" ] @@ -568,60 +565,37 @@ "metadata": {}, "outputs": [], "source": [ - "model_user_userkey = getUserKeyFromFile(os.getenv(\"NILLION_USERKEY_PATH_PARTY_2\"))\n", - "model_user_nodekey = getNodeKeyFromFile(os.getenv(\"NILLION_NODEKEY_PATH_PARTY_2\"))\n", - "model_user_client = create_nillion_client(model_user_userkey, model_user_nodekey)\n", - "model_user_party_id = model_user_client.party_id\n", - "model_user_user_id = create_nillion_client(\n", - " model_user_userkey, model_user_nodekey\n", - ").user_id" + "party_names = [\"Provider\", \"User\"]\n", + "program_name = \"multi_layer_perceptron\"\n", + "program_mir_path = f\"target/{program_name}.nada.bin\"" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 16, "metadata": {}, + "outputs": [], "source": [ - "### Upload Nada program to Nillion" + "payments_config = create_payments_config(chain_id, grpc_endpoint)\n", + "payments_client = LedgerClient(payments_config)\n", + "payments_wallet = LocalWallet(\n", + " PrivateKey(bytes.fromhex(os.getenv(\"NILLION_NILCHAIN_PRIVATE_KEY_0\"))),\n", + " prefix=\"nillion\",\n", + ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "TODO: explain what the Nada program does" + "### Upload Nada program to Nillion" ] }, { - "cell_type": "code", - "execution_count": 16, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "async def store_program(\n", - " *,\n", - " client: nillion.NillionClient,\n", - " cluster_id: str,\n", - " user_id: str,\n", - " nada_program_path: str,\n", - ") -> Dict[str, str]:\n", - " \"\"\"Stores Nada program binary in Nillion network.\n", - "\n", - " Args:\n", - " client (nillion.NillionClient): Client that will upload Nada program.\n", - " cluster_id (str): Nillion cluster ID.\n", - " user_id (str): User ID of user that will upload Nada program.\n", - " nada_program_path (str): Path to Nada program binary.\n", - "\n", - " Returns:\n", - " Dict[str, str]: Resulting `action_id` and `program_id`.\n", - " \"\"\"\n", - " action_id = await client.store_program(cluster_id, \"multi_layer_perceptron\", nada_program_path)\n", - " program_id = f\"{user_id}/multi_layer_perceptron\"\n", - "\n", - " return {\n", - " \"action_id\": action_id,\n", - " \"program_id\": program_id,\n", - " }" + "TODO: explain what the Nada program does" ] }, { @@ -633,26 +607,23 @@ "name": "stdout", "output_type": "stream", "text": [ - "✅ Program saved successfully!\n", - "action_id: bbdc0628-2272-4405-a63a-7ddf1c238e48\n", - "program_id: 3tkrMbd2fQYTX2MSK31drWKepcmYYbE1MKEQUGRrkdAP9kPCaiVMYaMWUd5xkeeZjaxYFq3bKd1Rhki77oqGVQTR/main\n" + "Getting quote for operation...\n", + "Submitting payment receipt 2 unil, tx hash 32054F2BE5EED437390CDF7A782C6659B8F0C178A398CCF346178E2827C554DB\n", + "Stored program. action_id: 3rgqxWd47e171EUwe4RXP9hm45tmoXfuF8fC52S7jcFoQTnU8wPiL7hqWzyV1muak6bEg7iWhudwg4t2pM9XnXcp/multi_layer_perceptron\n", + "Stored program_id: 3rgqxWd47e171EUwe4RXP9hm45tmoXfuF8fC52S7jcFoQTnU8wPiL7hqWzyV1muak6bEg7iWhudwg4t2pM9XnXcp/multi_layer_perceptron\n" ] } ], "source": [ - "result_store_program = await store_program(\n", - " client=model_provider_client,\n", - " cluster_id=cluster_id,\n", - " user_id=model_provider_user_id,\n", - " nada_program_path=\"target/multi_layer_perceptron.nada.bin\",\n", - ")\n", - "\n", - "action_id = result_store_program[\"action_id\"]\n", - "program_id = result_store_program[\"program_id\"]\n", - "\n", - "print(\"✅ Program saved successfully!\")\n", - "print(\"action_id:\", action_id)\n", - "print(\"program_id:\", program_id)" + "program_id = await store_program(\n", + " model_provider_client,\n", + " payments_wallet,\n", + " payments_client,\n", + " model_provider_user_id,\n", + " cluster_id,\n", + " program_name,\n", + " program_mir_path,\n", + ")" ] }, { @@ -676,95 +647,38 @@ "cell_type": "code", "execution_count": 19, "metadata": {}, - "outputs": [], - "source": [ - "async def store_model(\n", - " *,\n", - " model_client: TorchClient,\n", - " client: nillion.NillionClient,\n", - " cluster_id: str,\n", - " program_id: str,\n", - " party_id: str,\n", - " model_user_user_id: str,\n", - " model_provider_user_id: str,\n", - ") -> Dict[str, str]:\n", - " \"\"\"Stores model params in Nillion network.\n", - "\n", - " Args:\n", - " model (MyModel): Model object to store in network.\n", - " client (nillion.NillionClient): Nillion client that stores model params.\n", - " cluster_id (str): Nillion cluster ID.\n", - " program_id (str): Program ID of Nada program.\n", - " party_id (str): Party ID of party that will store model params.\n", - " model_user_user_id (str): User ID of user that will get compute permissions.\n", - " model_provider_user_id (str): User ID of user that will provide model params.\n", - " precision (int): Desired precision.\n", - "\n", - " Returns:\n", - " Dict[str, str]: Resulting `provider_party_id` and `model_store_id`.\n", - " \"\"\"\n", - "\n", - " model_secrets = nillion.Secrets(\n", - " model_client.export_state_as_secrets(\"my_nn\", na.SecretRational)\n", - " )\n", - "\n", - " secret_bindings = nillion.ProgramBindings(program_id)\n", - " secret_bindings.add_input_party(\"Party0\", party_id)\n", - "\n", - " permissions = nillion.Permissions.default_for_user(model_provider_user_id)\n", - " compute_permissions = {\n", - " model_user_user_id: {program_id},\n", - " }\n", - " # Give permission to model user to run inference\n", - " permissions.add_compute_permissions(compute_permissions)\n", - "\n", - " store_id = await client.store_secrets(\n", - " cluster_id, secret_bindings, model_secrets, permissions\n", - " )\n", - "\n", - " return {\n", - " \"provider_party_id\": party_id,\n", - " \"model_store_id\": store_id,\n", - " }" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "✅ Model params uploaded successfully!\n", - "provider_party_id: 12D3KooWAcTbAaa6LGoCvgB1BPSedAME2ynaEwPLnLYusBDjmSzM\n", - "model_store_id: 4b2b1ebb-b3d5-4811-a980-ac858fd6c0cd\n" + "Getting quote for operation...\n", + "Quote cost is 5570 unil\n", + "Submitting payment receipt 5570 unil, tx hash 6A9CB2D7060BE85272B383A6F23E71D34B10B87D27F21173004990831868683A\n" ] } ], "source": [ - "result_store_model = await store_model(\n", - " model_client=model_client,\n", - " client=model_provider_client,\n", - " cluster_id=cluster_id,\n", - " program_id=program_id,\n", - " party_id=model_provider_party_id,\n", - " model_user_user_id=model_user_user_id,\n", - " model_provider_user_id=model_provider_user_id,\n", + "model_secrets = nillion.NadaValues(\n", + " model_client.export_state_as_secrets(\"my_nn\", na.SecretRational)\n", ")\n", - "\n", - "provider_party_id = result_store_model[\"provider_party_id\"]\n", - "model_store_id = result_store_model[\"model_store_id\"]\n", - "\n", - "print(\"✅ Model params uploaded successfully!\")\n", - "print(\"provider_party_id:\", provider_party_id)\n", - "print(\"model_store_id:\", model_store_id)" + "permissions = nillion.Permissions.default_for_user(model_provider_client.user_id)\n", + "permissions.add_compute_permissions({model_provider_client.user_id: {program_id}})\n", + "\n", + "model_store_id = await store_secrets(\n", + " model_provider_client,\n", + " payments_wallet,\n", + " payments_client,\n", + " cluster_id,\n", + " model_secrets,\n", + " 1,\n", + " permissions,\n", + ")" ] }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 20, "metadata": {}, "outputs": [], "source": [ @@ -780,7 +694,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ diff --git a/examples/multi_layer_perceptron/02_model_inference.ipynb b/examples/multi_layer_perceptron/02_model_inference.ipynb index 215799b..db4fcf1 100644 --- a/examples/multi_layer_perceptron/02_model_inference.ipynb +++ b/examples/multi_layer_perceptron/02_model_inference.ipynb @@ -9,7 +9,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -30,28 +30,35 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "from typing import Dict\n", - "import torch\n", + "import os\n", + "import sys\n", + "\n", + "sys.path.append(os.path.abspath(os.path.join(os.getcwd(), os.pardir)))\n", + "\n", "import json\n", "import os\n", + "from common.utils import compute, store_secret_array\n", + "from nillion_python_helpers import (create_nillion_client,\n", + " create_payments_config)\n", + "from py_nillion_client import NodeKey, UserKey\n", "import py_nillion_client as nillion\n", "from torchvision import transforms\n", + "import nada_numpy as na\n", "from PIL import Image\n", "from dotenv import load_dotenv\n", "import numpy as np\n", + "import torch\n", "\n", - "import nada_numpy as na\n", - "import nada_numpy.client as na_client\n", - "import py_nillion_client as nillion\n", - "from nillion_python_helpers import (\n", - " create_nillion_client,\n", - " getUserKeyFromFile,\n", - " getNodeKeyFromFile,\n", - ")" + "from cosmpy.aerial.client import LedgerClient\n", + "from cosmpy.aerial.wallet import LocalWallet\n", + "from cosmpy.crypto.keypairs import PrivateKey\n", + "\n", + "home = os.getenv(\"HOME\")\n", + "load_dotenv(f\"{home}/.config/nillion/nillion-devnet.env\")" ] }, { @@ -74,20 +81,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# Load all Nillion network environment variables\n", "assert os.getcwd().endswith(\n", @@ -98,13 +94,16 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cluster_id = os.getenv(\"NILLION_CLUSTER_ID\")\n", - "model_user_userkey = getUserKeyFromFile(os.getenv(\"NILLION_USERKEY_PATH_PARTY_2\"))\n", - "model_user_nodekey = getNodeKeyFromFile(os.getenv(\"NILLION_NODEKEY_PATH_PARTY_2\"))\n", + "grpc_endpoint = os.getenv(\"NILLION_NILCHAIN_GRPC\")\n", + "chain_id = os.getenv(\"NILLION_NILCHAIN_CHAIN_ID\")\n", + "seed = \"my_seed\"\n", + "model_user_userkey = UserKey.from_seed((seed))\n", + "model_user_nodekey = NodeKey.from_seed((seed))\n", "model_user_client = create_nillion_client(model_user_userkey, model_user_nodekey)\n", "model_user_party_id = model_user_client.party_id\n", "model_user_user_id = model_user_client.user_id" @@ -112,19 +111,23 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "payments_config = create_payments_config(chain_id, grpc_endpoint)\n", + "payments_client = LedgerClient(payments_config)\n", + "payments_wallet = LocalWallet(\n", + " PrivateKey(bytes.fromhex(os.getenv(\"NILLION_NILCHAIN_PRIVATE_KEY_0\"))),\n", + " prefix=\"nillion\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Program ID: 3tkrMbd2fQYTX2MSK31drWKepcmYYbE1MKEQUGRrkdAP9kPCaiVMYaMWUd5xkeeZjaxYFq3bKd1Rhki77oqGVQTR/main\n", - "Model Store ID: 4b2b1ebb-b3d5-4811-a980-ac858fd6c0cd\n", - "Model Provider Party ID: 12D3KooWAcTbAaa6LGoCvgB1BPSedAME2ynaEwPLnLYusBDjmSzM\n" - ] - } - ], + "outputs": [], "source": [ "# This information was provided by the model provider\n", "with open(\"data/tmp.json\", \"r\") as provider_variables_file:\n", @@ -155,7 +158,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -170,20 +173,9 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(1, 1, 16, 16)" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "test_image_batch = np.array(test_image.unsqueeze(0))\n", "test_image_batch.shape # (B, channels, H, W)" @@ -198,175 +190,73 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "async def store_images(\n", - " *,\n", - " client: nillion.NillionClient,\n", - " cluster_id: str,\n", - " program_id: str,\n", - " party_id: str,\n", - " user_id: str,\n", - " images: torch.Tensor,\n", - ") -> Dict[str, str]:\n", - " \"\"\"Stores text features in Nillion network.\n", - "\n", - " Args:\n", - " client (nillion.NillionClient): Nillion client that stores features.\n", - " cluster_id (str): Nillion cluster ID.\n", - " program_id (str): Program ID of Nada program.\n", - " party_id (str): Party ID of party that will store text features.\n", - " user_id (str): User ID of user that will get compute permissions.\n", - " images (torch.Tensor): Image batch.\n", - " precision (int): Scaling factor to convert float to ints.\n", - "\n", - " Returns:\n", - " Dict[str, str]: Resulting `model_user_party_id` and `images_store_id`.\n", - " \"\"\"\n", - " secrets = nillion.Secrets(\n", - " na_client.array(images, \"my_input\", nada_type=na.SecretRational)\n", - " )\n", - "\n", - " secret_bindings = nillion.ProgramBindings(program_id)\n", - " secret_bindings.add_input_party(\"Party1\", party_id)\n", + "permissions = nillion.Permissions.default_for_user(model_user_client.user_id)\n", + "permissions.add_compute_permissions({model_user_client.user_id: {program_id}})\n", "\n", - " images_store_id = await client.store_secrets(\n", - " cluster_id, secret_bindings, secrets, None\n", - " )\n", - "\n", - " return {\n", - " \"model_user_user_id\": user_id,\n", - " \"images_store_id\": images_store_id,\n", - " }" + "images_store_id = await store_secret_array(\n", + " model_user_client,\n", + " payments_wallet,\n", + " payments_client,\n", + " cluster_id,\n", + " test_image_batch,\n", + " \"my_input\",\n", + " na.SecretRational,\n", + " 1,\n", + " permissions,\n", + ")" ] }, { - "cell_type": "code", - "execution_count": 9, + "cell_type": "markdown", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Images uploaded successfully!\n", - "model_user_user_id: 22K41jnxYNoDDck5ZPgZyAG6Lv52G7xjVHVnfvLovYGCMFUsBB7yYRCaeebnDFh9qEW8ki7a7hbjSnNwBUWNkdmv\n", - "images_store_id: e057d84b-cea0-4a63-8946-bef676759739\n" - ] - } - ], "source": [ - "result_store_features = await store_images(\n", - " client=model_user_client,\n", - " cluster_id=cluster_id,\n", - " program_id=program_id,\n", - " party_id=model_user_party_id,\n", - " user_id=model_user_user_id,\n", - " images=test_image_batch,\n", - ")\n", - "\n", - "model_user_user_id = result_store_features[\"model_user_user_id\"]\n", - "images_store_id = result_store_features[\"images_store_id\"]\n", - "\n", - "print(\"✅ Images uploaded successfully!\")\n", - "print(\"model_user_user_id:\", model_user_user_id)\n", - "print(\"images_store_id:\", images_store_id)" + "### Run inference & check result" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ - "### Run inference & check result" + "compute_bindings = nillion.ProgramBindings(program_id)\n", + "\n", + "compute_bindings.add_input_party(\"Provider\", model_provider_party_id)\n", + "compute_bindings.add_input_party(\"User\", model_user_party_id)\n", + "compute_bindings.add_output_party(\"User\", model_user_party_id)" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "async def run_inference(\n", - " *,\n", - " client: nillion.NillionClient,\n", - " cluster_id: str,\n", - " program_id: str,\n", - " model_user_party_id: str,\n", - " model_provider_party_id: str,\n", - " model_store_id: str,\n", - " images_store_id: str,\n", - ") -> Dict[str, str | float]:\n", - " \"\"\"Runs blind inference on the Nillion network by executing the Nada program on the uploaded data.\n", - "\n", - " Args:\n", - " client (nillion.NillionClient): Nillion client that runs inference.\n", - " cluster_id (str): Nillion cluster ID.\n", - " program_id (str): Program ID of Nada program.\n", - " model_user_party_id (str): Party ID of party that will run inference.\n", - " model_user_party_id (str): Party ID of party that will provide model params.\n", - " model_store_id (str): Store ID that points to the model params in the Nillion network.\n", - " images_store_id (str): Store ID that points to the images in the Nillion network.\n", - " precision (int): Scaling factor to convert float to ints.s\n", - "\n", - " Returns:\n", - " Dict[str, str | float]: Resulting `compute_id`, `output_0` and `output_1`.\n", - " \"\"\"\n", - " compute_bindings = nillion.ProgramBindings(program_id)\n", - " compute_bindings.add_input_party(\"Party0\", model_user_party_id)\n", - " compute_bindings.add_input_party(\"Party1\", model_provider_party_id)\n", - " compute_bindings.add_output_party(\"Party1\", model_user_party_id)\n", - "\n", - " _ = await client.compute(\n", - " cluster_id,\n", - " compute_bindings,\n", - " [images_store_id, model_store_id],\n", - " nillion.Secrets({}),\n", - " nillion.PublicVariables({}),\n", - " )\n", - "\n", - " while True:\n", - " compute_event = await client.next_compute_event()\n", - " if isinstance(compute_event, nillion.ComputeFinishedEvent):\n", - " inference_result = compute_event.result.value\n", - " break\n", - "\n", - " return {\n", - " \"compute_id\": compute_event.uuid,\n", - " \"output_0\": na_client.float_from_rational(inference_result[\"my_output_0_0\"]),\n", - " \"output_1\": na_client.float_from_rational(inference_result[\"my_output_0_1\"]),\n", - " }" + "result = await compute(\n", + " model_user_client,\n", + " payments_wallet,\n", + " payments_client,\n", + " program_id,\n", + " cluster_id,\n", + " compute_bindings,\n", + " [model_store_id, images_store_id],\n", + " nillion.NadaValues({}),\n", + " verbose=True,\n", + ")\n", + "result" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'compute_id': '67557c31-d7db-4cd3-bb77-e1029011cea7',\n", - " 'output_0': -1.665313720703125,\n", - " 'output_1': 0.876068115234375}" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "result_inference = await run_inference(\n", - " client=model_user_client,\n", - " cluster_id=cluster_id,\n", - " program_id=program_id,\n", - " model_user_party_id=model_user_party_id,\n", - " model_provider_party_id=model_provider_party_id,\n", - " model_store_id=model_store_id,\n", - " images_store_id=images_store_id,\n", - ")\n", + "result_inference = {key: na.float_from_rational(value) for key, value in result.items()}\n", "result_inference" ] }, @@ -379,7 +269,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -389,7 +279,7 @@ "\n", " def __init__(self) -> None:\n", " \"\"\"Model is a two layers and an activations\"\"\"\n", - " super(MyNN, self).__init__()\n", + " super().__init__()\n", " self.conv1 = torch.nn.Conv2d(\n", " in_channels=1, out_channels=2, kernel_size=3, stride=4, padding=1\n", " )\n", @@ -411,20 +301,9 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "my_model = MyNN()\n", "my_model.load_state_dict(torch.load(\"./data/my_model.pt\"))" @@ -432,40 +311,18 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "tensor([0.0730, 0.9270], grad_fn=)" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "torch.softmax(my_model(test_image.unsqueeze(0))[0], dim=0)" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "tensor([0.0730, 0.9270])" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "torch.softmax(\n", " torch.Tensor([result_inference[\"output_0\"], result_inference[\"output_1\"]]), dim=0\n", @@ -489,7 +346,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.12.2" } }, "nbformat": 4, diff --git a/examples/multi_layer_perceptron/src/multi_layer_perceptron.py b/examples/multi_layer_perceptron/src/multi_layer_perceptron.py index 3ace617..7f21328 100644 --- a/examples/multi_layer_perceptron/src/multi_layer_perceptron.py +++ b/examples/multi_layer_perceptron/src/multi_layer_perceptron.py @@ -1,24 +1,26 @@ import nada_numpy as na from my_nn import MyNN +from nada_dsl import Party def nada_main(): - # Step 1: We use Nada NumPy wrapper to create "Party0" and "Party1" - parties = na.parties(2) + # Step 1: We use Nada NumPy wrapper to create "User" and "Provider" + user = Party("User") + provider = Party("Provider") # Step 2: Instantiate model object my_model = MyNN() # Step 3: Load model weights from Nillion network by passing model name (acts as ID) # In this examples Party0 provides the model and Party1 runs inference - my_model.load_state_from_network("my_nn", parties[0], na.SecretRational) + my_model.load_state_from_network("my_nn", provider, na.SecretRational) # Step 4: Load input data to be used for inference (provided by Party1) - my_input = na.array((1, 1, 16, 16), parties[1], "my_input", na.SecretRational) + my_input = na.array((1, 1, 16, 16), user, "my_input", na.SecretRational) # Step 5: Compute inference # Note: completely equivalent to `my_model.forward(...)` result = my_model(my_input) # Step 6: We can use result.output() to produce the output for Party1 and variable name "my_output" - return result.output(parties[1], "my_output") + return result.output(user, "my_output") diff --git a/examples/multi_layer_perceptron/src/my_nn.py b/examples/multi_layer_perceptron/src/my_nn.py index 9ad6746..20e9caf 100644 --- a/examples/multi_layer_perceptron/src/my_nn.py +++ b/examples/multi_layer_perceptron/src/my_nn.py @@ -8,14 +8,12 @@ class MyNN(nn.Module): def __init__(self) -> None: """Model is a two layers and an activations""" - super(MyNN, self).__init__() - # Input size (1, 1, 16, 16) --> Output size (1, 2) + super().__init__() self.conv1 = nn.Conv2d( - in_channels=1, out_channels=2, kernel_size=3, padding=1, stride=4 + in_channels=1, out_channels=2, kernel_size=3, padding=1, stride=3 ) - # Input size (1, 2) --> Output size (1, 2) self.pool = nn.AvgPool2d(kernel_size=2, stride=2) - self.fc1 = nn.Linear(in_features=8, out_features=2) + self.fc1 = nn.Linear(in_features=18, out_features=2) self.relu = nn.ReLU() self.flatten = nn.Flatten() diff --git a/examples/multi_layer_perceptron/tests/multi_layer_perceptron.yaml b/examples/multi_layer_perceptron/tests/multi_layer_perceptron.yaml index f2de756..9a44f01 100644 --- a/examples/multi_layer_perceptron/tests/multi_layer_perceptron.yaml +++ b/examples/multi_layer_perceptron/tests/multi_layer_perceptron.yaml @@ -1,326 +1,634 @@ --- program: multi_layer_perceptron inputs: - secrets: - my_input_0_0_12_7: - SecretInteger: "3" - my_input_0_0_11_12: - SecretInteger: "3" - my_input_0_0_0_11: - SecretInteger: "3" - my_input_0_0_8_0: - SecretInteger: "3" - my_nn_fc1.weight_0_4: - SecretInteger: "3" - my_input_0_0_8_5: - SecretInteger: "3" - my_input_0_0_3_0: - SecretInteger: "3" - my_input_0_0_9_3: - SecretInteger: "3" - my_nn_fc1.weight_0_7: - SecretInteger: "3" - my_input_0_0_13_3: - SecretInteger: "3" - my_input_0_0_11_9: - SecretInteger: "3" - my_input_0_0_9_8: - SecretInteger: "3" - my_input_0_0_3_12: - SecretInteger: "3" - my_input_0_0_4_3: - SecretInteger: "3" - my_nn_conv1.weight_1_0_2_2: - SecretInteger: "3" - my_input_0_0_1_1: - SecretInteger: "3" - my_nn_fc1.weight_0_5: - SecretInteger: "3" - my_input_0_0_1_0: - SecretInteger: "3" - my_input_0_0_9_1: - SecretInteger: "3" - my_input_0_0_4_8: - SecretInteger: "3" - my_input_0_0_4_9: - SecretInteger: "3" - my_input_0_0_1_7: - SecretInteger: "3" - my_nn_fc1.bias_0: - SecretInteger: "3" - my_nn_conv1.weight_0_0_2_2: - SecretInteger: "3" - my_nn_fc1.weight_0_1: - SecretInteger: "3" - my_nn_conv1.weight_1_0_1_0: - SecretInteger: "3" - my_input_0_0_12_9: - SecretInteger: "3" - my_input_0_0_8_1: - SecretInteger: "3" - my_nn_conv1.weight_1_0_0_1: - SecretInteger: "3" - my_input_0_0_13_5: - SecretInteger: "3" - my_input_0_0_0_4: - SecretInteger: "3" - my_input_0_0_11_7: - SecretInteger: "3" - my_input_0_0_0_9: - SecretInteger: "3" - my_nn_fc1.weight_1_1: - SecretInteger: "3" - my_input_0_0_0_0: - SecretInteger: "3" - my_input_0_0_8_4: - SecretInteger: "3" - my_input_0_0_7_9: - SecretInteger: "3" - my_nn_fc1.weight_1_7: - SecretInteger: "3" - my_input_0_0_4_13: - SecretInteger: "3" - my_input_0_0_12_0: - SecretInteger: "3" - my_input_0_0_1_12: - SecretInteger: "3" - my_nn_conv1.weight_0_0_1_2: - SecretInteger: "3" - my_nn_fc1.weight_0_6: - SecretInteger: "3" - my_input_0_0_0_1: - SecretInteger: "3" - my_input_0_0_7_1: - SecretInteger: "3" - my_nn_conv1.weight_0_0_2_1: - SecretInteger: "3" - my_input_0_0_3_7: - SecretInteger: "3" - my_input_0_0_0_3: - SecretInteger: "3" - my_input_0_0_5_1: - SecretInteger: "3" - my_nn_conv1.weight_1_0_0_2: - SecretInteger: "3" - my_input_0_0_3_13: - SecretInteger: "3" - my_input_0_0_4_1: - SecretInteger: "3" - my_input_0_0_7_11: - SecretInteger: "3" - my_input_0_0_3_9: - SecretInteger: "3" - my_input_0_0_8_9: - SecretInteger: "3" - my_input_0_0_11_1: - SecretInteger: "3" - my_input_0_0_12_12: - SecretInteger: "3" - my_input_0_0_9_0: - SecretInteger: "3" - my_input_0_0_4_0: - SecretInteger: "3" - my_input_0_0_8_7: - SecretInteger: "3" - my_input_0_0_3_3: - SecretInteger: "3" - my_input_0_0_7_5: - SecretInteger: "3" - my_input_0_0_9_5: - SecretInteger: "3" - my_input_0_0_8_11: - SecretInteger: "3" - my_input_0_0_13_8: - SecretInteger: "3" - my_input_0_0_5_5: - SecretInteger: "3" - my_input_0_0_7_7: - SecretInteger: "3" - my_input_0_0_4_11: - SecretInteger: "3" - my_input_0_0_12_5: - SecretInteger: "3" - my_nn_conv1.weight_1_0_2_0: - SecretInteger: "3" - my_nn_fc1.weight_1_2: - SecretInteger: "3" - my_input_0_0_5_12: - SecretInteger: "3" - my_input_0_0_13_13: - SecretInteger: "3" - my_input_0_0_5_7: - SecretInteger: "3" - my_input_0_0_7_3: - SecretInteger: "3" - my_input_0_0_1_5: - SecretInteger: "3" - my_input_0_0_1_9: - SecretInteger: "3" - my_nn_fc1.weight_1_0: - SecretInteger: "3" - my_input_0_0_7_12: - SecretInteger: "3" - my_input_0_0_11_11: - SecretInteger: "3" - my_input_0_0_8_8: - SecretInteger: "3" - my_input_0_0_5_8: - SecretInteger: "3" - my_input_0_0_12_3: - SecretInteger: "3" - my_input_0_0_1_4: - SecretInteger: "3" - my_input_0_0_11_8: - SecretInteger: "3" - my_input_0_0_0_13: - SecretInteger: "3" - my_input_0_0_12_4: - SecretInteger: "3" - my_input_0_0_3_11: - SecretInteger: "3" - my_input_0_0_11_0: - SecretInteger: "3" - my_input_0_0_8_12: - SecretInteger: "3" - my_input_0_0_0_7: - SecretInteger: "3" - my_input_0_0_9_12: - SecretInteger: "3" - my_nn_conv1.weight_1_0_1_2: - SecretInteger: "3" - my_input_0_0_0_12: - SecretInteger: "3" - my_input_0_0_13_4: - SecretInteger: "3" - my_input_0_0_5_13: - SecretInteger: "3" - my_nn_conv1.bias_0: - SecretInteger: "3" - my_nn_conv1.weight_1_0_1_1: - SecretInteger: "3" - my_input_0_0_7_8: - SecretInteger: "3" - my_input_0_0_1_11: - SecretInteger: "3" - my_input_0_0_8_3: - SecretInteger: "3" - my_nn_conv1.weight_1_0_2_1: - SecretInteger: "3" - my_input_0_0_11_5: - SecretInteger: "3" - my_nn_fc1.weight_1_3: - SecretInteger: "3" - my_input_0_0_3_8: - SecretInteger: "3" - my_input_0_0_9_7: - SecretInteger: "3" - my_input_0_0_12_11: - SecretInteger: "3" - my_nn_fc1.weight_1_6: - SecretInteger: "3" - my_nn_fc1.bias_1: - SecretInteger: "3" - my_input_0_0_7_13: - SecretInteger: "3" - my_input_0_0_11_3: - SecretInteger: "3" - my_input_0_0_9_4: - SecretInteger: "3" - my_nn_conv1.weight_1_0_0_0: - SecretInteger: "3" - my_input_0_0_13_12: - SecretInteger: "3" - my_input_0_0_0_5: - SecretInteger: "3" - my_input_0_0_5_0: - SecretInteger: "3" - my_input_0_0_7_0: - SecretInteger: "3" - my_input_0_0_4_4: - SecretInteger: "3" - my_input_0_0_4_12: - SecretInteger: "3" - my_input_0_0_5_9: - SecretInteger: "3" - my_input_0_0_12_8: - SecretInteger: "3" - my_input_0_0_13_9: - SecretInteger: "3" - my_input_0_0_1_13: - SecretInteger: "3" - my_input_0_0_12_13: - SecretInteger: "3" - my_input_0_0_3_5: - SecretInteger: "3" - my_input_0_0_11_4: - SecretInteger: "3" - my_nn_conv1.weight_0_0_0_0: - SecretInteger: "3" - my_input_0_0_5_11: - SecretInteger: "3" - my_input_0_0_13_1: - SecretInteger: "3" - my_input_0_0_8_13: - SecretInteger: "3" - my_input_0_0_3_4: - SecretInteger: "3" - my_nn_conv1.bias_1: - SecretInteger: "3" - my_input_0_0_5_4: - SecretInteger: "3" - my_input_0_0_4_5: - SecretInteger: "3" - my_input_0_0_0_8: - SecretInteger: "3" - my_input_0_0_4_7: - SecretInteger: "3" - my_input_0_0_9_11: - SecretInteger: "3" - my_input_0_0_13_11: - SecretInteger: "3" - my_nn_conv1.weight_0_0_2_0: - SecretInteger: "3" - my_nn_conv1.weight_0_0_0_1: - SecretInteger: "3" - my_input_0_0_13_7: - SecretInteger: "3" - my_nn_conv1.weight_0_0_0_2: - SecretInteger: "3" - my_nn_conv1.weight_0_0_1_1: - SecretInteger: "3" - my_nn_fc1.weight_0_0: - SecretInteger: "3" - my_input_0_0_1_3: - SecretInteger: "3" - my_input_0_0_5_3: - SecretInteger: "3" - my_nn_conv1.weight_0_0_1_0: - SecretInteger: "3" - my_input_0_0_12_1: - SecretInteger: "3" - my_input_0_0_9_9: - SecretInteger: "3" - my_input_0_0_9_13: - SecretInteger: "3" - my_input_0_0_11_13: - SecretInteger: "3" - my_nn_fc1.weight_1_4: - SecretInteger: "3" - my_input_0_0_3_1: - SecretInteger: "3" - my_nn_fc1.weight_1_5: - SecretInteger: "3" - my_nn_fc1.weight_0_2: - SecretInteger: "3" - my_input_0_0_13_0: - SecretInteger: "3" - my_input_0_0_1_8: - SecretInteger: "3" - my_input_0_0_7_4: - SecretInteger: "3" - my_nn_fc1.weight_0_3: - SecretInteger: "3" - public_variables: {} + my_input_0_0_1_6: + SecretInteger: "3" + my_nn_fc1.weight_0_16: + SecretInteger: "3" + my_input_0_0_8_15: + SecretInteger: "3" + my_nn_fc1.weight_0_12: + SecretInteger: "3" + my_input_0_0_14_9: + SecretInteger: "3" + my_input_0_0_14_7: + SecretInteger: "3" + my_input_0_0_2_7: + SecretInteger: "3" + my_input_0_0_11_3: + SecretInteger: "3" + my_input_0_0_13_9: + SecretInteger: "3" + my_input_0_0_8_2: + SecretInteger: "3" + my_input_0_0_0_11: + SecretInteger: "3" + my_input_0_0_4_10: + SecretInteger: "3" + my_input_0_0_0_1: + SecretInteger: "3" + my_input_0_0_13_7: + SecretInteger: "3" + my_input_0_0_10_1: + SecretInteger: "3" + my_nn_fc1.bias_1: + SecretInteger: "3" + my_input_0_0_12_14: + SecretInteger: "3" + my_input_0_0_11_12: + SecretInteger: "3" + my_input_0_0_15_10: + SecretInteger: "3" + my_input_0_0_14_5: + SecretInteger: "3" + my_input_0_0_15_3: + SecretInteger: "3" + my_input_0_0_5_15: + SecretInteger: "3" + my_input_0_0_7_4: + SecretInteger: "3" + my_input_0_0_3_14: + SecretInteger: "3" + my_input_0_0_2_13: + SecretInteger: "3" + my_input_0_0_2_12: + SecretInteger: "3" + my_input_0_0_0_12: + SecretInteger: "3" + my_input_0_0_11_6: + SecretInteger: "3" + my_input_0_0_4_8: + SecretInteger: "3" + my_nn_fc1.weight_0_9: + SecretInteger: "3" + my_input_0_0_13_3: + SecretInteger: "3" + my_nn_conv1.weight_1_0_0_0: + SecretInteger: "3" + my_input_0_0_2_14: + SecretInteger: "3" + my_input_0_0_10_10: + SecretInteger: "3" + my_nn_fc1.weight_1_12: + SecretInteger: "3" + my_input_0_0_13_8: + SecretInteger: "3" + my_nn_conv1.weight_1_0_2_0: + SecretInteger: "3" + my_input_0_0_1_11: + SecretInteger: "3" + my_nn_conv1.weight_1_0_2_2: + SecretInteger: "3" + my_input_0_0_3_15: + SecretInteger: "3" + my_input_0_0_4_14: + SecretInteger: "3" + my_input_0_0_9_4: + SecretInteger: "3" + my_nn_fc1.weight_1_0: + SecretInteger: "3" + my_input_0_0_11_14: + SecretInteger: "3" + my_input_0_0_12_6: + SecretInteger: "3" + my_input_0_0_7_11: + SecretInteger: "3" + my_input_0_0_5_1: + SecretInteger: "3" + my_input_0_0_0_8: + SecretInteger: "3" + my_input_0_0_12_3: + SecretInteger: "3" + my_input_0_0_15_1: + SecretInteger: "3" + my_nn_fc1.weight_1_13: + SecretInteger: "3" + my_input_0_0_12_0: + SecretInteger: "3" + my_input_0_0_8_9: + SecretInteger: "3" + my_nn_fc1.weight_1_6: + SecretInteger: "3" + my_input_0_0_7_7: + SecretInteger: "3" + my_input_0_0_0_15: + SecretInteger: "3" + my_nn_conv1.weight_1_0_1_0: + SecretInteger: "3" + my_input_0_0_13_14: + SecretInteger: "3" + my_input_0_0_1_1: + SecretInteger: "3" + my_input_0_0_11_0: + SecretInteger: "3" + my_input_0_0_5_14: + SecretInteger: "3" + my_input_0_0_15_2: + SecretInteger: "3" + my_input_0_0_8_3: + SecretInteger: "3" + my_input_0_0_9_2: + SecretInteger: "3" + my_input_0_0_9_1: + SecretInteger: "3" + my_nn_fc1.weight_1_10: + SecretInteger: "3" + my_input_0_0_10_4: + SecretInteger: "3" + my_input_0_0_6_0: + SecretInteger: "3" + my_input_0_0_6_4: + SecretInteger: "3" + my_nn_conv1.weight_1_0_1_1: + SecretInteger: "3" + my_input_0_0_12_7: + SecretInteger: "3" + my_nn_conv1.bias_1: + SecretInteger: "3" + my_nn_conv1.weight_0_0_1_1: + SecretInteger: "3" + my_input_0_0_5_12: + SecretInteger: "3" + my_input_0_0_5_10: + SecretInteger: "3" + my_input_0_0_9_0: + SecretInteger: "3" + my_nn_fc1.weight_0_10: + SecretInteger: "3" + my_nn_conv1.weight_1_0_2_1: + SecretInteger: "3" + my_input_0_0_9_3: + SecretInteger: "3" + my_nn_fc1.weight_0_7: + SecretInteger: "3" + my_input_0_0_4_4: + SecretInteger: "3" + my_nn_fc1.weight_1_17: + SecretInteger: "3" + my_input_0_0_14_11: + SecretInteger: "3" + my_input_0_0_12_8: + SecretInteger: "3" + my_input_0_0_9_5: + SecretInteger: "3" + my_input_0_0_10_12: + SecretInteger: "3" + my_nn_fc1.weight_0_3: + SecretInteger: "3" + my_input_0_0_13_5: + SecretInteger: "3" + my_input_0_0_7_6: + SecretInteger: "3" + my_nn_conv1.weight_0_0_1_2: + SecretInteger: "3" + my_input_0_0_12_2: + SecretInteger: "3" + my_input_0_0_12_11: + SecretInteger: "3" + my_input_0_0_13_11: + SecretInteger: "3" + my_input_0_0_14_6: + SecretInteger: "3" + my_input_0_0_11_1: + SecretInteger: "3" + my_input_0_0_5_11: + SecretInteger: "3" + my_input_0_0_7_1: + SecretInteger: "3" + my_input_0_0_2_10: + SecretInteger: "3" + my_input_0_0_1_2: + SecretInteger: "3" + my_input_0_0_11_11: + SecretInteger: "3" + my_input_0_0_9_11: + SecretInteger: "3" + my_nn_fc1.weight_0_5: + SecretInteger: "3" + my_input_0_0_10_13: + SecretInteger: "3" + my_input_0_0_8_6: + SecretInteger: "3" + my_input_0_0_7_5: + SecretInteger: "3" + my_input_0_0_15_14: + SecretInteger: "3" + my_input_0_0_10_15: + SecretInteger: "3" + my_input_0_0_6_1: + SecretInteger: "3" + my_input_0_0_2_9: + SecretInteger: "3" + my_nn_conv1.weight_0_0_0_2: + SecretInteger: "3" + my_input_0_0_8_13: + SecretInteger: "3" + my_input_0_0_8_7: + SecretInteger: "3" + my_input_0_0_15_4: + SecretInteger: "3" + my_input_0_0_1_9: + SecretInteger: "3" + my_input_0_0_0_5: + SecretInteger: "3" + my_nn_fc1.weight_0_15: + SecretInteger: "3" + my_input_0_0_12_5: + SecretInteger: "3" + my_input_0_0_9_7: + SecretInteger: "3" + my_input_0_0_0_7: + SecretInteger: "3" + my_input_0_0_4_1: + SecretInteger: "3" + my_input_0_0_3_10: + SecretInteger: "3" + my_input_0_0_0_9: + SecretInteger: "3" + my_input_0_0_1_4: + SecretInteger: "3" + my_input_0_0_7_15: + SecretInteger: "3" + my_input_0_0_11_13: + SecretInteger: "3" + my_input_0_0_12_9: + SecretInteger: "3" + my_input_0_0_1_10: + SecretInteger: "3" + my_input_0_0_13_1: + SecretInteger: "3" + my_input_0_0_11_15: + SecretInteger: "3" + my_input_0_0_0_10: + SecretInteger: "3" + my_input_0_0_1_15: + SecretInteger: "3" + my_input_0_0_1_7: + SecretInteger: "3" + my_input_0_0_3_4: + SecretInteger: "3" + my_input_0_0_11_5: + SecretInteger: "3" + my_input_0_0_12_13: + SecretInteger: "3" + my_input_0_0_11_4: + SecretInteger: "3" + my_nn_fc1.weight_0_0: + SecretInteger: "3" + my_input_0_0_14_13: + SecretInteger: "3" + my_input_0_0_13_12: + SecretInteger: "3" + my_input_0_0_10_8: + SecretInteger: "3" + my_input_0_0_13_15: + SecretInteger: "3" + my_input_0_0_3_0: + SecretInteger: "3" + my_input_0_0_0_2: + SecretInteger: "3" + my_input_0_0_3_6: + SecretInteger: "3" + my_input_0_0_11_8: + SecretInteger: "3" + my_nn_fc1.weight_0_1: + SecretInteger: "3" + my_input_0_0_6_6: + SecretInteger: "3" + my_input_0_0_1_8: + SecretInteger: "3" + my_input_0_0_1_0: + SecretInteger: "3" + my_input_0_0_14_12: + SecretInteger: "3" + my_input_0_0_15_13: + SecretInteger: "3" + my_input_0_0_7_14: + SecretInteger: "3" + my_input_0_0_3_11: + SecretInteger: "3" + my_input_0_0_14_10: + SecretInteger: "3" + my_input_0_0_14_1: + SecretInteger: "3" + my_input_0_0_14_3: + SecretInteger: "3" + my_input_0_0_10_6: + SecretInteger: "3" + my_input_0_0_10_0: + SecretInteger: "3" + my_input_0_0_8_8: + SecretInteger: "3" + my_input_0_0_15_12: + SecretInteger: "3" + my_input_0_0_3_1: + SecretInteger: "3" + my_input_0_0_2_8: + SecretInteger: "3" + my_input_0_0_7_12: + SecretInteger: "3" + my_input_0_0_0_0: + SecretInteger: "3" + my_input_0_0_4_0: + SecretInteger: "3" + my_input_0_0_15_9: + SecretInteger: "3" + my_input_0_0_0_13: + SecretInteger: "3" + my_input_0_0_2_4: + SecretInteger: "3" + my_input_0_0_1_12: + SecretInteger: "3" + my_input_0_0_11_10: + SecretInteger: "3" + my_nn_fc1.weight_1_7: + SecretInteger: "3" + my_input_0_0_8_10: + SecretInteger: "3" + my_input_0_0_2_2: + SecretInteger: "3" + my_input_0_0_13_10: + SecretInteger: "3" + my_input_0_0_6_13: + SecretInteger: "3" + my_input_0_0_8_4: + SecretInteger: "3" + my_input_0_0_6_9: + SecretInteger: "3" + my_input_0_0_14_4: + SecretInteger: "3" + my_input_0_0_6_14: + SecretInteger: "3" + my_input_0_0_6_11: + SecretInteger: "3" + my_input_0_0_4_3: + SecretInteger: "3" + my_input_0_0_7_13: + SecretInteger: "3" + my_input_0_0_4_6: + SecretInteger: "3" + my_input_0_0_10_2: + SecretInteger: "3" + my_input_0_0_9_15: + SecretInteger: "3" + my_nn_fc1.weight_0_14: + SecretInteger: "3" + my_input_0_0_0_14: + SecretInteger: "3" + my_input_0_0_9_6: + SecretInteger: "3" + my_input_0_0_10_11: + SecretInteger: "3" + my_input_0_0_3_12: + SecretInteger: "3" + my_input_0_0_1_13: + SecretInteger: "3" + my_input_0_0_13_2: + SecretInteger: "3" + my_input_0_0_3_7: + SecretInteger: "3" + my_input_0_0_3_2: + SecretInteger: "3" + my_input_0_0_4_5: + SecretInteger: "3" + my_input_0_0_12_4: + SecretInteger: "3" + my_input_0_0_2_15: + SecretInteger: "3" + my_input_0_0_15_11: + SecretInteger: "3" + my_input_0_0_13_0: + SecretInteger: "3" + my_input_0_0_10_7: + SecretInteger: "3" + my_input_0_0_7_8: + SecretInteger: "3" + my_input_0_0_4_13: + SecretInteger: "3" + my_input_0_0_4_2: + SecretInteger: "3" + my_input_0_0_8_1: + SecretInteger: "3" + my_input_0_0_14_14: + SecretInteger: "3" + my_input_0_0_5_0: + SecretInteger: "3" + my_nn_fc1.bias_0: + SecretInteger: "3" + my_nn_fc1.weight_1_15: + SecretInteger: "3" + my_input_0_0_5_4: + SecretInteger: "3" + my_input_0_0_0_4: + SecretInteger: "3" + my_nn_fc1.weight_1_8: + SecretInteger: "3" + my_input_0_0_9_9: + SecretInteger: "3" + my_input_0_0_2_3: + SecretInteger: "3" + my_input_0_0_0_3: + SecretInteger: "3" + my_input_0_0_9_13: + SecretInteger: "3" + my_nn_fc1.weight_1_9: + SecretInteger: "3" + my_input_0_0_3_5: + SecretInteger: "3" + my_input_0_0_7_0: + SecretInteger: "3" + my_input_0_0_6_10: + SecretInteger: "3" + my_nn_fc1.weight_0_6: + SecretInteger: "3" + my_input_0_0_8_5: + SecretInteger: "3" + my_input_0_0_10_9: + SecretInteger: "3" + my_input_0_0_5_9: + SecretInteger: "3" + my_nn_fc1.weight_1_16: + SecretInteger: "3" + my_input_0_0_14_15: + SecretInteger: "3" + my_input_0_0_2_6: + SecretInteger: "3" + my_input_0_0_14_0: + SecretInteger: "3" + my_input_0_0_10_3: + SecretInteger: "3" + my_input_0_0_10_5: + SecretInteger: "3" + my_input_0_0_4_11: + SecretInteger: "3" + my_input_0_0_1_14: + SecretInteger: "3" + my_nn_conv1.weight_1_0_1_2: + SecretInteger: "3" + my_input_0_0_15_8: + SecretInteger: "3" + my_input_0_0_3_13: + SecretInteger: "3" + my_nn_conv1.weight_1_0_0_1: + SecretInteger: "3" + my_input_0_0_2_0: + SecretInteger: "3" + my_input_0_0_1_3: + SecretInteger: "3" + my_nn_fc1.weight_1_11: + SecretInteger: "3" + my_nn_fc1.weight_0_13: + SecretInteger: "3" + my_input_0_0_12_1: + SecretInteger: "3" + my_input_0_0_15_7: + SecretInteger: "3" + my_input_0_0_14_8: + SecretInteger: "3" + my_input_0_0_15_15: + SecretInteger: "3" + my_input_0_0_6_8: + SecretInteger: "3" + my_input_0_0_5_2: + SecretInteger: "3" + my_input_0_0_2_5: + SecretInteger: "3" + my_nn_fc1.weight_1_5: + SecretInteger: "3" + my_input_0_0_12_10: + SecretInteger: "3" + my_nn_conv1.bias_0: + SecretInteger: "3" + my_input_0_0_7_10: + SecretInteger: "3" + my_input_0_0_8_14: + SecretInteger: "3" + my_input_0_0_7_3: + SecretInteger: "3" + my_input_0_0_6_2: + SecretInteger: "3" + my_input_0_0_5_13: + SecretInteger: "3" + my_nn_fc1.weight_1_2: + SecretInteger: "3" + my_nn_fc1.weight_1_1: + SecretInteger: "3" + my_nn_fc1.weight_0_17: + SecretInteger: "3" + my_input_0_0_13_6: + SecretInteger: "3" + my_input_0_0_1_5: + SecretInteger: "3" + my_input_0_0_0_6: + SecretInteger: "3" + my_input_0_0_7_2: + SecretInteger: "3" + my_input_0_0_9_12: + SecretInteger: "3" + my_input_0_0_6_12: + SecretInteger: "3" + my_input_0_0_4_7: + SecretInteger: "3" + my_input_0_0_9_14: + SecretInteger: "3" + my_nn_fc1.weight_0_4: + SecretInteger: "3" + my_nn_conv1.weight_0_0_2_0: + SecretInteger: "3" + my_input_0_0_13_4: + SecretInteger: "3" + my_input_0_0_6_5: + SecretInteger: "3" + my_input_0_0_3_3: + SecretInteger: "3" + my_input_0_0_5_3: + SecretInteger: "3" + my_nn_conv1.weight_0_0_0_1: + SecretInteger: "3" + my_input_0_0_4_9: + SecretInteger: "3" + my_nn_fc1.weight_1_4: + SecretInteger: "3" + my_nn_conv1.weight_0_0_0_0: + SecretInteger: "3" + my_input_0_0_15_6: + SecretInteger: "3" + my_input_0_0_8_12: + SecretInteger: "3" + my_input_0_0_10_14: + SecretInteger: "3" + my_input_0_0_9_8: + SecretInteger: "3" + my_input_0_0_5_7: + SecretInteger: "3" + my_nn_fc1.weight_1_14: + SecretInteger: "3" + my_nn_conv1.weight_0_0_2_2: + SecretInteger: "3" + my_nn_conv1.weight_0_0_1_0: + SecretInteger: "3" + my_input_0_0_4_15: + SecretInteger: "3" + my_input_0_0_6_7: + SecretInteger: "3" + my_input_0_0_8_11: + SecretInteger: "3" + my_input_0_0_5_8: + SecretInteger: "3" + my_input_0_0_4_12: + SecretInteger: "3" + my_input_0_0_12_12: + SecretInteger: "3" + my_input_0_0_2_11: + SecretInteger: "3" + my_nn_fc1.weight_1_3: + SecretInteger: "3" + my_input_0_0_3_9: + SecretInteger: "3" + my_input_0_0_2_1: + SecretInteger: "3" + my_nn_fc1.weight_0_8: + SecretInteger: "3" + my_input_0_0_5_5: + SecretInteger: "3" + my_input_0_0_11_2: + SecretInteger: "3" + my_input_0_0_6_3: + SecretInteger: "3" + my_nn_fc1.weight_0_11: + SecretInteger: "3" + my_input_0_0_11_7: + SecretInteger: "3" + my_input_0_0_15_0: + SecretInteger: "3" + my_nn_conv1.weight_1_0_0_2: + SecretInteger: "3" + my_input_0_0_15_5: + SecretInteger: "3" + my_input_0_0_13_13: + SecretInteger: "3" + my_input_0_0_11_9: + SecretInteger: "3" + my_input_0_0_6_15: + SecretInteger: "3" + my_input_0_0_9_10: + SecretInteger: "3" + my_input_0_0_5_6: + SecretInteger: "3" + my_nn_fc1.weight_0_2: + SecretInteger: "3" + my_input_0_0_14_2: + SecretInteger: "3" + my_nn_conv1.weight_0_0_2_1: + SecretInteger: "3" + my_input_0_0_7_9: + SecretInteger: "3" + my_input_0_0_8_0: + SecretInteger: "3" + my_input_0_0_3_8: + SecretInteger: "3" + my_input_0_0_12_15: + SecretInteger: "3" expected_outputs: my_output_0_0: SecretInteger: "3" diff --git a/examples/neural_net/main.py b/examples/neural_net/main.py index e5dcc82..8f721e0 100644 --- a/examples/neural_net/main.py +++ b/examples/neural_net/main.py @@ -3,7 +3,7 @@ import os import sys -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))) +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import asyncio @@ -12,36 +12,55 @@ import numpy as np import py_nillion_client as nillion import torch +from common.utils import compute, store_program, store_secrets +from cosmpy.aerial.client import LedgerClient +from cosmpy.aerial.wallet import LocalWallet +from cosmpy.crypto.keypairs import PrivateKey from dotenv import load_dotenv -# Import helper functions for creating nillion client and getting keys -from nillion_python_helpers import (create_nillion_client, getNodeKeyFromFile, - getUserKeyFromFile) +from nillion_python_helpers import (create_nillion_client, + create_payments_config) +from py_nillion_client import NodeKey, UserKey -from examples.common.utils import compute, store_program, store_secrets from nada_ai.client import TorchClient -# Load environment variables from a .env file -load_dotenv() +home = os.getenv("HOME") +load_dotenv(f"{home}/.config/nillion/nillion-devnet.env") -# Main asynchronous function to coordinate the process -async def main(): +async def main() -> None: + """Main nada program""" + cluster_id = os.getenv("NILLION_CLUSTER_ID") - userkey = getUserKeyFromFile(os.getenv("NILLION_USERKEY_PATH_PARTY_1")) - nodekey = getNodeKeyFromFile(os.getenv("NILLION_NODEKEY_PATH_PARTY_1")) + grpc_endpoint = os.getenv("NILLION_NILCHAIN_GRPC") + chain_id = os.getenv("NILLION_NILCHAIN_CHAIN_ID") + seed = "my_seed" + userkey = UserKey.from_seed((seed)) + nodekey = NodeKey.from_seed((seed)) client = create_nillion_client(userkey, nodekey) party_id = client.party_id user_id = client.user_id + party_names = na_client.parties(2) program_name = "neural_net" - program_mir_path = f"./target/{program_name}.nada.bin" - - if not os.path.exists("bench"): - os.mkdir("bench") + program_mir_path = f"target/{program_name}.nada.bin" + + # Configure payments + payments_config = create_payments_config(chain_id, grpc_endpoint) + payments_client = LedgerClient(payments_config) + payments_wallet = LocalWallet( + PrivateKey(bytes.fromhex(os.getenv("NILLION_NILCHAIN_PRIVATE_KEY_0"))), + prefix="nillion", + ) - # Store the program + # Store program program_id = await store_program( - client, user_id, cluster_id, program_name, program_mir_path + client, + payments_wallet, + payments_client, + user_id, + cluster_id, + program_name, + program_mir_path, ) # Create custom torch Module @@ -50,7 +69,7 @@ class MyNN(torch.nn.Module): def __init__(self) -> None: """Model is a two layers and an activations""" - super(MyNN, self).__init__() + super().__init__() self.linear_0 = torch.nn.Linear(8, 4) self.linear_1 = torch.nn.Linear(4, 2) self.relu = torch.nn.ReLU() @@ -68,40 +87,60 @@ def forward(self, x: torch.tensor) -> torch.tensor: # Create and store model secrets via ModelClient model_client = TorchClient(my_nn) - model_secrets = nillion.Secrets( + model_secrets = nillion.NadaValues( model_client.export_state_as_secrets("my_nn", na.SecretRational) ) + permissions = nillion.Permissions.default_for_user(client.user_id) + permissions.add_compute_permissions({client.user_id: {program_id}}) model_store_id = await store_secrets( - client, cluster_id, program_id, party_id, party_names[0], model_secrets + client, + payments_wallet, + payments_client, + cluster_id, + model_secrets, + 1, + permissions, ) # Store inputs to perform inference for my_input = na_client.array(np.ones((8,)), "my_input", na.SecretRational) - input_secrets = nillion.Secrets(my_input) + input_secrets = nillion.NadaValues(my_input) data_store_id = await store_secrets( - client, cluster_id, program_id, party_id, party_names[1], input_secrets + client, + payments_wallet, + payments_client, + cluster_id, + input_secrets, + 1, + permissions, ) # Set up the compute bindings for the parties compute_bindings = nillion.ProgramBindings(program_id) - [ + + for party_name in party_names: compute_bindings.add_input_party(party_name, party_id) - for party_name in party_names - ] - compute_bindings.add_output_party(party_names[1], party_id) + compute_bindings.add_output_party(party_names[-1], party_id) print(f"Computing using program {program_id}") print(f"Use secret store_id: {model_store_id} {data_store_id}") - # Perform the computation and return the result + # Create a computation time secret to use + computation_time_secrets = nillion.NadaValues({}) + + # Compute, passing all params including the receipt that shows proof of payment result = await compute( client, + payments_wallet, + payments_client, + program_id, cluster_id, compute_bindings, [model_store_id, data_store_id], - nillion.Secrets({}), + computation_time_secrets, + verbose=True, ) # Sort & rescale the obtained results by the quantization scale @@ -113,13 +152,12 @@ def forward(self, x: torch.tensor) -> torch.tensor: ) ] - print(f"🖥️ The result is {outputs}") + print(f"🖥️ The processed result is {outputs} @ {na.get_log_scale()}-bit precision") expected = my_nn.forward(torch.ones((8,))).detach().numpy().tolist() - print(f"🖥️ VS expected plain-text result {expected}") - return result + + print(f"🖥️ VS expected result {expected}") -# Run the main function if the script is executed directly if __name__ == "__main__": asyncio.run(main()) diff --git a/examples/neural_net/src/my_nn.py b/examples/neural_net/src/my_nn.py index eaaefca..15b1d81 100644 --- a/examples/neural_net/src/my_nn.py +++ b/examples/neural_net/src/my_nn.py @@ -8,7 +8,7 @@ class MyNN(nn.Module): def __init__(self) -> None: """Model is a two layers and an activations""" - super(MyNN, self).__init__() + super().__init__() self.linear_0 = nn.Linear(8, 4) self.linear_1 = nn.Linear(4, 2) self.relu = nn.ReLU() diff --git a/examples/neural_net/tests/neural_net.yaml b/examples/neural_net/tests/neural_net.yaml index bb15100..8bff483 100644 --- a/examples/neural_net/tests/neural_net.yaml +++ b/examples/neural_net/tests/neural_net.yaml @@ -1,125 +1,115 @@ ---- program: neural_net inputs: - secrets: - # We assume all values were originally floats, scaled & rounded by a factor of 2**16 - - # For simplicity's sake, we assume all coefficients and inputs are 2.5 - # 2.5 * 2**16 = 163840 - - my_nn_linear_0.weight_1_2: - SecretInteger: "163840" - my_nn_linear_0.weight_2_4: - SecretInteger: "163840" - my_nn_linear_0.weight_1_7: - SecretInteger: "163840" - my_nn_linear_0.weight_0_4: - SecretInteger: "163840" - my_nn_linear_0.bias_2: - SecretInteger: "163840" - my_nn_linear_1.weight_0_3: - SecretInteger: "163840" - my_nn_linear_0.weight_3_1: - SecretInteger: "163840" - my_nn_linear_0.weight_3_6: - SecretInteger: "163840" - my_nn_linear_0.weight_1_3: - SecretInteger: "163840" - my_nn_linear_0.bias_3: - SecretInteger: "163840" - my_nn_linear_1.weight_1_1: - SecretInteger: "163840" - my_input_0: - SecretInteger: "163840" - my_input_4: - SecretInteger: "163840" - my_nn_linear_1.weight_0_0: - SecretInteger: "163840" - my_nn_linear_0.weight_3_0: - SecretInteger: "163840" - my_nn_linear_1.weight_1_2: - SecretInteger: "163840" - my_nn_linear_0.weight_0_1: - SecretInteger: "163840" - my_nn_linear_0.weight_2_2: - SecretInteger: "163840" - my_input_2: - SecretInteger: "163840" - my_nn_linear_1.weight_1_0: - SecretInteger: "163840" - my_input_1: - SecretInteger: "163840" - my_nn_linear_0.weight_0_0: - SecretInteger: "163840" - my_input_6: - SecretInteger: "163840" - my_nn_linear_0.weight_0_5: - SecretInteger: "163840" - my_nn_linear_1.weight_0_1: - SecretInteger: "163840" - my_nn_linear_0.weight_0_2: - SecretInteger: "163840" - my_nn_linear_0.weight_1_1: - SecretInteger: "163840" - my_nn_linear_0.weight_2_1: - SecretInteger: "163840" - my_nn_linear_0.weight_2_3: - SecretInteger: "163840" - my_nn_linear_0.weight_2_7: - SecretInteger: "163840" - my_nn_linear_1.weight_1_3: - SecretInteger: "163840" - my_nn_linear_0.bias_1: - SecretInteger: "163840" - my_nn_linear_0.weight_1_4: - SecretInteger: "163840" - my_nn_linear_0.weight_2_5: - SecretInteger: "163840" - my_nn_linear_0.weight_0_3: - SecretInteger: "163840" - my_nn_linear_0.weight_3_5: - SecretInteger: "163840" - my_nn_linear_0.weight_3_7: - SecretInteger: "163840" - my_input_5: - SecretInteger: "163840" - my_nn_linear_0.weight_2_0: - SecretInteger: "163840" - my_nn_linear_0.weight_1_0: - SecretInteger: "163840" - my_nn_linear_0.weight_1_6: - SecretInteger: "163840" - my_nn_linear_1.weight_0_2: - SecretInteger: "163840" - my_nn_linear_0.weight_3_4: - SecretInteger: "163840" - my_nn_linear_0.weight_3_3: - SecretInteger: "163840" - my_input_3: - SecretInteger: "163840" - my_nn_linear_0.weight_3_2: - SecretInteger: "163840" - my_nn_linear_1.bias_1: - SecretInteger: "163840" - my_input_7: - SecretInteger: "163840" - my_nn_linear_0.bias_0: - SecretInteger: "163840" - my_nn_linear_0.weight_0_6: - SecretInteger: "163840" - my_nn_linear_0.weight_2_6: - SecretInteger: "163840" - my_nn_linear_0.weight_1_5: - SecretInteger: "163840" - my_nn_linear_1.bias_0: - SecretInteger: "163840" - my_nn_linear_0.weight_0_7: - SecretInteger: "163840" - public_variables: {} + my_nn_linear_0.weight_1_2: + SecretInteger: '163840' + my_nn_linear_0.weight_2_4: + SecretInteger: '163840' + my_nn_linear_0.weight_1_7: + SecretInteger: '163840' + my_nn_linear_0.weight_0_4: + SecretInteger: '163840' + my_nn_linear_0.bias_2: + SecretInteger: '163840' + my_nn_linear_1.weight_0_3: + SecretInteger: '163840' + my_nn_linear_0.weight_3_1: + SecretInteger: '163840' + my_nn_linear_0.weight_3_6: + SecretInteger: '163840' + my_nn_linear_0.weight_1_3: + SecretInteger: '163840' + my_nn_linear_0.bias_3: + SecretInteger: '163840' + my_nn_linear_1.weight_1_1: + SecretInteger: '163840' + my_input_0: + SecretInteger: '163840' + my_input_4: + SecretInteger: '163840' + my_nn_linear_1.weight_0_0: + SecretInteger: '163840' + my_nn_linear_0.weight_3_0: + SecretInteger: '163840' + my_nn_linear_1.weight_1_2: + SecretInteger: '163840' + my_nn_linear_0.weight_0_1: + SecretInteger: '163840' + my_nn_linear_0.weight_2_2: + SecretInteger: '163840' + my_input_2: + SecretInteger: '163840' + my_nn_linear_1.weight_1_0: + SecretInteger: '163840' + my_input_1: + SecretInteger: '163840' + my_nn_linear_0.weight_0_0: + SecretInteger: '163840' + my_input_6: + SecretInteger: '163840' + my_nn_linear_0.weight_0_5: + SecretInteger: '163840' + my_nn_linear_1.weight_0_1: + SecretInteger: '163840' + my_nn_linear_0.weight_0_2: + SecretInteger: '163840' + my_nn_linear_0.weight_1_1: + SecretInteger: '163840' + my_nn_linear_0.weight_2_1: + SecretInteger: '163840' + my_nn_linear_0.weight_2_3: + SecretInteger: '163840' + my_nn_linear_0.weight_2_7: + SecretInteger: '163840' + my_nn_linear_1.weight_1_3: + SecretInteger: '163840' + my_nn_linear_0.bias_1: + SecretInteger: '163840' + my_nn_linear_0.weight_1_4: + SecretInteger: '163840' + my_nn_linear_0.weight_2_5: + SecretInteger: '163840' + my_nn_linear_0.weight_0_3: + SecretInteger: '163840' + my_nn_linear_0.weight_3_5: + SecretInteger: '163840' + my_nn_linear_0.weight_3_7: + SecretInteger: '163840' + my_input_5: + SecretInteger: '163840' + my_nn_linear_0.weight_2_0: + SecretInteger: '163840' + my_nn_linear_0.weight_1_0: + SecretInteger: '163840' + my_nn_linear_0.weight_1_6: + SecretInteger: '163840' + my_nn_linear_1.weight_0_2: + SecretInteger: '163840' + my_nn_linear_0.weight_3_4: + SecretInteger: '163840' + my_nn_linear_0.weight_3_3: + SecretInteger: '163840' + my_input_3: + SecretInteger: '163840' + my_nn_linear_0.weight_3_2: + SecretInteger: '163840' + my_nn_linear_1.bias_1: + SecretInteger: '163840' + my_input_7: + SecretInteger: '163840' + my_nn_linear_0.bias_0: + SecretInteger: '163840' + my_nn_linear_0.weight_0_6: + SecretInteger: '163840' + my_nn_linear_0.weight_2_6: + SecretInteger: '163840' + my_nn_linear_0.weight_1_5: + SecretInteger: '163840' + my_nn_linear_1.bias_0: + SecretInteger: '163840' + my_nn_linear_0.weight_0_7: + SecretInteger: '163840' expected_outputs: - # If you go in and crunch the numbers of this one, the result should be 527.5 - # 527.5 * 2**16 = 34_570_240 my_output_0: - SecretInteger: "34570240" + SecretInteger: '34570240' my_output_1: - SecretInteger: "34570240" + SecretInteger: '34570240' diff --git a/examples/spam_detection/01_model_provider.ipynb b/examples/spam_detection/01_model_provider.ipynb index 039200e..d81bb6e 100644 --- a/examples/spam_detection/01_model_provider.ipynb +++ b/examples/spam_detection/01_model_provider.ipynb @@ -63,13 +63,26 @@ "/Users/mathiasleys/projects/venv/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", " from .autonotebook import tqdm as notebook_tqdm\n" ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "import json\n", "import os\n", + "import sys\n", + "\n", + "sys.path.append(os.path.abspath(os.path.join(os.getcwd(), os.pardir)))\n", + "\n", + "import json\n", "import zipfile\n", - "from typing import Dict\n", "\n", "import joblib\n", "import pandas as pd\n", @@ -84,15 +97,19 @@ "\n", "from config import NUM_FEATS\n", "\n", - "# Using Nada AI model client\n", "from nada_ai.client import SklearnClient\n", "import nada_numpy as na\n", "import py_nillion_client as nillion\n", - "from nillion_python_helpers import (\n", - " create_nillion_client,\n", - " getUserKeyFromFile,\n", - " getNodeKeyFromFile,\n", - ")" + "from nillion_python_helpers import (create_nillion_client,\n", + " create_payments_config)\n", + "from py_nillion_client import NodeKey, UserKey\n", + "from common.utils import store_program, store_secrets\n", + "from cosmpy.aerial.client import LedgerClient\n", + "from cosmpy.aerial.wallet import LocalWallet\n", + "from cosmpy.crypto.keypairs import PrivateKey\n", + "\n", + "home = os.getenv(\"HOME\")\n", + "load_dotenv(f\"{home}/.config/nillion/nillion-devnet.env\")" ] }, { @@ -784,11 +801,12 @@ "outputs": [], "source": [ "cluster_id = os.getenv(\"NILLION_CLUSTER_ID\")\n", - "model_provider_userkey = getUserKeyFromFile(os.getenv(\"NILLION_USERKEY_PATH_PARTY_1\"))\n", - "model_provider_nodekey = getNodeKeyFromFile(os.getenv(\"NILLION_NODEKEY_PATH_PARTY_1\"))\n", - "model_provider_client = create_nillion_client(\n", - " model_provider_userkey, model_provider_nodekey\n", - ")\n", + "grpc_endpoint = os.getenv(\"NILLION_NILCHAIN_GRPC\")\n", + "chain_id = os.getenv(\"NILLION_NILCHAIN_CHAIN_ID\")\n", + "seed = \"my_seed\"\n", + "model_provider_userkey = UserKey.from_seed((seed))\n", + "model_provider_nodekey = NodeKey.from_seed((seed))\n", + "model_provider_client = create_nillion_client(model_provider_userkey, model_provider_nodekey)\n", "model_provider_party_id = model_provider_client.party_id\n", "model_provider_user_id = model_provider_client.user_id" ] @@ -799,67 +817,44 @@ "metadata": {}, "outputs": [], "source": [ - "model_user_userkey = getUserKeyFromFile(os.getenv(\"NILLION_USERKEY_PATH_PARTY_2\"))\n", - "model_user_nodekey = getNodeKeyFromFile(os.getenv(\"NILLION_NODEKEY_PATH_PARTY_2\"))\n", - "model_user_client = create_nillion_client(model_user_userkey, model_user_nodekey)\n", - "model_user_party_id = model_user_client.party_id\n", - "model_user_user_id = create_nillion_client(\n", - " model_user_userkey, model_user_nodekey\n", - ").user_id" + "party_names = [\"Provider\", \"User\"]\n", + "program_name = \"spam_detection\"\n", + "program_mir_path = f\"target/{program_name}.nada.bin\"" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 14, "metadata": {}, + "outputs": [], "source": [ - "## Model Provider flow" + "payments_config = create_payments_config(chain_id, grpc_endpoint)\n", + "payments_client = LedgerClient(payments_config)\n", + "payments_wallet = LocalWallet(\n", + " PrivateKey(bytes.fromhex(os.getenv(\"NILLION_NILCHAIN_PRIVATE_KEY_0\"))),\n", + " prefix=\"nillion\",\n", + ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Upload Nada program to Nillion" + "## Model Provider flow" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "TODO: explain what the Nada program does" + "## Upload Nada program to Nillion" ] }, { - "cell_type": "code", - "execution_count": 14, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "async def store_program(\n", - " *,\n", - " client: nillion.NillionClient,\n", - " cluster_id: str,\n", - " user_id: str,\n", - " nada_program_path: str,\n", - ") -> Dict[str, str]:\n", - " \"\"\"Stores Nada program binary in Nillion network.\n", - "\n", - " Args:\n", - " client (nillion.NillionClient): Client that will upload Nada program.\n", - " cluster_id (str): Nillion cluster ID.\n", - " user_id (str): User ID of user that will upload Nada program.\n", - " nada_program_path (str): Path to Nada program binary.\n", - "\n", - " Returns:\n", - " Dict[str, str]: Resulting `action_id` and `program_id`.\n", - " \"\"\"\n", - " action_id = await client.store_program(cluster_id, \"spam_detection\", nada_program_path)\n", - " program_id = f\"{user_id}/spam_detection\"\n", - "\n", - " return {\n", - " \"action_id\": action_id,\n", - " \"program_id\": program_id,\n", - " }" + "TODO: explain what the Nada program does" ] }, { @@ -871,26 +866,23 @@ "name": "stdout", "output_type": "stream", "text": [ - "✅ Program saved successfully!\n", - "action_id: 4aff9311-ec32-440e-b38d-30af171000cd\n", - "program_id: 33sxVBj3jenx74bGq5eiX3HzwBJS85aGTjutfnfwPwVyJEPhhWr2h1CcYeryqUvvNXKr4ipGQjNFBVbHUDCWXjWE/spam_detection\n" + "Getting quote for operation...\n", + "Submitting payment receipt 2 unil, tx hash 8117B7327C2D1A37D8F5A6DBD8286FC1A34F2B10695F955F66CA564E51CCC1DC\n", + "Stored program. action_id: 3rgqxWd47e171EUwe4RXP9hm45tmoXfuF8fC52S7jcFoQTnU8wPiL7hqWzyV1muak6bEg7iWhudwg4t2pM9XnXcp/spam_detection\n", + "Stored program_id: 3rgqxWd47e171EUwe4RXP9hm45tmoXfuF8fC52S7jcFoQTnU8wPiL7hqWzyV1muak6bEg7iWhudwg4t2pM9XnXcp/spam_detection\n" ] } ], "source": [ - "result_store_program = await store_program(\n", - " client=model_provider_client,\n", - " cluster_id=cluster_id,\n", - " user_id=model_provider_user_id,\n", - " nada_program_path=\"target/spam_detection.nada.bin\",\n", - ")\n", - "\n", - "action_id = result_store_program[\"action_id\"]\n", - "program_id = result_store_program[\"program_id\"]\n", - "\n", - "print(\"✅ Program saved successfully!\")\n", - "print(\"action_id:\", action_id)\n", - "print(\"program_id:\", program_id)" + "program_id = await store_program(\n", + " model_provider_client,\n", + " payments_wallet,\n", + " payments_client,\n", + " model_provider_user_id,\n", + " cluster_id,\n", + " program_name,\n", + " program_mir_path,\n", + ")" ] }, { @@ -914,94 +906,38 @@ "cell_type": "code", "execution_count": 17, "metadata": {}, - "outputs": [], - "source": [ - "async def store_model(\n", - " *,\n", - " model: SklearnClient,\n", - " client: nillion.NillionClient,\n", - " cluster_id: str,\n", - " program_id: str,\n", - " party_id: str,\n", - " model_user_user_id: str,\n", - " model_provider_user_id: str,\n", - ") -> Dict[str, str]:\n", - " \"\"\"Stores model params in Nillion network.\n", - "\n", - " Args:\n", - " model (LogisticRegression): Model object to store in network.\n", - " client (nillion.NillionClient): Nillion client that stores model params.\n", - " cluster_id (str): Nillion cluster ID.\n", - " program_id (str): Program ID of Nada program.\n", - " party_id (str): Party ID of party that will store model params.\n", - " model_user_user_id (str): User ID of user that will get compute permissions.\n", - " model_provider_user_id (str): User ID of user that will provide model params.\n", - "\n", - " Returns:\n", - " Dict[str, str]: Resulting `provider_party_id` and `model_store_id`.\n", - " \"\"\"\n", - "\n", - " secrets = nillion.Secrets(\n", - " model.export_state_as_secrets(\"my_model\", na.SecretRational)\n", - " )\n", - "\n", - " secret_bindings = nillion.ProgramBindings(program_id)\n", - " secret_bindings.add_input_party(\"Provider\", party_id)\n", - "\n", - " permissions = nillion.Permissions.default_for_user(model_provider_user_id)\n", - " compute_permissions = {\n", - " model_user_user_id: {program_id},\n", - " }\n", - " # Give permission to model user to run inference\n", - " permissions.add_compute_permissions(compute_permissions)\n", - "\n", - " store_id = await client.store_secrets(\n", - " cluster_id, secret_bindings, secrets, permissions\n", - " )\n", - "\n", - " return {\n", - " \"provider_party_id\": party_id,\n", - " \"model_store_id\": store_id,\n", - " }" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "✅ Model params uploaded successfully!\n", - "provider_party_id: 12D3KooWFYjK13Ny2W4hEfcZtD5DUvCGP6CJ4H2YnnUCHpZBDKpj\n", - "model_store_id: bf1d62e2-beff-41bd-9c5a-f1acf9e6779d\n" + "Getting quote for operation...\n", + "Quote cost is 48098 unil\n", + "Submitting payment receipt 48098 unil, tx hash 363B761F30F2957BA94CFFDDA1819821EA7C7E4826A0586B38255BB7A739436C\n" ] } ], "source": [ - "result_store_model = await store_model(\n", - " model=model_client,\n", - " client=model_provider_client,\n", - " cluster_id=cluster_id,\n", - " program_id=program_id,\n", - " party_id=model_provider_party_id,\n", - " model_user_user_id=model_user_user_id,\n", - " model_provider_user_id=model_provider_user_id,\n", + "model_secrets = nillion.NadaValues(\n", + " model_client.export_state_as_secrets(\"my_model\", na.SecretRational)\n", ")\n", + "permissions = nillion.Permissions.default_for_user(model_provider_client.user_id)\n", + "permissions.add_compute_permissions({model_provider_client.user_id: {program_id}})\n", "\n", - "provider_party_id = result_store_model[\"provider_party_id\"]\n", - "model_store_id = result_store_model[\"model_store_id\"]\n", - "\n", - "print(\"✅ Model params uploaded successfully!\")\n", - "print(\"provider_party_id:\", provider_party_id)\n", - "print(\"model_store_id:\", model_store_id)" + "model_store_id = await store_secrets(\n", + " model_provider_client,\n", + " payments_wallet,\n", + " payments_client,\n", + " cluster_id,\n", + " model_secrets,\n", + " 1,\n", + " permissions,\n", + ")" ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 18, "metadata": {}, "outputs": [], "source": [ @@ -1014,29 +950,6 @@ " }\n", " json.dump(provider_variables, provider_variables_file)" ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "('40a606cc-70a5-4268-8f72-f7f75c388146', )" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "result_tuple = await model_provider_client.retrieve_secret(\n", - " cluster_id, model_store_id, \"my_model_coef_0_123\"\n", - ")\n", - "result_tuple" - ] } ], "metadata": { diff --git a/examples/spam_detection/02_model_inference.ipynb b/examples/spam_detection/02_model_inference.ipynb index 30e031a..137a6e3 100644 --- a/examples/spam_detection/02_model_inference.ipynb +++ b/examples/spam_detection/02_model_inference.ipynb @@ -32,14 +32,30 @@ "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "from typing import Dict, List\n", + "import os\n", + "import sys\n", + "\n", + "sys.path.append(os.path.abspath(os.path.join(os.getcwd(), os.pardir)))\n", + "\n", + "import math\n", "\n", "import json\n", - "import os\n", "import joblib\n", "\n", + "from common.utils import compute, store_secret_array\n", "\n", "from dotenv import load_dotenv\n", "import numpy as np\n", @@ -49,13 +65,16 @@ "import nada_numpy as na\n", "import nada_numpy.client as na_client\n", "import py_nillion_client as nillion\n", - "from nillion_python_helpers import (\n", - " create_nillion_client,\n", - " getUserKeyFromFile,\n", - " getNodeKeyFromFile,\n", - ")\n", + "from cosmpy.aerial.client import LedgerClient\n", + "from cosmpy.aerial.wallet import LocalWallet\n", + "from cosmpy.crypto.keypairs import PrivateKey\n", + "from py_nillion_client import NodeKey, UserKey\n", + "from nillion_python_helpers import (create_nillion_client,\n", + " create_payments_config)\n", "\n", - "from config import NUM_FEATS" + "\n", + "home = os.getenv(\"HOME\")\n", + "load_dotenv(f\"{home}/.config/nillion/nillion-devnet.env\")" ] }, { @@ -107,8 +126,11 @@ "outputs": [], "source": [ "cluster_id = os.getenv(\"NILLION_CLUSTER_ID\")\n", - "model_user_userkey = getUserKeyFromFile(os.getenv(\"NILLION_USERKEY_PATH_PARTY_2\"))\n", - "model_user_nodekey = getNodeKeyFromFile(os.getenv(\"NILLION_NODEKEY_PATH_PARTY_2\"))\n", + "grpc_endpoint = os.getenv(\"NILLION_NILCHAIN_GRPC\")\n", + "chain_id = os.getenv(\"NILLION_NILCHAIN_CHAIN_ID\")\n", + "seed = \"my_seed\"\n", + "model_user_userkey = UserKey.from_seed((seed))\n", + "model_user_nodekey = NodeKey.from_seed((seed))\n", "model_user_client = create_nillion_client(model_user_userkey, model_user_nodekey)\n", "model_user_party_id = model_user_client.party_id\n", "model_user_user_id = model_user_client.user_id" @@ -118,14 +140,28 @@ "cell_type": "code", "execution_count": 5, "metadata": {}, + "outputs": [], + "source": [ + "payments_config = create_payments_config(chain_id, grpc_endpoint)\n", + "payments_client = LedgerClient(payments_config)\n", + "payments_wallet = LocalWallet(\n", + " PrivateKey(bytes.fromhex(os.getenv(\"NILLION_NILCHAIN_PRIVATE_KEY_0\"))),\n", + " prefix=\"nillion\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Program ID: 33sxVBj3jenx74bGq5eiX3HzwBJS85aGTjutfnfwPwVyJEPhhWr2h1CcYeryqUvvNXKr4ipGQjNFBVbHUDCWXjWE/spam_detection\n", - "Model Store ID: bf1d62e2-beff-41bd-9c5a-f1acf9e6779d\n", - "Model Provider Party ID: 12D3KooWFYjK13Ny2W4hEfcZtD5DUvCGP6CJ4H2YnnUCHpZBDKpj\n" + "Program ID: 3rgqxWd47e171EUwe4RXP9hm45tmoXfuF8fC52S7jcFoQTnU8wPiL7hqWzyV1muak6bEg7iWhudwg4t2pM9XnXcp/spam_detection\n", + "Model Store ID: 1a67209f-359e-46fa-9451-6dd559c27ca1\n", + "Model Provider Party ID: 12D3KooWJHrXiK2JTCjJxwCCktJPSYsUsz2WHEBSB5iZtqGiZ8Qm\n" ] } ], @@ -159,7 +195,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -168,7 +204,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -180,7 +216,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -194,52 +230,6 @@ "### Send features to Nillion" ] }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "async def store_features(\n", - " *,\n", - " client: nillion.NillionClient,\n", - " cluster_id: str,\n", - " program_id: str,\n", - " party_id: str,\n", - " user_id: str,\n", - " features: np.ndarray\n", - ") -> Dict[str, str]:\n", - " \"\"\"Stores text features in Nillion network.\n", - "\n", - " Args:\n", - " client (nillion.NillionClient): Nillion client that stores features.\n", - " cluster_id (str): Nillion cluster ID.\n", - " program_id (str): Program ID of Nada program.\n", - " party_id (str): Party ID of party that will store text features.\n", - " user_id (str): User ID of user that will get compute permissions.\n", - " features (List[float]): List of text features.\n", - " precision (int): Scaling factor to convert float to ints.\n", - "\n", - " Returns:\n", - " Dict[str, str]: Resulting `model_user_party_id` and `features_store_id`.\n", - " \"\"\"\n", - "\n", - " secrets = nillion.Secrets(na_client.array(features, \"my_input\", na.SecretRational))\n", - "\n", - " print(secrets)\n", - " secret_bindings = nillion.ProgramBindings(program_id)\n", - " secret_bindings.add_input_party(\"User\", party_id)\n", - "\n", - " features_store_id = await client.store_secrets(\n", - " cluster_id, secret_bindings, secrets, None\n", - " )\n", - "\n", - " return {\n", - " \"model_user_user_id\": user_id,\n", - " \"features_store_id\": features_store_id,\n", - " }" - ] - }, { "cell_type": "code", "execution_count": 10, @@ -249,29 +239,27 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", - "✅ Text features uploaded successfully!\n", - "model_user_user_id: 346jE91YmBjhSdvVSKCSpBxAY1kj5brpnCtWutLWMvXj8sF2iBR7fnmm4fjAGj7uPmHtb7CBQRjV5Q4H1KzepDCL\n", - "features_store_id: 10c7d969-f60f-43fe-8795-2335bc9be522\n" + "Getting quote for operation...\n", + "Quote cost is 48002 unil\n", + "Submitting payment receipt 48002 unil, tx hash ADC46091FE92101AC9740304E5C2DF883C90ACF66EB155EAEFE23D4438479A4A\n" ] } ], "source": [ - "result_store_features = await store_features(\n", - " client=model_user_client,\n", - " cluster_id=cluster_id,\n", - " program_id=program_id,\n", - " party_id=model_user_party_id,\n", - " user_id=model_user_user_id,\n", - " features=features,\n", - ")\n", + "permissions = nillion.Permissions.default_for_user(model_user_client.user_id)\n", + "permissions.add_compute_permissions({model_user_client.user_id: {program_id}})\n", "\n", - "model_user_user_id = result_store_features[\"model_user_user_id\"]\n", - "features_store_id = result_store_features[\"features_store_id\"]\n", - "\n", - "print(\"✅ Text features uploaded successfully!\")\n", - "print(\"model_user_user_id:\", model_user_user_id)\n", - "print(\"features_store_id:\", features_store_id)" + "images_store_id = await store_secret_array(\n", + " model_user_client,\n", + " payments_wallet,\n", + " payments_client,\n", + " cluster_id,\n", + " features,\n", + " \"my_input\",\n", + " na.SecretRational,\n", + " 1,\n", + " permissions,\n", + ")" ] }, { @@ -287,60 +275,11 @@ "metadata": {}, "outputs": [], "source": [ - "async def run_inference(\n", - " *,\n", - " client: nillion.NillionClient,\n", - " cluster_id: str,\n", - " program_id: str,\n", - " model_user_party_id: str,\n", - " model_provider_party_id: str,\n", - " model_store_id: str,\n", - " features_store_id: str,\n", - ") -> Dict[str, str | float]:\n", - " \"\"\"Runs blind inference on the Nillion network by executing the Nada program on the uploaded data.\n", - "\n", - " Args:\n", - " client (nillion.NillionClient): Nillion client that runs inference.\n", - " cluster_id (str): Nillion cluster ID.\n", - " program_id (str): Program ID of Nada program.\n", - " model_user_party_id (str): Party ID of party that will run inference.\n", - " model_user_party_id (str): Party ID of party that will provide model params.\n", - " model_store_id (str): Store ID that points to the model params in the Nillion network.\n", - " features_store_id (str): Store ID that points to the text features in the Nillion network.\n", - " precision (int): Scaling factor to convert float to ints.s\n", - "\n", - " Returns:\n", - " Dict[str, str | float]: Resulting `compute_id` and `logit`.\n", - " \"\"\"\n", - " compute_bindings = nillion.ProgramBindings(program_id)\n", - " compute_bindings.add_input_party(\"User\", model_user_party_id)\n", - " compute_bindings.add_input_party(\"Provider\", model_provider_party_id)\n", - " compute_bindings.add_output_party(\"User\", model_user_party_id)\n", + "compute_bindings = nillion.ProgramBindings(program_id)\n", "\n", - " _ = await client.compute(\n", - " cluster_id,\n", - " compute_bindings,\n", - " [features_store_id, model_store_id],\n", - " nillion.Secrets({}),\n", - " nillion.PublicVariables({}),\n", - " )\n", - "\n", - " while True:\n", - " compute_event = await client.next_compute_event()\n", - " if isinstance(compute_event, nillion.ComputeFinishedEvent):\n", - " inference_result = compute_event.result.value\n", - " break\n", - "\n", - " sigmoid = lambda x: 1 / (1 + np.exp(-x))\n", - "\n", - " quantized_logit = inference_result[\"logit_0\"]\n", - " logit = quantized_logit / (2 ** na.get_log_scale())\n", - " output_probability = sigmoid(logit)\n", - " return {\n", - " \"compute_id\": compute_event.uuid,\n", - " \"logit\": logit,\n", - " \"output_probability\": output_probability,\n", - " }" + "compute_bindings.add_input_party(\"Provider\", model_provider_party_id)\n", + "compute_bindings.add_input_party(\"User\", model_user_party_id)\n", + "compute_bindings.add_output_party(\"User\", model_user_party_id)" ] }, { @@ -352,33 +291,38 @@ "name": "stdout", "output_type": "stream", "text": [ - "✅ Inference ran successfully!\n", - "compute_id: dc230bb3-1a27-41c0-9236-3ee0e11f5c1a\n", - "logit: 2.4093170166015625\n", - "Probability of spam in Nillion: 91.753502%\n" + "Getting quote for operation...\n", + "Quote cost is 1004 unil\n", + "Submitting payment receipt 1004 unil, tx hash 3B0F0A512E3459077F4B0C76C51573FE6E0123695BA5350C88C82B74D4ED7799\n", + "✅ Compute complete for compute_id d256e8bb-b85a-428f-b168-6359cfaf3ec8\n", + "🖥️ The result is {'logit_0': 157897}\n", + "Computed logit is 2.4093170166015625\n", + "Which corresponds to probability 0.9175350190040187\n" ] } ], "source": [ - "result_inference = await run_inference(\n", - " client=model_user_client,\n", - " cluster_id=cluster_id,\n", - " program_id=program_id,\n", - " model_user_party_id=model_user_party_id,\n", - " model_provider_party_id=model_provider_party_id,\n", - " model_store_id=model_store_id,\n", - " features_store_id=features_store_id,\n", + "result = await compute(\n", + " model_user_client,\n", + " payments_wallet,\n", + " payments_client,\n", + " program_id,\n", + " cluster_id,\n", + " compute_bindings,\n", + " [model_store_id, images_store_id],\n", + " nillion.NadaValues({}),\n", + " verbose=True,\n", ")\n", "\n", - "compute_id = result_inference[\"compute_id\"]\n", - "logit = result_inference[\"logit\"]\n", - "output_probability = result_inference[\"output_probability\"]\n", + "logit = na_client.float_from_rational(result[\"logit_0\"])\n", + "print(\"Computed logit is\", logit)\n", "\n", - "print(\"✅ Inference ran successfully!\")\n", - "print(\"compute_id:\", compute_id)\n", - "print(\"logit:\", logit)\n", + "def sigmoid(x):\n", + " return 1 / (1 + math.exp(-x))\n", "\n", - "print(\"Probability of spam in Nillion: {:.6f}%\".format(output_probability * 100))" + "output_probability = sigmoid(logit)\n", + "\n", + "print(\"Which corresponds to probability\", output_probability)" ] }, { @@ -425,7 +369,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Logit in plain text: 2.4080795630742755\n" + "Logit in plain text: 2.408079563074276\n" ] } ], diff --git a/examples/spam_detection/tests/spam_detection.yaml b/examples/spam_detection/tests/spam_detection.yaml index ede8336..84f417c 100644 --- a/examples/spam_detection/tests/spam_detection.yaml +++ b/examples/spam_detection/tests/spam_detection.yaml @@ -1,2010 +1,2007 @@ ---- program: spam_detection inputs: - secrets: - my_input_81: - SecretInteger: "3" - my_input_417: - SecretInteger: "3" - my_input_168: - SecretInteger: "3" - my_input_75: - SecretInteger: "3" - my_model_coef_0_81: - SecretInteger: "3" - my_model_coef_0_194: - SecretInteger: "3" - my_model_coef_0_210: - SecretInteger: "3" - my_model_coef_0_108: - SecretInteger: "3" - my_model_coef_0_476: - SecretInteger: "3" - my_model_coef_0_182: - SecretInteger: "3" - my_input_236: - SecretInteger: "3" - my_input_13: - SecretInteger: "3" - my_model_coef_0_229: - SecretInteger: "3" - my_model_coef_0_147: - SecretInteger: "3" - my_input_468: - SecretInteger: "3" - my_model_coef_0_350: - SecretInteger: "3" - my_input_252: - SecretInteger: "3" - my_input_34: - SecretInteger: "3" - my_model_coef_0_212: - SecretInteger: "3" - my_input_330: - SecretInteger: "3" - my_input_240: - SecretInteger: "3" - my_input_133: - SecretInteger: "3" - my_model_coef_0_166: - SecretInteger: "3" - my_model_coef_0_174: - SecretInteger: "3" - my_model_coef_0_425: - SecretInteger: "3" - my_input_452: - SecretInteger: "3" - my_model_coef_0_423: - SecretInteger: "3" - my_model_coef_0_291: - SecretInteger: "3" - my_model_coef_0_359: - SecretInteger: "3" - my_model_coef_0_143: - SecretInteger: "3" - my_model_coef_0_94: - SecretInteger: "3" - my_model_coef_0_177: - SecretInteger: "3" - my_input_217: - SecretInteger: "3" - my_model_coef_0_80: - SecretInteger: "3" - my_input_336: - SecretInteger: "3" - my_input_472: - SecretInteger: "3" - my_model_coef_0_232: - SecretInteger: "3" - my_model_coef_0_274: - SecretInteger: "3" - my_model_coef_0_256: - SecretInteger: "3" - my_model_coef_0_368: - SecretInteger: "3" - my_input_47: - SecretInteger: "3" - my_input_79: - SecretInteger: "3" - my_input_409: - SecretInteger: "3" - my_model_coef_0_42: - SecretInteger: "3" - my_model_coef_0_262: - SecretInteger: "3" - my_model_coef_0_29: - SecretInteger: "3" - my_input_48: - SecretInteger: "3" - my_input_100: - SecretInteger: "3" - my_model_coef_0_483: - SecretInteger: "3" - my_input_372: - SecretInteger: "3" - my_input_276: - SecretInteger: "3" - my_input_221: - SecretInteger: "3" - my_input_349: - SecretInteger: "3" - my_model_coef_0_25: - SecretInteger: "3" - my_input_422: - SecretInteger: "3" - my_model_coef_0_379: - SecretInteger: "3" - my_input_329: - SecretInteger: "3" - my_input_482: - SecretInteger: "3" - my_model_coef_0_234: - SecretInteger: "3" - my_input_237: - SecretInteger: "3" - my_input_435: - SecretInteger: "3" - my_input_260: - SecretInteger: "3" - my_model_coef_0_400: - SecretInteger: "3" - my_model_coef_0_472: - SecretInteger: "3" - my_model_coef_0_96: - SecretInteger: "3" - my_model_coef_0_279: - SecretInteger: "3" - my_input_230: - SecretInteger: "3" - my_input_313: - SecretInteger: "3" - my_input_444: - SecretInteger: "3" - my_input_174: - SecretInteger: "3" - my_model_coef_0_236: - SecretInteger: "3" - my_input_122: - SecretInteger: "3" - my_input_461: - SecretInteger: "3" - my_input_1: - SecretInteger: "3" - my_input_314: - SecretInteger: "3" - my_input_325: - SecretInteger: "3" - my_model_coef_0_243: - SecretInteger: "3" - my_model_coef_0_383: - SecretInteger: "3" - my_input_3: - SecretInteger: "3" - my_input_195: - SecretInteger: "3" - my_input_473: - SecretInteger: "3" - my_input_464: - SecretInteger: "3" - my_input_300: - SecretInteger: "3" - my_model_coef_0_436: - SecretInteger: "3" - my_input_243: - SecretInteger: "3" - my_model_coef_0_192: - SecretInteger: "3" - my_model_coef_0_421: - SecretInteger: "3" - my_input_62: - SecretInteger: "3" - my_input_255: - SecretInteger: "3" - my_input_382: - SecretInteger: "3" - my_input_247: - SecretInteger: "3" - my_model_coef_0_116: - SecretInteger: "3" - my_input_242: - SecretInteger: "3" - my_model_coef_0_294: - SecretInteger: "3" - my_model_coef_0_59: - SecretInteger: "3" - my_model_coef_0_185: - SecretInteger: "3" - my_model_coef_0_390: - SecretInteger: "3" - my_model_coef_0_202: - SecretInteger: "3" - my_model_coef_0_304: - SecretInteger: "3" - my_model_coef_0_248: - SecretInteger: "3" - my_input_69: - SecretInteger: "3" - my_input_206: - SecretInteger: "3" - my_input_485: - SecretInteger: "3" - my_input_118: - SecretInteger: "3" - my_input_307: - SecretInteger: "3" - my_input_289: - SecretInteger: "3" - my_input_45: - SecretInteger: "3" - my_input_164: - SecretInteger: "3" - my_input_181: - SecretInteger: "3" - my_input_466: - SecretInteger: "3" - my_input_84: - SecretInteger: "3" - my_model_coef_0_208: - SecretInteger: "3" - my_input_395: - SecretInteger: "3" - my_input_127: - SecretInteger: "3" - my_input_29: - SecretInteger: "3" - my_input_144: - SecretInteger: "3" - my_input_326: - SecretInteger: "3" - my_input_495: - SecretInteger: "3" - my_input_191: - SecretInteger: "3" - my_model_coef_0_67: - SecretInteger: "3" - my_model_coef_0_394: - SecretInteger: "3" - my_input_319: - SecretInteger: "3" - my_input_126: - SecretInteger: "3" - my_input_431: - SecretInteger: "3" - my_model_coef_0_388: - SecretInteger: "3" - my_model_coef_0_227: - SecretInteger: "3" - my_input_15: - SecretInteger: "3" - my_input_128: - SecretInteger: "3" - my_input_445: - SecretInteger: "3" - my_input_59: - SecretInteger: "3" - my_input_404: - SecretInteger: "3" - my_input_158: - SecretInteger: "3" - my_model_coef_0_470: - SecretInteger: "3" - my_model_coef_0_137: - SecretInteger: "3" - my_model_coef_0_33: - SecretInteger: "3" - my_input_183: - SecretInteger: "3" - my_model_coef_0_395: - SecretInteger: "3" - my_input_323: - SecretInteger: "3" - my_input_327: - SecretInteger: "3" - my_input_113: - SecretInteger: "3" - my_model_coef_0_498: - SecretInteger: "3" - my_input_385: - SecretInteger: "3" - my_input_362: - SecretInteger: "3" - my_input_92: - SecretInteger: "3" - my_model_coef_0_333: - SecretInteger: "3" - my_input_49: - SecretInteger: "3" - my_model_coef_0_241: - SecretInteger: "3" - my_model_coef_0_361: - SecretInteger: "3" - my_model_coef_0_381: - SecretInteger: "3" - my_model_coef_0_409: - SecretInteger: "3" - my_input_72: - SecretInteger: "3" - my_input_123: - SecretInteger: "3" - my_model_coef_0_64: - SecretInteger: "3" - my_input_170: - SecretInteger: "3" - my_input_328: - SecretInteger: "3" - my_input_250: - SecretInteger: "3" - my_input_341: - SecretInteger: "3" - my_input_303: - SecretInteger: "3" - my_input_426: - SecretInteger: "3" - my_model_coef_0_131: - SecretInteger: "3" - my_input_420: - SecretInteger: "3" - my_model_coef_0_153: - SecretInteger: "3" - my_model_coef_0_403: - SecretInteger: "3" - my_input_67: - SecretInteger: "3" - my_input_321: - SecretInteger: "3" - my_model_coef_0_112: - SecretInteger: "3" - my_input_486: - SecretInteger: "3" - my_model_coef_0_6: - SecretInteger: "3" - my_model_coef_0_357: - SecretInteger: "3" - my_input_399: - SecretInteger: "3" - my_input_432: - SecretInteger: "3" - my_input_8: - SecretInteger: "3" - my_model_coef_0_485: - SecretInteger: "3" - my_input_407: - SecretInteger: "3" - my_input_22: - SecretInteger: "3" - my_model_coef_0_306: - SecretInteger: "3" - my_model_coef_0_163: - SecretInteger: "3" - my_input_196: - SecretInteger: "3" - my_input_364: - SecretInteger: "3" - my_model_coef_0_341: - SecretInteger: "3" - my_input_350: - SecretInteger: "3" - my_input_377: - SecretInteger: "3" - my_input_454: - SecretInteger: "3" - my_input_458: - SecretInteger: "3" - my_model_coef_0_167: - SecretInteger: "3" - my_model_coef_0_430: - SecretInteger: "3" - my_model_coef_0_129: - SecretInteger: "3" - my_input_400: - SecretInteger: "3" - my_model_coef_0_41: - SecretInteger: "3" - my_input_265: - SecretInteger: "3" - my_model_coef_0_134: - SecretInteger: "3" - my_model_coef_0_82: - SecretInteger: "3" - my_model_coef_0_56: - SecretInteger: "3" - my_input_38: - SecretInteger: "3" - my_input_103: - SecretInteger: "3" - my_model_coef_0_0: - SecretInteger: "3" - my_model_coef_0_260: - SecretInteger: "3" - my_model_coef_0_362: - SecretInteger: "3" - my_input_443: - SecretInteger: "3" - my_input_306: - SecretInteger: "3" - my_model_coef_0_441: - SecretInteger: "3" - my_model_coef_0_209: - SecretInteger: "3" - my_model_coef_0_141: - SecretInteger: "3" - my_model_coef_0_217: - SecretInteger: "3" - my_model_coef_0_4: - SecretInteger: "3" - my_model_coef_0_161: - SecretInteger: "3" - my_model_coef_0_481: - SecretInteger: "3" - my_input_119: - SecretInteger: "3" - my_model_coef_0_204: - SecretInteger: "3" - my_model_intercept_0: - SecretInteger: "3" - my_input_177: - SecretInteger: "3" - my_input_86: - SecretInteger: "3" - my_model_coef_0_424: - SecretInteger: "3" - my_model_coef_0_355: - SecretInteger: "3" - my_model_coef_0_55: - SecretInteger: "3" - my_input_231: - SecretInteger: "3" - my_input_74: - SecretInteger: "3" - my_model_coef_0_432: - SecretInteger: "3" - my_input_455: - SecretInteger: "3" - my_model_coef_0_17: - SecretInteger: "3" - my_model_coef_0_119: - SecretInteger: "3" - my_input_156: - SecretInteger: "3" - my_input_190: - SecretInteger: "3" - my_input_381: - SecretInteger: "3" - my_input_421: - SecretInteger: "3" - my_model_coef_0_447: - SecretInteger: "3" - my_input_180: - SecretInteger: "3" - my_input_489: - SecretInteger: "3" - my_model_coef_0_363: - SecretInteger: "3" - my_model_coef_0_440: - SecretInteger: "3" - my_input_264: - SecretInteger: "3" - my_model_coef_0_101: - SecretInteger: "3" - my_model_coef_0_69: - SecretInteger: "3" - my_model_coef_0_246: - SecretInteger: "3" - my_model_coef_0_135: - SecretInteger: "3" - my_input_499: - SecretInteger: "3" - my_model_coef_0_346: - SecretInteger: "3" - my_input_412: - SecretInteger: "3" - my_input_441: - SecretInteger: "3" - my_model_coef_0_272: - SecretInteger: "3" - my_input_32: - SecretInteger: "3" - my_model_coef_0_251: - SecretInteger: "3" - my_input_16: - SecretInteger: "3" - my_model_coef_0_254: - SecretInteger: "3" - my_input_7: - SecretInteger: "3" - my_input_384: - SecretInteger: "3" - my_model_coef_0_392: - SecretInteger: "3" - my_model_coef_0_62: - SecretInteger: "3" - my_input_90: - SecretInteger: "3" - my_input_194: - SecretInteger: "3" - my_model_coef_0_468: - SecretInteger: "3" - my_input_366: - SecretInteger: "3" - my_input_405: - SecretInteger: "3" - my_model_coef_0_13: - SecretInteger: "3" - my_model_coef_0_159: - SecretInteger: "3" - my_input_424: - SecretInteger: "3" - my_input_254: - SecretInteger: "3" - my_model_coef_0_428: - SecretInteger: "3" - my_model_coef_0_21: - SecretInteger: "3" - my_input_226: - SecretInteger: "3" - my_model_coef_0_258: - SecretInteger: "3" - my_input_310: - SecretInteger: "3" - my_model_coef_0_426: - SecretInteger: "3" - my_model_coef_0_477: - SecretInteger: "3" - my_model_coef_0_24: - SecretInteger: "3" - my_model_coef_0_85: - SecretInteger: "3" - my_model_coef_0_37: - SecretInteger: "3" - my_model_coef_0_145: - SecretInteger: "3" - my_input_160: - SecretInteger: "3" - my_input_256: - SecretInteger: "3" - my_model_coef_0_91: - SecretInteger: "3" - my_model_coef_0_399: - SecretInteger: "3" - my_model_coef_0_309: - SecretInteger: "3" - my_model_coef_0_9: - SecretInteger: "3" - my_model_coef_0_367: - SecretInteger: "3" - my_model_coef_0_326: - SecretInteger: "3" - my_model_coef_0_329: - SecretInteger: "3" - my_input_296: - SecretInteger: "3" - my_input_484: - SecretInteger: "3" - my_input_200: - SecretInteger: "3" - my_model_coef_0_83: - SecretInteger: "3" - my_input_462: - SecretInteger: "3" - my_input_277: - SecretInteger: "3" - my_model_coef_0_238: - SecretInteger: "3" - my_model_coef_0_444: - SecretInteger: "3" - my_model_coef_0_358: - SecretInteger: "3" - my_model_coef_0_158: - SecretInteger: "3" - my_input_390: - SecretInteger: "3" - my_model_coef_0_307: - SecretInteger: "3" - my_model_coef_0_493: - SecretInteger: "3" - my_model_coef_0_323: - SecretInteger: "3" - my_input_374: - SecretInteger: "3" - my_input_469: - SecretInteger: "3" - my_model_coef_0_488: - SecretInteger: "3" - my_model_coef_0_213: - SecretInteger: "3" - my_input_56: - SecretInteger: "3" - my_model_coef_0_79: - SecretInteger: "3" - my_input_159: - SecretInteger: "3" - my_model_coef_0_429: - SecretInteger: "3" - my_input_293: - SecretInteger: "3" - my_input_167: - SecretInteger: "3" - my_input_375: - SecretInteger: "3" - my_model_coef_0_136: - SecretInteger: "3" - my_input_43: - SecretInteger: "3" - my_model_coef_0_157: - SecretInteger: "3" - my_input_24: - SecretInteger: "3" - my_input_5: - SecretInteger: "3" - my_input_450: - SecretInteger: "3" - my_input_42: - SecretInteger: "3" - my_model_coef_0_76: - SecretInteger: "3" - my_model_coef_0_464: - SecretInteger: "3" - my_input_19: - SecretInteger: "3" - my_model_coef_0_198: - SecretInteger: "3" - my_input_249: - SecretInteger: "3" - my_input_493: - SecretInteger: "3" - my_model_coef_0_288: - SecretInteger: "3" - my_input_302: - SecretInteger: "3" - my_model_coef_0_150: - SecretInteger: "3" - my_input_204: - SecretInteger: "3" - my_input_60: - SecretInteger: "3" - my_input_220: - SecretInteger: "3" - my_model_coef_0_280: - SecretInteger: "3" - my_model_coef_0_494: - SecretInteger: "3" - my_model_coef_0_16: - SecretInteger: "3" - my_input_322: - SecretInteger: "3" - my_model_coef_0_268: - SecretInteger: "3" - my_model_coef_0_489: - SecretInteger: "3" - my_model_coef_0_442: - SecretInteger: "3" - my_model_coef_0_374: - SecretInteger: "3" - my_model_coef_0_478: - SecretInteger: "3" - my_input_298: - SecretInteger: "3" - my_input_483: - SecretInteger: "3" - my_input_267: - SecretInteger: "3" - my_model_coef_0_73: - SecretInteger: "3" - my_input_368: - SecretInteger: "3" - my_input_207: - SecretInteger: "3" - my_model_coef_0_220: - SecretInteger: "3" - my_input_318: - SecretInteger: "3" - my_model_coef_0_492: - SecretInteger: "3" - my_input_161: - SecretInteger: "3" - my_model_coef_0_180: - SecretInteger: "3" - my_model_coef_0_371: - SecretInteger: "3" - my_model_coef_0_87: - SecretInteger: "3" - my_model_coef_0_90: - SecretInteger: "3" - my_model_coef_0_148: - SecretInteger: "3" - my_model_coef_0_342: - SecretInteger: "3" - my_model_coef_0_43: - SecretInteger: "3" - my_input_73: - SecretInteger: "3" - my_input_339: - SecretInteger: "3" - my_model_coef_0_179: - SecretInteger: "3" - my_input_338: - SecretInteger: "3" - my_input_434: - SecretInteger: "3" - my_input_475: - SecretInteger: "3" - my_model_coef_0_107: - SecretInteger: "3" - my_model_coef_0_211: - SecretInteger: "3" - my_model_coef_0_473: - SecretInteger: "3" - my_input_274: - SecretInteger: "3" - my_input_447: - SecretInteger: "3" - my_input_175: - SecretInteger: "3" - my_input_55: - SecretInteger: "3" - my_model_coef_0_171: - SecretInteger: "3" - my_input_392: - SecretInteger: "3" - my_model_coef_0_216: - SecretInteger: "3" - my_input_145: - SecretInteger: "3" - my_input_227: - SecretInteger: "3" - my_model_coef_0_226: - SecretInteger: "3" - my_model_coef_0_31: - SecretInteger: "3" - my_input_98: - SecretInteger: "3" - my_input_106: - SecretInteger: "3" - my_input_216: - SecretInteger: "3" - my_model_coef_0_126: - SecretInteger: "3" - my_input_134: - SecretInteger: "3" - my_model_coef_0_102: - SecretInteger: "3" - my_input_324: - SecretInteger: "3" - my_input_162: - SecretInteger: "3" - my_input_121: - SecretInteger: "3" - my_input_71: - SecretInteger: "3" - my_input_491: - SecretInteger: "3" - my_model_coef_0_58: - SecretInteger: "3" - my_input_269: - SecretInteger: "3" - my_input_383: - SecretInteger: "3" - my_model_coef_0_303: - SecretInteger: "3" - my_model_coef_0_120: - SecretInteger: "3" - my_input_150: - SecretInteger: "3" - my_model_coef_0_32: - SecretInteger: "3" - my_model_coef_0_100: - SecretInteger: "3" - my_input_52: - SecretInteger: "3" - my_model_coef_0_397: - SecretInteger: "3" - my_model_coef_0_181: - SecretInteger: "3" - my_input_287: - SecretInteger: "3" - my_model_coef_0_263: - SecretInteger: "3" - my_model_coef_0_360: - SecretInteger: "3" - my_input_110: - SecretInteger: "3" - my_input_288: - SecretInteger: "3" - my_input_305: - SecretInteger: "3" - my_input_453: - SecretInteger: "3" - my_input_232: - SecretInteger: "3" - my_input_474: - SecretInteger: "3" - my_model_coef_0_348: - SecretInteger: "3" - my_model_coef_0_452: - SecretInteger: "3" - my_model_coef_0_352: - SecretInteger: "3" - my_input_4: - SecretInteger: "3" - my_input_31: - SecretInteger: "3" - my_model_coef_0_281: - SecretInteger: "3" - my_input_365: - SecretInteger: "3" - my_model_coef_0_103: - SecretInteger: "3" - my_model_coef_0_175: - SecretInteger: "3" - my_model_coef_0_138: - SecretInteger: "3" - my_model_coef_0_40: - SecretInteger: "3" - my_model_coef_0_230: - SecretInteger: "3" - my_model_coef_0_193: - SecretInteger: "3" - my_model_coef_0_200: - SecretInteger: "3" - my_input_89: - SecretInteger: "3" - my_model_coef_0_427: - SecretInteger: "3" - my_input_480: - SecretInteger: "3" - my_input_253: - SecretInteger: "3" - my_model_coef_0_11: - SecretInteger: "3" - my_model_coef_0_12: - SecretInteger: "3" - my_model_coef_0_113: - SecretInteger: "3" - my_model_coef_0_438: - SecretInteger: "3" - my_model_coef_0_247: - SecretInteger: "3" - my_input_284: - SecretInteger: "3" - my_input_137: - SecretInteger: "3" - my_model_coef_0_283: - SecretInteger: "3" - my_model_coef_0_420: - SecretInteger: "3" - my_input_176: - SecretInteger: "3" - my_model_coef_0_223: - SecretInteger: "3" - my_model_coef_0_435: - SecretInteger: "3" - my_input_244: - SecretInteger: "3" - my_input_477: - SecretInteger: "3" - my_input_471: - SecretInteger: "3" - my_input_114: - SecretInteger: "3" - my_input_233: - SecretInteger: "3" - my_model_coef_0_151: - SecretInteger: "3" - my_model_coef_0_253: - SecretInteger: "3" - my_model_coef_0_264: - SecretInteger: "3" - my_model_coef_0_142: - SecretInteger: "3" - my_model_coef_0_391: - SecretInteger: "3" - my_model_coef_0_337: - SecretInteger: "3" - my_input_369: - SecretInteger: "3" - my_model_coef_0_284: - SecretInteger: "3" - my_model_coef_0_314: - SecretInteger: "3" - my_model_coef_0_28: - SecretInteger: "3" - my_model_coef_0_334: - SecretInteger: "3" - my_input_225: - SecretInteger: "3" - my_input_358: - SecretInteger: "3" - my_input_460: - SecretInteger: "3" - my_model_coef_0_45: - SecretInteger: "3" - my_model_coef_0_389: - SecretInteger: "3" - my_input_406: - SecretInteger: "3" - my_input_487: - SecretInteger: "3" - my_model_coef_0_114: - SecretInteger: "3" - my_model_coef_0_463: - SecretInteger: "3" - my_model_coef_0_110: - SecretInteger: "3" - my_input_299: - SecretInteger: "3" - my_input_488: - SecretInteger: "3" - my_input_352: - SecretInteger: "3" - my_model_coef_0_313: - SecretInteger: "3" - my_model_coef_0_376: - SecretInteger: "3" - my_model_coef_0_164: - SecretInteger: "3" - my_model_coef_0_414: - SecretInteger: "3" - my_model_coef_0_22: - SecretInteger: "3" - my_input_348: - SecretInteger: "3" - my_input_315: - SecretInteger: "3" - my_input_189: - SecretInteger: "3" - my_input_347: - SecretInteger: "3" - my_input_241: - SecretInteger: "3" - my_input_41: - SecretInteger: "3" - my_model_coef_0_235: - SecretInteger: "3" - my_model_coef_0_244: - SecretInteger: "3" - my_model_coef_0_378: - SecretInteger: "3" - my_model_coef_0_401: - SecretInteger: "3" - my_input_140: - SecretInteger: "3" - my_input_463: - SecretInteger: "3" - my_model_coef_0_340: - SecretInteger: "3" - my_model_coef_0_205: - SecretInteger: "3" - my_model_coef_0_127: - SecretInteger: "3" - my_model_coef_0_191: - SecretInteger: "3" - my_input_96: - SecretInteger: "3" - my_input_146: - SecretInteger: "3" - my_input_391: - SecretInteger: "3" - my_model_coef_0_15: - SecretInteger: "3" - my_model_coef_0_201: - SecretInteger: "3" - my_input_355: - SecretInteger: "3" - my_input_139: - SecretInteger: "3" - my_input_270: - SecretInteger: "3" - my_model_coef_0_20: - SecretInteger: "3" - my_input_414: - SecretInteger: "3" - my_model_coef_0_117: - SecretInteger: "3" - my_input_428: - SecretInteger: "3" - my_input_494: - SecretInteger: "3" - my_model_coef_0_168: - SecretInteger: "3" - my_input_266: - SecretInteger: "3" - my_input_492: - SecretInteger: "3" - my_input_94: - SecretInteger: "3" - my_input_102: - SecretInteger: "3" - my_model_coef_0_365: - SecretInteger: "3" - my_input_212: - SecretInteger: "3" - my_input_205: - SecretInteger: "3" - my_input_213: - SecretInteger: "3" - my_model_coef_0_39: - SecretInteger: "3" - my_model_coef_0_404: - SecretInteger: "3" - my_input_416: - SecretInteger: "3" - my_input_258: - SecretInteger: "3" - my_model_coef_0_245: - SecretInteger: "3" - my_input_411: - SecretInteger: "3" - my_input_278: - SecretInteger: "3" - my_model_coef_0_311: - SecretInteger: "3" - my_input_23: - SecretInteger: "3" - my_input_282: - SecretInteger: "3" - my_input_342: - SecretInteger: "3" - my_model_coef_0_57: - SecretInteger: "3" - my_model_coef_0_23: - SecretInteger: "3" - my_input_496: - SecretInteger: "3" - my_input_173: - SecretInteger: "3" - my_input_82: - SecretInteger: "3" - my_model_coef_0_88: - SecretInteger: "3" - my_input_87: - SecretInteger: "3" - my_model_coef_0_118: - SecretInteger: "3" - my_input_138: - SecretInteger: "3" - my_input_179: - SecretInteger: "3" - my_input_120: - SecretInteger: "3" - my_model_coef_0_316: - SecretInteger: "3" - my_model_coef_0_240: - SecretInteger: "3" - my_model_coef_0_351: - SecretInteger: "3" - my_input_245: - SecretInteger: "3" - my_model_coef_0_349: - SecretInteger: "3" - my_model_coef_0_86: - SecretInteger: "3" - my_input_178: - SecretInteger: "3" - my_model_coef_0_336: - SecretInteger: "3" - my_input_185: - SecretInteger: "3" - my_input_187: - SecretInteger: "3" - my_input_11: - SecretInteger: "3" - my_model_coef_0_275: - SecretInteger: "3" - my_model_coef_0_54: - SecretInteger: "3" - my_model_coef_0_5: - SecretInteger: "3" - my_model_coef_0_335: - SecretInteger: "3" - my_input_413: - SecretInteger: "3" - my_input_26: - SecretInteger: "3" - my_model_coef_0_231: - SecretInteger: "3" - my_model_coef_0_486: - SecretInteger: "3" - my_input_125: - SecretInteger: "3" - my_model_coef_0_225: - SecretInteger: "3" - my_model_coef_0_295: - SecretInteger: "3" - my_model_coef_0_282: - SecretInteger: "3" - my_model_coef_0_289: - SecretInteger: "3" - my_model_coef_0_95: - SecretInteger: "3" - my_model_coef_0_411: - SecretInteger: "3" - my_input_229: - SecretInteger: "3" - my_input_165: - SecretInteger: "3" - my_model_coef_0_27: - SecretInteger: "3" - my_model_coef_0_250: - SecretInteger: "3" - my_input_223: - SecretInteger: "3" - my_input_6: - SecretInteger: "3" - my_input_63: - SecretInteger: "3" - my_model_coef_0_152: - SecretInteger: "3" - my_input_188: - SecretInteger: "3" - my_input_333: - SecretInteger: "3" - my_model_coef_0_277: - SecretInteger: "3" - my_model_coef_0_178: - SecretInteger: "3" - my_input_109: - SecretInteger: "3" - my_model_coef_0_330: - SecretInteger: "3" - my_model_coef_0_386: - SecretInteger: "3" - my_input_169: - SecretInteger: "3" - my_model_coef_0_154: - SecretInteger: "3" - my_model_coef_0_160: - SecretInteger: "3" - my_model_coef_0_99: - SecretInteger: "3" - my_input_294: - SecretInteger: "3" - my_model_coef_0_451: - SecretInteger: "3" - my_input_280: - SecretInteger: "3" - my_model_coef_0_398: - SecretInteger: "3" - my_input_394: - SecretInteger: "3" - my_model_coef_0_497: - SecretInteger: "3" - my_input_286: - SecretInteger: "3" - my_input_387: - SecretInteger: "3" - my_input_199: - SecretInteger: "3" - my_model_coef_0_139: - SecretInteger: "3" - my_model_coef_0_259: - SecretInteger: "3" - my_model_coef_0_132: - SecretInteger: "3" - my_model_coef_0_130: - SecretInteger: "3" - my_model_coef_0_2: - SecretInteger: "3" - my_model_coef_0_125: - SecretInteger: "3" - my_model_coef_0_215: - SecretInteger: "3" - my_model_coef_0_465: - SecretInteger: "3" - my_model_coef_0_495: - SecretInteger: "3" - my_model_coef_0_77: - SecretInteger: "3" - my_model_coef_0_122: - SecretInteger: "3" - my_model_coef_0_366: - SecretInteger: "3" - my_model_coef_0_203: - SecretInteger: "3" - my_model_coef_0_74: - SecretInteger: "3" - my_model_coef_0_292: - SecretInteger: "3" - my_input_53: - SecretInteger: "3" - my_model_coef_0_300: - SecretInteger: "3" - my_model_coef_0_298: - SecretInteger: "3" - my_input_39: - SecretInteger: "3" - my_input_46: - SecretInteger: "3" - my_input_136: - SecretInteger: "3" - my_input_9: - SecretInteger: "3" - my_input_83: - SecretInteger: "3" - my_input_478: - SecretInteger: "3" - my_model_coef_0_53: - SecretInteger: "3" - my_model_coef_0_199: - SecretInteger: "3" - my_model_coef_0_458: - SecretInteger: "3" - my_model_coef_0_387: - SecretInteger: "3" - my_model_coef_0_310: - SecretInteger: "3" - my_input_272: - SecretInteger: "3" - my_model_coef_0_273: - SecretInteger: "3" - my_model_coef_0_93: - SecretInteger: "3" - my_model_coef_0_70: - SecretInteger: "3" - my_input_50: - SecretInteger: "3" - my_input_353: - SecretInteger: "3" - my_input_442: - SecretInteger: "3" - my_input_379: - SecretInteger: "3" - my_model_coef_0_434: - SecretInteger: "3" - my_input_93: - SecretInteger: "3" - my_input_203: - SecretInteger: "3" - my_input_64: - SecretInteger: "3" - my_model_coef_0_499: - SecretInteger: "3" - my_input_142: - SecretInteger: "3" - my_input_182: - SecretInteger: "3" - my_input_115: - SecretInteger: "3" - my_input_117: - SecretInteger: "3" - my_model_coef_0_104: - SecretInteger: "3" - my_model_coef_0_156: - SecretInteger: "3" - my_model_coef_0_293: - SecretInteger: "3" - my_input_155: - SecretInteger: "3" - my_input_148: - SecretInteger: "3" - my_input_476: - SecretInteger: "3" - my_model_coef_0_408: - SecretInteger: "3" - my_model_coef_0_322: - SecretInteger: "3" - my_model_coef_0_433: - SecretInteger: "3" - my_model_coef_0_97: - SecretInteger: "3" - my_input_116: - SecretInteger: "3" - my_model_coef_0_186: - SecretInteger: "3" - my_model_coef_0_439: - SecretInteger: "3" - my_input_153: - SecretInteger: "3" - my_model_coef_0_187: - SecretInteger: "3" - my_input_248: - SecretInteger: "3" - my_input_292: - SecretInteger: "3" - my_input_25: - SecretInteger: "3" - my_model_coef_0_105: - SecretInteger: "3" - my_input_135: - SecretInteger: "3" - my_input_427: - SecretInteger: "3" - my_input_85: - SecretInteger: "3" - my_model_coef_0_422: - SecretInteger: "3" - my_model_coef_0_89: - SecretInteger: "3" - my_input_147: - SecretInteger: "3" - my_input_268: - SecretInteger: "3" - my_model_coef_0_384: - SecretInteger: "3" - my_model_coef_0_480: - SecretInteger: "3" - my_model_coef_0_308: - SecretInteger: "3" - my_model_coef_0_354: - SecretInteger: "3" - my_input_132: - SecretInteger: "3" - my_input_202: - SecretInteger: "3" - my_input_357: - SecretInteger: "3" - my_input_320: - SecretInteger: "3" - my_input_209: - SecretInteger: "3" - my_model_coef_0_172: - SecretInteger: "3" - my_input_66: - SecretInteger: "3" - my_input_124: - SecretInteger: "3" - my_input_373: - SecretInteger: "3" - my_model_coef_0_479: - SecretInteger: "3" - my_model_coef_0_146: - SecretInteger: "3" - my_model_coef_0_466: - SecretInteger: "3" - my_model_coef_0_8: - SecretInteger: "3" - my_input_356: - SecretInteger: "3" - my_input_371: - SecretInteger: "3" - my_input_378: - SecretInteger: "3" - my_model_coef_0_121: - SecretInteger: "3" - my_model_coef_0_170: - SecretInteger: "3" - my_input_470: - SecretInteger: "3" - my_model_coef_0_325: - SecretInteger: "3" - my_model_coef_0_457: - SecretInteger: "3" - my_input_101: - SecretInteger: "3" - my_model_coef_0_52: - SecretInteger: "3" - my_model_coef_0_270: - SecretInteger: "3" - my_model_coef_0_26: - SecretInteger: "3" - my_model_coef_0_290: - SecretInteger: "3" - my_input_498: - SecretInteger: "3" - my_model_coef_0_165: - SecretInteger: "3" - my_input_449: - SecretInteger: "3" - my_input_376: - SecretInteger: "3" - my_model_coef_0_339: - SecretInteger: "3" - my_input_316: - SecretInteger: "3" - my_model_coef_0_188: - SecretInteger: "3" - my_model_coef_0_413: - SecretInteger: "3" - my_model_coef_0_338: - SecretInteger: "3" - my_model_coef_0_10: - SecretInteger: "3" - my_model_coef_0_469: - SecretInteger: "3" - my_model_coef_0_276: - SecretInteger: "3" - my_model_coef_0_155: - SecretInteger: "3" - my_model_coef_0_115: - SecretInteger: "3" - my_input_186: - SecretInteger: "3" - my_input_446: - SecretInteger: "3" - my_model_coef_0_173: - SecretInteger: "3" - my_model_coef_0_405: - SecretInteger: "3" - my_input_291: - SecretInteger: "3" - my_model_coef_0_321: - SecretInteger: "3" - my_model_coef_0_38: - SecretInteger: "3" - my_model_coef_0_176: - SecretInteger: "3" - my_model_coef_0_49: - SecretInteger: "3" - my_model_coef_0_385: - SecretInteger: "3" - my_model_coef_0_267: - SecretInteger: "3" - my_model_coef_0_14: - SecretInteger: "3" - my_model_coef_0_48: - SecretInteger: "3" - my_model_coef_0_312: - SecretInteger: "3" - my_input_430: - SecretInteger: "3" - my_model_coef_0_373: - SecretInteger: "3" - my_model_coef_0_443: - SecretInteger: "3" - my_model_coef_0_327: - SecretInteger: "3" - my_model_coef_0_453: - SecretInteger: "3" - my_input_35: - SecretInteger: "3" - my_input_208: - SecretInteger: "3" - my_input_228: - SecretInteger: "3" - my_model_coef_0_302: - SecretInteger: "3" - my_model_coef_0_491: - SecretInteger: "3" - my_model_coef_0_34: - SecretInteger: "3" - my_model_coef_0_305: - SecretInteger: "3" - my_model_coef_0_320: - SecretInteger: "3" - my_input_380: - SecretInteger: "3" - my_model_coef_0_47: - SecretInteger: "3" - my_input_419: - SecretInteger: "3" - my_model_coef_0_484: - SecretInteger: "3" - my_input_70: - SecretInteger: "3" - my_input_218: - SecretInteger: "3" - my_model_coef_0_474: - SecretInteger: "3" - my_input_257: - SecretInteger: "3" - my_input_361: - SecretInteger: "3" - my_input_219: - SecretInteger: "3" - my_model_coef_0_331: - SecretInteger: "3" - my_input_37: - SecretInteger: "3" - my_input_456: - SecretInteger: "3" - my_model_coef_0_252: - SecretInteger: "3" - my_input_57: - SecretInteger: "3" - my_input_91: - SecretInteger: "3" - my_model_coef_0_446: - SecretInteger: "3" - my_model_coef_0_184: - SecretInteger: "3" - my_input_354: - SecretInteger: "3" - my_model_coef_0_410: - SecretInteger: "3" - my_input_10: - SecretInteger: "3" - my_input_172: - SecretInteger: "3" - my_model_coef_0_460: - SecretInteger: "3" - my_model_coef_0_449: - SecretInteger: "3" - my_input_76: - SecretInteger: "3" - my_input_61: - SecretInteger: "3" - my_input_433: - SecretInteger: "3" - my_model_coef_0_149: - SecretInteger: "3" - my_model_coef_0_382: - SecretInteger: "3" - my_model_coef_0_418: - SecretInteger: "3" - my_input_222: - SecretInteger: "3" - my_model_coef_0_353: - SecretInteger: "3" - my_input_54: - SecretInteger: "3" - my_input_438: - SecretInteger: "3" - my_input_309: - SecretInteger: "3" - my_input_0: - SecretInteger: "3" - my_input_235: - SecretInteger: "3" - my_model_coef_0_50: - SecretInteger: "3" - my_model_coef_0_221: - SecretInteger: "3" - my_model_coef_0_106: - SecretInteger: "3" - my_input_340: - SecretInteger: "3" - my_model_coef_0_46: - SecretInteger: "3" - my_input_262: - SecretInteger: "3" - my_input_448: - SecretInteger: "3" - my_input_20: - SecretInteger: "3" - my_model_coef_0_343: - SecretInteger: "3" - my_model_coef_0_416: - SecretInteger: "3" - my_input_149: - SecretInteger: "3" - my_model_coef_0_169: - SecretInteger: "3" - my_model_coef_0_233: - SecretInteger: "3" - my_model_coef_0_123: - SecretInteger: "3" - my_input_304: - SecretInteger: "3" - my_input_36: - SecretInteger: "3" - my_input_65: - SecretInteger: "3" - my_input_359: - SecretInteger: "3" - my_input_337: - SecretInteger: "3" - my_model_coef_0_219: - SecretInteger: "3" - my_model_coef_0_92: - SecretInteger: "3" - my_input_154: - SecretInteger: "3" - my_model_coef_0_377: - SecretInteger: "3" - my_model_coef_0_255: - SecretInteger: "3" - my_input_497: - SecretInteger: "3" - my_model_coef_0_60: - SecretInteger: "3" - my_model_coef_0_344: - SecretInteger: "3" - my_model_coef_0_445: - SecretInteger: "3" - my_input_112: - SecretInteger: "3" - my_input_251: - SecretInteger: "3" - my_input_418: - SecretInteger: "3" - my_input_275: - SecretInteger: "3" - my_model_coef_0_214: - SecretInteger: "3" - my_input_224: - SecretInteger: "3" - my_input_459: - SecretInteger: "3" - my_model_coef_0_296: - SecretInteger: "3" - my_input_440: - SecretInteger: "3" - my_input_58: - SecretInteger: "3" - my_input_239: - SecretInteger: "3" - my_input_246: - SecretInteger: "3" - my_input_271: - SecretInteger: "3" - my_model_coef_0_482: - SecretInteger: "3" - my_model_coef_0_44: - SecretInteger: "3" - my_input_346: - SecretInteger: "3" - my_model_coef_0_109: - SecretInteger: "3" - my_model_coef_0_72: - SecretInteger: "3" - my_model_coef_0_328: - SecretInteger: "3" - my_model_coef_0_190: - SecretInteger: "3" - my_input_143: - SecretInteger: "3" - my_model_coef_0_30: - SecretInteger: "3" - my_model_coef_0_68: - SecretInteger: "3" - my_model_coef_0_406: - SecretInteger: "3" - my_model_coef_0_265: - SecretInteger: "3" - my_input_129: - SecretInteger: "3" - my_input_363: - SecretInteger: "3" - my_input_439: - SecretInteger: "3" - my_input_99: - SecretInteger: "3" - my_model_coef_0_222: - SecretInteger: "3" - my_model_coef_0_475: - SecretInteger: "3" - my_model_coef_0_65: - SecretInteger: "3" - my_model_coef_0_128: - SecretInteger: "3" - my_input_402: - SecretInteger: "3" - my_model_coef_0_315: - SecretInteger: "3" - my_input_403: - SecretInteger: "3" - my_input_481: - SecretInteger: "3" - my_model_coef_0_162: - SecretInteger: "3" - my_model_coef_0_266: - SecretInteger: "3" - my_model_coef_0_461: - SecretInteger: "3" - my_input_18: - SecretInteger: "3" - my_input_97: - SecretInteger: "3" - my_model_coef_0_459: - SecretInteger: "3" - my_input_130: - SecretInteger: "3" - my_input_295: - SecretInteger: "3" - my_model_coef_0_396: - SecretInteger: "3" - my_model_coef_0_239: - SecretInteger: "3" - my_model_coef_0_318: - SecretInteger: "3" - my_model_coef_0_324: - SecretInteger: "3" - my_model_coef_0_332: - SecretInteger: "3" - my_input_28: - SecretInteger: "3" - my_input_111: - SecretInteger: "3" - my_input_312: - SecretInteger: "3" - my_input_40: - SecretInteger: "3" - my_input_214: - SecretInteger: "3" - my_model_coef_0_51: - SecretInteger: "3" - my_model_coef_0_75: - SecretInteger: "3" - my_model_coef_0_345: - SecretInteger: "3" - my_model_coef_0_249: - SecretInteger: "3" - my_input_398: - SecretInteger: "3" - my_model_coef_0_269: - SecretInteger: "3" - my_model_coef_0_196: - SecretInteger: "3" - my_input_297: - SecretInteger: "3" - my_model_coef_0_450: - SecretInteger: "3" - my_model_coef_0_183: - SecretInteger: "3" - my_input_263: - SecretInteger: "3" - my_input_410: - SecretInteger: "3" - my_input_367: - SecretInteger: "3" - my_model_coef_0_496: - SecretInteger: "3" - my_input_107: - SecretInteger: "3" - my_model_coef_0_19: - SecretInteger: "3" - my_input_490: - SecretInteger: "3" - my_model_coef_0_218: - SecretInteger: "3" - my_model_coef_0_261: - SecretInteger: "3" - my_model_coef_0_370: - SecretInteger: "3" - my_input_479: - SecretInteger: "3" - my_input_401: - SecretInteger: "3" - my_input_423: - SecretInteger: "3" - my_input_95: - SecretInteger: "3" - my_model_coef_0_456: - SecretInteger: "3" - my_model_coef_0_189: - SecretInteger: "3" - my_model_coef_0_347: - SecretInteger: "3" - my_input_273: - SecretInteger: "3" - my_input_465: - SecretInteger: "3" - my_model_coef_0_356: - SecretInteger: "3" - my_input_311: - SecretInteger: "3" - my_model_coef_0_78: - SecretInteger: "3" - my_input_345: - SecretInteger: "3" - my_model_coef_0_63: - SecretInteger: "3" - my_input_396: - SecretInteger: "3" - my_model_coef_0_111: - SecretInteger: "3" - my_input_192: - SecretInteger: "3" - my_model_coef_0_1: - SecretInteger: "3" - my_input_33: - SecretInteger: "3" - my_model_coef_0_471: - SecretInteger: "3" - my_input_80: - SecretInteger: "3" - my_input_281: - SecretInteger: "3" - my_model_coef_0_3: - SecretInteger: "3" - my_model_coef_0_417: - SecretInteger: "3" - my_model_coef_0_462: - SecretInteger: "3" - my_model_coef_0_224: - SecretInteger: "3" - my_input_437: - SecretInteger: "3" - my_input_386: - SecretInteger: "3" - my_input_27: - SecretInteger: "3" - my_input_166: - SecretInteger: "3" - my_input_279: - SecretInteger: "3" - my_model_coef_0_197: - SecretInteger: "3" - my_model_coef_0_369: - SecretInteger: "3" - my_model_coef_0_133: - SecretInteger: "3" - my_input_141: - SecretInteger: "3" - my_model_coef_0_372: - SecretInteger: "3" - my_input_451: - SecretInteger: "3" - my_model_coef_0_415: - SecretInteger: "3" - my_model_coef_0_455: - SecretInteger: "3" - my_input_157: - SecretInteger: "3" - my_model_coef_0_487: - SecretInteger: "3" - my_input_210: - SecretInteger: "3" - my_model_coef_0_319: - SecretInteger: "3" - my_input_301: - SecretInteger: "3" - my_input_68: - SecretInteger: "3" - my_model_coef_0_431: - SecretInteger: "3" - my_input_234: - SecretInteger: "3" - my_model_coef_0_448: - SecretInteger: "3" - my_input_285: - SecretInteger: "3" - my_input_184: - SecretInteger: "3" - my_model_coef_0_228: - SecretInteger: "3" - my_input_360: - SecretInteger: "3" - my_input_436: - SecretInteger: "3" - my_input_331: - SecretInteger: "3" - my_model_coef_0_364: - SecretInteger: "3" - my_model_coef_0_317: - SecretInteger: "3" - my_model_coef_0_402: - SecretInteger: "3" - my_input_17: - SecretInteger: "3" - my_model_coef_0_61: - SecretInteger: "3" - my_input_351: - SecretInteger: "3" - my_input_370: - SecretInteger: "3" - my_input_429: - SecretInteger: "3" - my_input_393: - SecretInteger: "3" - my_input_211: - SecretInteger: "3" - my_model_coef_0_36: - SecretInteger: "3" - my_input_108: - SecretInteger: "3" - my_model_coef_0_278: - SecretInteger: "3" - my_model_coef_0_18: - SecretInteger: "3" - my_model_coef_0_84: - SecretInteger: "3" - my_model_coef_0_467: - SecretInteger: "3" - my_input_193: - SecretInteger: "3" - my_input_290: - SecretInteger: "3" - my_input_104: - SecretInteger: "3" - my_model_coef_0_490: - SecretInteger: "3" - my_input_78: - SecretInteger: "3" - my_input_457: - SecretInteger: "3" - my_input_238: - SecretInteger: "3" - my_input_259: - SecretInteger: "3" - my_model_coef_0_297: - SecretInteger: "3" - my_input_283: - SecretInteger: "3" - my_input_198: - SecretInteger: "3" - my_model_coef_0_195: - SecretInteger: "3" - my_model_coef_0_299: - SecretInteger: "3" - my_model_coef_0_257: - SecretInteger: "3" - my_model_coef_0_287: - SecretInteger: "3" - my_input_261: - SecretInteger: "3" - my_input_344: - SecretInteger: "3" - my_input_332: - SecretInteger: "3" - my_model_coef_0_419: - SecretInteger: "3" - my_model_coef_0_98: - SecretInteger: "3" - my_input_105: - SecretInteger: "3" - my_input_171: - SecretInteger: "3" - my_input_152: - SecretInteger: "3" - my_model_coef_0_237: - SecretInteger: "3" - my_model_coef_0_301: - SecretInteger: "3" - my_input_408: - SecretInteger: "3" - my_input_335: - SecretInteger: "3" - my_model_coef_0_207: - SecretInteger: "3" - my_model_coef_0_380: - SecretInteger: "3" - my_model_coef_0_393: - SecretInteger: "3" - my_input_317: - SecretInteger: "3" - my_input_163: - SecretInteger: "3" - my_input_415: - SecretInteger: "3" - my_input_467: - SecretInteger: "3" - my_input_21: - SecretInteger: "3" - my_input_88: - SecretInteger: "3" - my_model_coef_0_242: - SecretInteger: "3" - my_input_308: - SecretInteger: "3" - my_model_coef_0_7: - SecretInteger: "3" - my_model_coef_0_375: - SecretInteger: "3" - my_model_coef_0_285: - SecretInteger: "3" - my_input_215: - SecretInteger: "3" - my_input_12: - SecretInteger: "3" - my_input_343: - SecretInteger: "3" - my_model_coef_0_35: - SecretInteger: "3" - my_input_151: - SecretInteger: "3" - my_model_coef_0_271: - SecretInteger: "3" - my_input_397: - SecretInteger: "3" - my_input_389: - SecretInteger: "3" - my_input_425: - SecretInteger: "3" - my_input_388: - SecretInteger: "3" - my_model_coef_0_454: - SecretInteger: "3" - my_input_77: - SecretInteger: "3" - my_input_201: - SecretInteger: "3" - my_model_coef_0_407: - SecretInteger: "3" - my_input_51: - SecretInteger: "3" - my_input_334: - SecretInteger: "3" - my_model_coef_0_437: - SecretInteger: "3" - my_input_14: - SecretInteger: "3" - my_model_coef_0_206: - SecretInteger: "3" - my_model_coef_0_412: - SecretInteger: "3" - my_input_44: - SecretInteger: "3" - my_input_30: - SecretInteger: "3" - my_model_coef_0_71: - SecretInteger: "3" - my_model_coef_0_124: - SecretInteger: "3" - my_model_coef_0_286: - SecretInteger: "3" - my_input_2: - SecretInteger: "3" - my_model_coef_0_140: - SecretInteger: "3" - my_input_197: - SecretInteger: "3" - my_model_coef_0_66: - SecretInteger: "3" - my_model_coef_0_144: - SecretInteger: "3" - my_input_131: - SecretInteger: "3" - public_variables: {} + my_input_81: + SecretInteger: '3' + my_input_417: + SecretInteger: '3' + my_input_168: + SecretInteger: '3' + my_input_75: + SecretInteger: '3' + my_model_coef_0_81: + SecretInteger: '3' + my_model_coef_0_194: + SecretInteger: '3' + my_model_coef_0_210: + SecretInteger: '3' + my_model_coef_0_108: + SecretInteger: '3' + my_model_coef_0_476: + SecretInteger: '3' + my_model_coef_0_182: + SecretInteger: '3' + my_input_236: + SecretInteger: '3' + my_input_13: + SecretInteger: '3' + my_model_coef_0_229: + SecretInteger: '3' + my_model_coef_0_147: + SecretInteger: '3' + my_input_468: + SecretInteger: '3' + my_model_coef_0_350: + SecretInteger: '3' + my_input_252: + SecretInteger: '3' + my_input_34: + SecretInteger: '3' + my_model_coef_0_212: + SecretInteger: '3' + my_input_330: + SecretInteger: '3' + my_input_240: + SecretInteger: '3' + my_input_133: + SecretInteger: '3' + my_model_coef_0_166: + SecretInteger: '3' + my_model_coef_0_174: + SecretInteger: '3' + my_model_coef_0_425: + SecretInteger: '3' + my_input_452: + SecretInteger: '3' + my_model_coef_0_423: + SecretInteger: '3' + my_model_coef_0_291: + SecretInteger: '3' + my_model_coef_0_359: + SecretInteger: '3' + my_model_coef_0_143: + SecretInteger: '3' + my_model_coef_0_94: + SecretInteger: '3' + my_model_coef_0_177: + SecretInteger: '3' + my_input_217: + SecretInteger: '3' + my_model_coef_0_80: + SecretInteger: '3' + my_input_336: + SecretInteger: '3' + my_input_472: + SecretInteger: '3' + my_model_coef_0_232: + SecretInteger: '3' + my_model_coef_0_274: + SecretInteger: '3' + my_model_coef_0_256: + SecretInteger: '3' + my_model_coef_0_368: + SecretInteger: '3' + my_input_47: + SecretInteger: '3' + my_input_79: + SecretInteger: '3' + my_input_409: + SecretInteger: '3' + my_model_coef_0_42: + SecretInteger: '3' + my_model_coef_0_262: + SecretInteger: '3' + my_model_coef_0_29: + SecretInteger: '3' + my_input_48: + SecretInteger: '3' + my_input_100: + SecretInteger: '3' + my_model_coef_0_483: + SecretInteger: '3' + my_input_372: + SecretInteger: '3' + my_input_276: + SecretInteger: '3' + my_input_221: + SecretInteger: '3' + my_input_349: + SecretInteger: '3' + my_model_coef_0_25: + SecretInteger: '3' + my_input_422: + SecretInteger: '3' + my_model_coef_0_379: + SecretInteger: '3' + my_input_329: + SecretInteger: '3' + my_input_482: + SecretInteger: '3' + my_model_coef_0_234: + SecretInteger: '3' + my_input_237: + SecretInteger: '3' + my_input_435: + SecretInteger: '3' + my_input_260: + SecretInteger: '3' + my_model_coef_0_400: + SecretInteger: '3' + my_model_coef_0_472: + SecretInteger: '3' + my_model_coef_0_96: + SecretInteger: '3' + my_model_coef_0_279: + SecretInteger: '3' + my_input_230: + SecretInteger: '3' + my_input_313: + SecretInteger: '3' + my_input_444: + SecretInteger: '3' + my_input_174: + SecretInteger: '3' + my_model_coef_0_236: + SecretInteger: '3' + my_input_122: + SecretInteger: '3' + my_input_461: + SecretInteger: '3' + my_input_1: + SecretInteger: '3' + my_input_314: + SecretInteger: '3' + my_input_325: + SecretInteger: '3' + my_model_coef_0_243: + SecretInteger: '3' + my_model_coef_0_383: + SecretInteger: '3' + my_input_3: + SecretInteger: '3' + my_input_195: + SecretInteger: '3' + my_input_473: + SecretInteger: '3' + my_input_464: + SecretInteger: '3' + my_input_300: + SecretInteger: '3' + my_model_coef_0_436: + SecretInteger: '3' + my_input_243: + SecretInteger: '3' + my_model_coef_0_192: + SecretInteger: '3' + my_model_coef_0_421: + SecretInteger: '3' + my_input_62: + SecretInteger: '3' + my_input_255: + SecretInteger: '3' + my_input_382: + SecretInteger: '3' + my_input_247: + SecretInteger: '3' + my_model_coef_0_116: + SecretInteger: '3' + my_input_242: + SecretInteger: '3' + my_model_coef_0_294: + SecretInteger: '3' + my_model_coef_0_59: + SecretInteger: '3' + my_model_coef_0_185: + SecretInteger: '3' + my_model_coef_0_390: + SecretInteger: '3' + my_model_coef_0_202: + SecretInteger: '3' + my_model_coef_0_304: + SecretInteger: '3' + my_model_coef_0_248: + SecretInteger: '3' + my_input_69: + SecretInteger: '3' + my_input_206: + SecretInteger: '3' + my_input_485: + SecretInteger: '3' + my_input_118: + SecretInteger: '3' + my_input_307: + SecretInteger: '3' + my_input_289: + SecretInteger: '3' + my_input_45: + SecretInteger: '3' + my_input_164: + SecretInteger: '3' + my_input_181: + SecretInteger: '3' + my_input_466: + SecretInteger: '3' + my_input_84: + SecretInteger: '3' + my_model_coef_0_208: + SecretInteger: '3' + my_input_395: + SecretInteger: '3' + my_input_127: + SecretInteger: '3' + my_input_29: + SecretInteger: '3' + my_input_144: + SecretInteger: '3' + my_input_326: + SecretInteger: '3' + my_input_495: + SecretInteger: '3' + my_input_191: + SecretInteger: '3' + my_model_coef_0_67: + SecretInteger: '3' + my_model_coef_0_394: + SecretInteger: '3' + my_input_319: + SecretInteger: '3' + my_input_126: + SecretInteger: '3' + my_input_431: + SecretInteger: '3' + my_model_coef_0_388: + SecretInteger: '3' + my_model_coef_0_227: + SecretInteger: '3' + my_input_15: + SecretInteger: '3' + my_input_128: + SecretInteger: '3' + my_input_445: + SecretInteger: '3' + my_input_59: + SecretInteger: '3' + my_input_404: + SecretInteger: '3' + my_input_158: + SecretInteger: '3' + my_model_coef_0_470: + SecretInteger: '3' + my_model_coef_0_137: + SecretInteger: '3' + my_model_coef_0_33: + SecretInteger: '3' + my_input_183: + SecretInteger: '3' + my_model_coef_0_395: + SecretInteger: '3' + my_input_323: + SecretInteger: '3' + my_input_327: + SecretInteger: '3' + my_input_113: + SecretInteger: '3' + my_model_coef_0_498: + SecretInteger: '3' + my_input_385: + SecretInteger: '3' + my_input_362: + SecretInteger: '3' + my_input_92: + SecretInteger: '3' + my_model_coef_0_333: + SecretInteger: '3' + my_input_49: + SecretInteger: '3' + my_model_coef_0_241: + SecretInteger: '3' + my_model_coef_0_361: + SecretInteger: '3' + my_model_coef_0_381: + SecretInteger: '3' + my_model_coef_0_409: + SecretInteger: '3' + my_input_72: + SecretInteger: '3' + my_input_123: + SecretInteger: '3' + my_model_coef_0_64: + SecretInteger: '3' + my_input_170: + SecretInteger: '3' + my_input_328: + SecretInteger: '3' + my_input_250: + SecretInteger: '3' + my_input_341: + SecretInteger: '3' + my_input_303: + SecretInteger: '3' + my_input_426: + SecretInteger: '3' + my_model_coef_0_131: + SecretInteger: '3' + my_input_420: + SecretInteger: '3' + my_model_coef_0_153: + SecretInteger: '3' + my_model_coef_0_403: + SecretInteger: '3' + my_input_67: + SecretInteger: '3' + my_input_321: + SecretInteger: '3' + my_model_coef_0_112: + SecretInteger: '3' + my_input_486: + SecretInteger: '3' + my_model_coef_0_6: + SecretInteger: '3' + my_model_coef_0_357: + SecretInteger: '3' + my_input_399: + SecretInteger: '3' + my_input_432: + SecretInteger: '3' + my_input_8: + SecretInteger: '3' + my_model_coef_0_485: + SecretInteger: '3' + my_input_407: + SecretInteger: '3' + my_input_22: + SecretInteger: '3' + my_model_coef_0_306: + SecretInteger: '3' + my_model_coef_0_163: + SecretInteger: '3' + my_input_196: + SecretInteger: '3' + my_input_364: + SecretInteger: '3' + my_model_coef_0_341: + SecretInteger: '3' + my_input_350: + SecretInteger: '3' + my_input_377: + SecretInteger: '3' + my_input_454: + SecretInteger: '3' + my_input_458: + SecretInteger: '3' + my_model_coef_0_167: + SecretInteger: '3' + my_model_coef_0_430: + SecretInteger: '3' + my_model_coef_0_129: + SecretInteger: '3' + my_input_400: + SecretInteger: '3' + my_model_coef_0_41: + SecretInteger: '3' + my_input_265: + SecretInteger: '3' + my_model_coef_0_134: + SecretInteger: '3' + my_model_coef_0_82: + SecretInteger: '3' + my_model_coef_0_56: + SecretInteger: '3' + my_input_38: + SecretInteger: '3' + my_input_103: + SecretInteger: '3' + my_model_coef_0_0: + SecretInteger: '3' + my_model_coef_0_260: + SecretInteger: '3' + my_model_coef_0_362: + SecretInteger: '3' + my_input_443: + SecretInteger: '3' + my_input_306: + SecretInteger: '3' + my_model_coef_0_441: + SecretInteger: '3' + my_model_coef_0_209: + SecretInteger: '3' + my_model_coef_0_141: + SecretInteger: '3' + my_model_coef_0_217: + SecretInteger: '3' + my_model_coef_0_4: + SecretInteger: '3' + my_model_coef_0_161: + SecretInteger: '3' + my_model_coef_0_481: + SecretInteger: '3' + my_input_119: + SecretInteger: '3' + my_model_coef_0_204: + SecretInteger: '3' + my_model_intercept_0: + SecretInteger: '3' + my_input_177: + SecretInteger: '3' + my_input_86: + SecretInteger: '3' + my_model_coef_0_424: + SecretInteger: '3' + my_model_coef_0_355: + SecretInteger: '3' + my_model_coef_0_55: + SecretInteger: '3' + my_input_231: + SecretInteger: '3' + my_input_74: + SecretInteger: '3' + my_model_coef_0_432: + SecretInteger: '3' + my_input_455: + SecretInteger: '3' + my_model_coef_0_17: + SecretInteger: '3' + my_model_coef_0_119: + SecretInteger: '3' + my_input_156: + SecretInteger: '3' + my_input_190: + SecretInteger: '3' + my_input_381: + SecretInteger: '3' + my_input_421: + SecretInteger: '3' + my_model_coef_0_447: + SecretInteger: '3' + my_input_180: + SecretInteger: '3' + my_input_489: + SecretInteger: '3' + my_model_coef_0_363: + SecretInteger: '3' + my_model_coef_0_440: + SecretInteger: '3' + my_input_264: + SecretInteger: '3' + my_model_coef_0_101: + SecretInteger: '3' + my_model_coef_0_69: + SecretInteger: '3' + my_model_coef_0_246: + SecretInteger: '3' + my_model_coef_0_135: + SecretInteger: '3' + my_input_499: + SecretInteger: '3' + my_model_coef_0_346: + SecretInteger: '3' + my_input_412: + SecretInteger: '3' + my_input_441: + SecretInteger: '3' + my_model_coef_0_272: + SecretInteger: '3' + my_input_32: + SecretInteger: '3' + my_model_coef_0_251: + SecretInteger: '3' + my_input_16: + SecretInteger: '3' + my_model_coef_0_254: + SecretInteger: '3' + my_input_7: + SecretInteger: '3' + my_input_384: + SecretInteger: '3' + my_model_coef_0_392: + SecretInteger: '3' + my_model_coef_0_62: + SecretInteger: '3' + my_input_90: + SecretInteger: '3' + my_input_194: + SecretInteger: '3' + my_model_coef_0_468: + SecretInteger: '3' + my_input_366: + SecretInteger: '3' + my_input_405: + SecretInteger: '3' + my_model_coef_0_13: + SecretInteger: '3' + my_model_coef_0_159: + SecretInteger: '3' + my_input_424: + SecretInteger: '3' + my_input_254: + SecretInteger: '3' + my_model_coef_0_428: + SecretInteger: '3' + my_model_coef_0_21: + SecretInteger: '3' + my_input_226: + SecretInteger: '3' + my_model_coef_0_258: + SecretInteger: '3' + my_input_310: + SecretInteger: '3' + my_model_coef_0_426: + SecretInteger: '3' + my_model_coef_0_477: + SecretInteger: '3' + my_model_coef_0_24: + SecretInteger: '3' + my_model_coef_0_85: + SecretInteger: '3' + my_model_coef_0_37: + SecretInteger: '3' + my_model_coef_0_145: + SecretInteger: '3' + my_input_160: + SecretInteger: '3' + my_input_256: + SecretInteger: '3' + my_model_coef_0_91: + SecretInteger: '3' + my_model_coef_0_399: + SecretInteger: '3' + my_model_coef_0_309: + SecretInteger: '3' + my_model_coef_0_9: + SecretInteger: '3' + my_model_coef_0_367: + SecretInteger: '3' + my_model_coef_0_326: + SecretInteger: '3' + my_model_coef_0_329: + SecretInteger: '3' + my_input_296: + SecretInteger: '3' + my_input_484: + SecretInteger: '3' + my_input_200: + SecretInteger: '3' + my_model_coef_0_83: + SecretInteger: '3' + my_input_462: + SecretInteger: '3' + my_input_277: + SecretInteger: '3' + my_model_coef_0_238: + SecretInteger: '3' + my_model_coef_0_444: + SecretInteger: '3' + my_model_coef_0_358: + SecretInteger: '3' + my_model_coef_0_158: + SecretInteger: '3' + my_input_390: + SecretInteger: '3' + my_model_coef_0_307: + SecretInteger: '3' + my_model_coef_0_493: + SecretInteger: '3' + my_model_coef_0_323: + SecretInteger: '3' + my_input_374: + SecretInteger: '3' + my_input_469: + SecretInteger: '3' + my_model_coef_0_488: + SecretInteger: '3' + my_model_coef_0_213: + SecretInteger: '3' + my_input_56: + SecretInteger: '3' + my_model_coef_0_79: + SecretInteger: '3' + my_input_159: + SecretInteger: '3' + my_model_coef_0_429: + SecretInteger: '3' + my_input_293: + SecretInteger: '3' + my_input_167: + SecretInteger: '3' + my_input_375: + SecretInteger: '3' + my_model_coef_0_136: + SecretInteger: '3' + my_input_43: + SecretInteger: '3' + my_model_coef_0_157: + SecretInteger: '3' + my_input_24: + SecretInteger: '3' + my_input_5: + SecretInteger: '3' + my_input_450: + SecretInteger: '3' + my_input_42: + SecretInteger: '3' + my_model_coef_0_76: + SecretInteger: '3' + my_model_coef_0_464: + SecretInteger: '3' + my_input_19: + SecretInteger: '3' + my_model_coef_0_198: + SecretInteger: '3' + my_input_249: + SecretInteger: '3' + my_input_493: + SecretInteger: '3' + my_model_coef_0_288: + SecretInteger: '3' + my_input_302: + SecretInteger: '3' + my_model_coef_0_150: + SecretInteger: '3' + my_input_204: + SecretInteger: '3' + my_input_60: + SecretInteger: '3' + my_input_220: + SecretInteger: '3' + my_model_coef_0_280: + SecretInteger: '3' + my_model_coef_0_494: + SecretInteger: '3' + my_model_coef_0_16: + SecretInteger: '3' + my_input_322: + SecretInteger: '3' + my_model_coef_0_268: + SecretInteger: '3' + my_model_coef_0_489: + SecretInteger: '3' + my_model_coef_0_442: + SecretInteger: '3' + my_model_coef_0_374: + SecretInteger: '3' + my_model_coef_0_478: + SecretInteger: '3' + my_input_298: + SecretInteger: '3' + my_input_483: + SecretInteger: '3' + my_input_267: + SecretInteger: '3' + my_model_coef_0_73: + SecretInteger: '3' + my_input_368: + SecretInteger: '3' + my_input_207: + SecretInteger: '3' + my_model_coef_0_220: + SecretInteger: '3' + my_input_318: + SecretInteger: '3' + my_model_coef_0_492: + SecretInteger: '3' + my_input_161: + SecretInteger: '3' + my_model_coef_0_180: + SecretInteger: '3' + my_model_coef_0_371: + SecretInteger: '3' + my_model_coef_0_87: + SecretInteger: '3' + my_model_coef_0_90: + SecretInteger: '3' + my_model_coef_0_148: + SecretInteger: '3' + my_model_coef_0_342: + SecretInteger: '3' + my_model_coef_0_43: + SecretInteger: '3' + my_input_73: + SecretInteger: '3' + my_input_339: + SecretInteger: '3' + my_model_coef_0_179: + SecretInteger: '3' + my_input_338: + SecretInteger: '3' + my_input_434: + SecretInteger: '3' + my_input_475: + SecretInteger: '3' + my_model_coef_0_107: + SecretInteger: '3' + my_model_coef_0_211: + SecretInteger: '3' + my_model_coef_0_473: + SecretInteger: '3' + my_input_274: + SecretInteger: '3' + my_input_447: + SecretInteger: '3' + my_input_175: + SecretInteger: '3' + my_input_55: + SecretInteger: '3' + my_model_coef_0_171: + SecretInteger: '3' + my_input_392: + SecretInteger: '3' + my_model_coef_0_216: + SecretInteger: '3' + my_input_145: + SecretInteger: '3' + my_input_227: + SecretInteger: '3' + my_model_coef_0_226: + SecretInteger: '3' + my_model_coef_0_31: + SecretInteger: '3' + my_input_98: + SecretInteger: '3' + my_input_106: + SecretInteger: '3' + my_input_216: + SecretInteger: '3' + my_model_coef_0_126: + SecretInteger: '3' + my_input_134: + SecretInteger: '3' + my_model_coef_0_102: + SecretInteger: '3' + my_input_324: + SecretInteger: '3' + my_input_162: + SecretInteger: '3' + my_input_121: + SecretInteger: '3' + my_input_71: + SecretInteger: '3' + my_input_491: + SecretInteger: '3' + my_model_coef_0_58: + SecretInteger: '3' + my_input_269: + SecretInteger: '3' + my_input_383: + SecretInteger: '3' + my_model_coef_0_303: + SecretInteger: '3' + my_model_coef_0_120: + SecretInteger: '3' + my_input_150: + SecretInteger: '3' + my_model_coef_0_32: + SecretInteger: '3' + my_model_coef_0_100: + SecretInteger: '3' + my_input_52: + SecretInteger: '3' + my_model_coef_0_397: + SecretInteger: '3' + my_model_coef_0_181: + SecretInteger: '3' + my_input_287: + SecretInteger: '3' + my_model_coef_0_263: + SecretInteger: '3' + my_model_coef_0_360: + SecretInteger: '3' + my_input_110: + SecretInteger: '3' + my_input_288: + SecretInteger: '3' + my_input_305: + SecretInteger: '3' + my_input_453: + SecretInteger: '3' + my_input_232: + SecretInteger: '3' + my_input_474: + SecretInteger: '3' + my_model_coef_0_348: + SecretInteger: '3' + my_model_coef_0_452: + SecretInteger: '3' + my_model_coef_0_352: + SecretInteger: '3' + my_input_4: + SecretInteger: '3' + my_input_31: + SecretInteger: '3' + my_model_coef_0_281: + SecretInteger: '3' + my_input_365: + SecretInteger: '3' + my_model_coef_0_103: + SecretInteger: '3' + my_model_coef_0_175: + SecretInteger: '3' + my_model_coef_0_138: + SecretInteger: '3' + my_model_coef_0_40: + SecretInteger: '3' + my_model_coef_0_230: + SecretInteger: '3' + my_model_coef_0_193: + SecretInteger: '3' + my_model_coef_0_200: + SecretInteger: '3' + my_input_89: + SecretInteger: '3' + my_model_coef_0_427: + SecretInteger: '3' + my_input_480: + SecretInteger: '3' + my_input_253: + SecretInteger: '3' + my_model_coef_0_11: + SecretInteger: '3' + my_model_coef_0_12: + SecretInteger: '3' + my_model_coef_0_113: + SecretInteger: '3' + my_model_coef_0_438: + SecretInteger: '3' + my_model_coef_0_247: + SecretInteger: '3' + my_input_284: + SecretInteger: '3' + my_input_137: + SecretInteger: '3' + my_model_coef_0_283: + SecretInteger: '3' + my_model_coef_0_420: + SecretInteger: '3' + my_input_176: + SecretInteger: '3' + my_model_coef_0_223: + SecretInteger: '3' + my_model_coef_0_435: + SecretInteger: '3' + my_input_244: + SecretInteger: '3' + my_input_477: + SecretInteger: '3' + my_input_471: + SecretInteger: '3' + my_input_114: + SecretInteger: '3' + my_input_233: + SecretInteger: '3' + my_model_coef_0_151: + SecretInteger: '3' + my_model_coef_0_253: + SecretInteger: '3' + my_model_coef_0_264: + SecretInteger: '3' + my_model_coef_0_142: + SecretInteger: '3' + my_model_coef_0_391: + SecretInteger: '3' + my_model_coef_0_337: + SecretInteger: '3' + my_input_369: + SecretInteger: '3' + my_model_coef_0_284: + SecretInteger: '3' + my_model_coef_0_314: + SecretInteger: '3' + my_model_coef_0_28: + SecretInteger: '3' + my_model_coef_0_334: + SecretInteger: '3' + my_input_225: + SecretInteger: '3' + my_input_358: + SecretInteger: '3' + my_input_460: + SecretInteger: '3' + my_model_coef_0_45: + SecretInteger: '3' + my_model_coef_0_389: + SecretInteger: '3' + my_input_406: + SecretInteger: '3' + my_input_487: + SecretInteger: '3' + my_model_coef_0_114: + SecretInteger: '3' + my_model_coef_0_463: + SecretInteger: '3' + my_model_coef_0_110: + SecretInteger: '3' + my_input_299: + SecretInteger: '3' + my_input_488: + SecretInteger: '3' + my_input_352: + SecretInteger: '3' + my_model_coef_0_313: + SecretInteger: '3' + my_model_coef_0_376: + SecretInteger: '3' + my_model_coef_0_164: + SecretInteger: '3' + my_model_coef_0_414: + SecretInteger: '3' + my_model_coef_0_22: + SecretInteger: '3' + my_input_348: + SecretInteger: '3' + my_input_315: + SecretInteger: '3' + my_input_189: + SecretInteger: '3' + my_input_347: + SecretInteger: '3' + my_input_241: + SecretInteger: '3' + my_input_41: + SecretInteger: '3' + my_model_coef_0_235: + SecretInteger: '3' + my_model_coef_0_244: + SecretInteger: '3' + my_model_coef_0_378: + SecretInteger: '3' + my_model_coef_0_401: + SecretInteger: '3' + my_input_140: + SecretInteger: '3' + my_input_463: + SecretInteger: '3' + my_model_coef_0_340: + SecretInteger: '3' + my_model_coef_0_205: + SecretInteger: '3' + my_model_coef_0_127: + SecretInteger: '3' + my_model_coef_0_191: + SecretInteger: '3' + my_input_96: + SecretInteger: '3' + my_input_146: + SecretInteger: '3' + my_input_391: + SecretInteger: '3' + my_model_coef_0_15: + SecretInteger: '3' + my_model_coef_0_201: + SecretInteger: '3' + my_input_355: + SecretInteger: '3' + my_input_139: + SecretInteger: '3' + my_input_270: + SecretInteger: '3' + my_model_coef_0_20: + SecretInteger: '3' + my_input_414: + SecretInteger: '3' + my_model_coef_0_117: + SecretInteger: '3' + my_input_428: + SecretInteger: '3' + my_input_494: + SecretInteger: '3' + my_model_coef_0_168: + SecretInteger: '3' + my_input_266: + SecretInteger: '3' + my_input_492: + SecretInteger: '3' + my_input_94: + SecretInteger: '3' + my_input_102: + SecretInteger: '3' + my_model_coef_0_365: + SecretInteger: '3' + my_input_212: + SecretInteger: '3' + my_input_205: + SecretInteger: '3' + my_input_213: + SecretInteger: '3' + my_model_coef_0_39: + SecretInteger: '3' + my_model_coef_0_404: + SecretInteger: '3' + my_input_416: + SecretInteger: '3' + my_input_258: + SecretInteger: '3' + my_model_coef_0_245: + SecretInteger: '3' + my_input_411: + SecretInteger: '3' + my_input_278: + SecretInteger: '3' + my_model_coef_0_311: + SecretInteger: '3' + my_input_23: + SecretInteger: '3' + my_input_282: + SecretInteger: '3' + my_input_342: + SecretInteger: '3' + my_model_coef_0_57: + SecretInteger: '3' + my_model_coef_0_23: + SecretInteger: '3' + my_input_496: + SecretInteger: '3' + my_input_173: + SecretInteger: '3' + my_input_82: + SecretInteger: '3' + my_model_coef_0_88: + SecretInteger: '3' + my_input_87: + SecretInteger: '3' + my_model_coef_0_118: + SecretInteger: '3' + my_input_138: + SecretInteger: '3' + my_input_179: + SecretInteger: '3' + my_input_120: + SecretInteger: '3' + my_model_coef_0_316: + SecretInteger: '3' + my_model_coef_0_240: + SecretInteger: '3' + my_model_coef_0_351: + SecretInteger: '3' + my_input_245: + SecretInteger: '3' + my_model_coef_0_349: + SecretInteger: '3' + my_model_coef_0_86: + SecretInteger: '3' + my_input_178: + SecretInteger: '3' + my_model_coef_0_336: + SecretInteger: '3' + my_input_185: + SecretInteger: '3' + my_input_187: + SecretInteger: '3' + my_input_11: + SecretInteger: '3' + my_model_coef_0_275: + SecretInteger: '3' + my_model_coef_0_54: + SecretInteger: '3' + my_model_coef_0_5: + SecretInteger: '3' + my_model_coef_0_335: + SecretInteger: '3' + my_input_413: + SecretInteger: '3' + my_input_26: + SecretInteger: '3' + my_model_coef_0_231: + SecretInteger: '3' + my_model_coef_0_486: + SecretInteger: '3' + my_input_125: + SecretInteger: '3' + my_model_coef_0_225: + SecretInteger: '3' + my_model_coef_0_295: + SecretInteger: '3' + my_model_coef_0_282: + SecretInteger: '3' + my_model_coef_0_289: + SecretInteger: '3' + my_model_coef_0_95: + SecretInteger: '3' + my_model_coef_0_411: + SecretInteger: '3' + my_input_229: + SecretInteger: '3' + my_input_165: + SecretInteger: '3' + my_model_coef_0_27: + SecretInteger: '3' + my_model_coef_0_250: + SecretInteger: '3' + my_input_223: + SecretInteger: '3' + my_input_6: + SecretInteger: '3' + my_input_63: + SecretInteger: '3' + my_model_coef_0_152: + SecretInteger: '3' + my_input_188: + SecretInteger: '3' + my_input_333: + SecretInteger: '3' + my_model_coef_0_277: + SecretInteger: '3' + my_model_coef_0_178: + SecretInteger: '3' + my_input_109: + SecretInteger: '3' + my_model_coef_0_330: + SecretInteger: '3' + my_model_coef_0_386: + SecretInteger: '3' + my_input_169: + SecretInteger: '3' + my_model_coef_0_154: + SecretInteger: '3' + my_model_coef_0_160: + SecretInteger: '3' + my_model_coef_0_99: + SecretInteger: '3' + my_input_294: + SecretInteger: '3' + my_model_coef_0_451: + SecretInteger: '3' + my_input_280: + SecretInteger: '3' + my_model_coef_0_398: + SecretInteger: '3' + my_input_394: + SecretInteger: '3' + my_model_coef_0_497: + SecretInteger: '3' + my_input_286: + SecretInteger: '3' + my_input_387: + SecretInteger: '3' + my_input_199: + SecretInteger: '3' + my_model_coef_0_139: + SecretInteger: '3' + my_model_coef_0_259: + SecretInteger: '3' + my_model_coef_0_132: + SecretInteger: '3' + my_model_coef_0_130: + SecretInteger: '3' + my_model_coef_0_2: + SecretInteger: '3' + my_model_coef_0_125: + SecretInteger: '3' + my_model_coef_0_215: + SecretInteger: '3' + my_model_coef_0_465: + SecretInteger: '3' + my_model_coef_0_495: + SecretInteger: '3' + my_model_coef_0_77: + SecretInteger: '3' + my_model_coef_0_122: + SecretInteger: '3' + my_model_coef_0_366: + SecretInteger: '3' + my_model_coef_0_203: + SecretInteger: '3' + my_model_coef_0_74: + SecretInteger: '3' + my_model_coef_0_292: + SecretInteger: '3' + my_input_53: + SecretInteger: '3' + my_model_coef_0_300: + SecretInteger: '3' + my_model_coef_0_298: + SecretInteger: '3' + my_input_39: + SecretInteger: '3' + my_input_46: + SecretInteger: '3' + my_input_136: + SecretInteger: '3' + my_input_9: + SecretInteger: '3' + my_input_83: + SecretInteger: '3' + my_input_478: + SecretInteger: '3' + my_model_coef_0_53: + SecretInteger: '3' + my_model_coef_0_199: + SecretInteger: '3' + my_model_coef_0_458: + SecretInteger: '3' + my_model_coef_0_387: + SecretInteger: '3' + my_model_coef_0_310: + SecretInteger: '3' + my_input_272: + SecretInteger: '3' + my_model_coef_0_273: + SecretInteger: '3' + my_model_coef_0_93: + SecretInteger: '3' + my_model_coef_0_70: + SecretInteger: '3' + my_input_50: + SecretInteger: '3' + my_input_353: + SecretInteger: '3' + my_input_442: + SecretInteger: '3' + my_input_379: + SecretInteger: '3' + my_model_coef_0_434: + SecretInteger: '3' + my_input_93: + SecretInteger: '3' + my_input_203: + SecretInteger: '3' + my_input_64: + SecretInteger: '3' + my_model_coef_0_499: + SecretInteger: '3' + my_input_142: + SecretInteger: '3' + my_input_182: + SecretInteger: '3' + my_input_115: + SecretInteger: '3' + my_input_117: + SecretInteger: '3' + my_model_coef_0_104: + SecretInteger: '3' + my_model_coef_0_156: + SecretInteger: '3' + my_model_coef_0_293: + SecretInteger: '3' + my_input_155: + SecretInteger: '3' + my_input_148: + SecretInteger: '3' + my_input_476: + SecretInteger: '3' + my_model_coef_0_408: + SecretInteger: '3' + my_model_coef_0_322: + SecretInteger: '3' + my_model_coef_0_433: + SecretInteger: '3' + my_model_coef_0_97: + SecretInteger: '3' + my_input_116: + SecretInteger: '3' + my_model_coef_0_186: + SecretInteger: '3' + my_model_coef_0_439: + SecretInteger: '3' + my_input_153: + SecretInteger: '3' + my_model_coef_0_187: + SecretInteger: '3' + my_input_248: + SecretInteger: '3' + my_input_292: + SecretInteger: '3' + my_input_25: + SecretInteger: '3' + my_model_coef_0_105: + SecretInteger: '3' + my_input_135: + SecretInteger: '3' + my_input_427: + SecretInteger: '3' + my_input_85: + SecretInteger: '3' + my_model_coef_0_422: + SecretInteger: '3' + my_model_coef_0_89: + SecretInteger: '3' + my_input_147: + SecretInteger: '3' + my_input_268: + SecretInteger: '3' + my_model_coef_0_384: + SecretInteger: '3' + my_model_coef_0_480: + SecretInteger: '3' + my_model_coef_0_308: + SecretInteger: '3' + my_model_coef_0_354: + SecretInteger: '3' + my_input_132: + SecretInteger: '3' + my_input_202: + SecretInteger: '3' + my_input_357: + SecretInteger: '3' + my_input_320: + SecretInteger: '3' + my_input_209: + SecretInteger: '3' + my_model_coef_0_172: + SecretInteger: '3' + my_input_66: + SecretInteger: '3' + my_input_124: + SecretInteger: '3' + my_input_373: + SecretInteger: '3' + my_model_coef_0_479: + SecretInteger: '3' + my_model_coef_0_146: + SecretInteger: '3' + my_model_coef_0_466: + SecretInteger: '3' + my_model_coef_0_8: + SecretInteger: '3' + my_input_356: + SecretInteger: '3' + my_input_371: + SecretInteger: '3' + my_input_378: + SecretInteger: '3' + my_model_coef_0_121: + SecretInteger: '3' + my_model_coef_0_170: + SecretInteger: '3' + my_input_470: + SecretInteger: '3' + my_model_coef_0_325: + SecretInteger: '3' + my_model_coef_0_457: + SecretInteger: '3' + my_input_101: + SecretInteger: '3' + my_model_coef_0_52: + SecretInteger: '3' + my_model_coef_0_270: + SecretInteger: '3' + my_model_coef_0_26: + SecretInteger: '3' + my_model_coef_0_290: + SecretInteger: '3' + my_input_498: + SecretInteger: '3' + my_model_coef_0_165: + SecretInteger: '3' + my_input_449: + SecretInteger: '3' + my_input_376: + SecretInteger: '3' + my_model_coef_0_339: + SecretInteger: '3' + my_input_316: + SecretInteger: '3' + my_model_coef_0_188: + SecretInteger: '3' + my_model_coef_0_413: + SecretInteger: '3' + my_model_coef_0_338: + SecretInteger: '3' + my_model_coef_0_10: + SecretInteger: '3' + my_model_coef_0_469: + SecretInteger: '3' + my_model_coef_0_276: + SecretInteger: '3' + my_model_coef_0_155: + SecretInteger: '3' + my_model_coef_0_115: + SecretInteger: '3' + my_input_186: + SecretInteger: '3' + my_input_446: + SecretInteger: '3' + my_model_coef_0_173: + SecretInteger: '3' + my_model_coef_0_405: + SecretInteger: '3' + my_input_291: + SecretInteger: '3' + my_model_coef_0_321: + SecretInteger: '3' + my_model_coef_0_38: + SecretInteger: '3' + my_model_coef_0_176: + SecretInteger: '3' + my_model_coef_0_49: + SecretInteger: '3' + my_model_coef_0_385: + SecretInteger: '3' + my_model_coef_0_267: + SecretInteger: '3' + my_model_coef_0_14: + SecretInteger: '3' + my_model_coef_0_48: + SecretInteger: '3' + my_model_coef_0_312: + SecretInteger: '3' + my_input_430: + SecretInteger: '3' + my_model_coef_0_373: + SecretInteger: '3' + my_model_coef_0_443: + SecretInteger: '3' + my_model_coef_0_327: + SecretInteger: '3' + my_model_coef_0_453: + SecretInteger: '3' + my_input_35: + SecretInteger: '3' + my_input_208: + SecretInteger: '3' + my_input_228: + SecretInteger: '3' + my_model_coef_0_302: + SecretInteger: '3' + my_model_coef_0_491: + SecretInteger: '3' + my_model_coef_0_34: + SecretInteger: '3' + my_model_coef_0_305: + SecretInteger: '3' + my_model_coef_0_320: + SecretInteger: '3' + my_input_380: + SecretInteger: '3' + my_model_coef_0_47: + SecretInteger: '3' + my_input_419: + SecretInteger: '3' + my_model_coef_0_484: + SecretInteger: '3' + my_input_70: + SecretInteger: '3' + my_input_218: + SecretInteger: '3' + my_model_coef_0_474: + SecretInteger: '3' + my_input_257: + SecretInteger: '3' + my_input_361: + SecretInteger: '3' + my_input_219: + SecretInteger: '3' + my_model_coef_0_331: + SecretInteger: '3' + my_input_37: + SecretInteger: '3' + my_input_456: + SecretInteger: '3' + my_model_coef_0_252: + SecretInteger: '3' + my_input_57: + SecretInteger: '3' + my_input_91: + SecretInteger: '3' + my_model_coef_0_446: + SecretInteger: '3' + my_model_coef_0_184: + SecretInteger: '3' + my_input_354: + SecretInteger: '3' + my_model_coef_0_410: + SecretInteger: '3' + my_input_10: + SecretInteger: '3' + my_input_172: + SecretInteger: '3' + my_model_coef_0_460: + SecretInteger: '3' + my_model_coef_0_449: + SecretInteger: '3' + my_input_76: + SecretInteger: '3' + my_input_61: + SecretInteger: '3' + my_input_433: + SecretInteger: '3' + my_model_coef_0_149: + SecretInteger: '3' + my_model_coef_0_382: + SecretInteger: '3' + my_model_coef_0_418: + SecretInteger: '3' + my_input_222: + SecretInteger: '3' + my_model_coef_0_353: + SecretInteger: '3' + my_input_54: + SecretInteger: '3' + my_input_438: + SecretInteger: '3' + my_input_309: + SecretInteger: '3' + my_input_0: + SecretInteger: '3' + my_input_235: + SecretInteger: '3' + my_model_coef_0_50: + SecretInteger: '3' + my_model_coef_0_221: + SecretInteger: '3' + my_model_coef_0_106: + SecretInteger: '3' + my_input_340: + SecretInteger: '3' + my_model_coef_0_46: + SecretInteger: '3' + my_input_262: + SecretInteger: '3' + my_input_448: + SecretInteger: '3' + my_input_20: + SecretInteger: '3' + my_model_coef_0_343: + SecretInteger: '3' + my_model_coef_0_416: + SecretInteger: '3' + my_input_149: + SecretInteger: '3' + my_model_coef_0_169: + SecretInteger: '3' + my_model_coef_0_233: + SecretInteger: '3' + my_model_coef_0_123: + SecretInteger: '3' + my_input_304: + SecretInteger: '3' + my_input_36: + SecretInteger: '3' + my_input_65: + SecretInteger: '3' + my_input_359: + SecretInteger: '3' + my_input_337: + SecretInteger: '3' + my_model_coef_0_219: + SecretInteger: '3' + my_model_coef_0_92: + SecretInteger: '3' + my_input_154: + SecretInteger: '3' + my_model_coef_0_377: + SecretInteger: '3' + my_model_coef_0_255: + SecretInteger: '3' + my_input_497: + SecretInteger: '3' + my_model_coef_0_60: + SecretInteger: '3' + my_model_coef_0_344: + SecretInteger: '3' + my_model_coef_0_445: + SecretInteger: '3' + my_input_112: + SecretInteger: '3' + my_input_251: + SecretInteger: '3' + my_input_418: + SecretInteger: '3' + my_input_275: + SecretInteger: '3' + my_model_coef_0_214: + SecretInteger: '3' + my_input_224: + SecretInteger: '3' + my_input_459: + SecretInteger: '3' + my_model_coef_0_296: + SecretInteger: '3' + my_input_440: + SecretInteger: '3' + my_input_58: + SecretInteger: '3' + my_input_239: + SecretInteger: '3' + my_input_246: + SecretInteger: '3' + my_input_271: + SecretInteger: '3' + my_model_coef_0_482: + SecretInteger: '3' + my_model_coef_0_44: + SecretInteger: '3' + my_input_346: + SecretInteger: '3' + my_model_coef_0_109: + SecretInteger: '3' + my_model_coef_0_72: + SecretInteger: '3' + my_model_coef_0_328: + SecretInteger: '3' + my_model_coef_0_190: + SecretInteger: '3' + my_input_143: + SecretInteger: '3' + my_model_coef_0_30: + SecretInteger: '3' + my_model_coef_0_68: + SecretInteger: '3' + my_model_coef_0_406: + SecretInteger: '3' + my_model_coef_0_265: + SecretInteger: '3' + my_input_129: + SecretInteger: '3' + my_input_363: + SecretInteger: '3' + my_input_439: + SecretInteger: '3' + my_input_99: + SecretInteger: '3' + my_model_coef_0_222: + SecretInteger: '3' + my_model_coef_0_475: + SecretInteger: '3' + my_model_coef_0_65: + SecretInteger: '3' + my_model_coef_0_128: + SecretInteger: '3' + my_input_402: + SecretInteger: '3' + my_model_coef_0_315: + SecretInteger: '3' + my_input_403: + SecretInteger: '3' + my_input_481: + SecretInteger: '3' + my_model_coef_0_162: + SecretInteger: '3' + my_model_coef_0_266: + SecretInteger: '3' + my_model_coef_0_461: + SecretInteger: '3' + my_input_18: + SecretInteger: '3' + my_input_97: + SecretInteger: '3' + my_model_coef_0_459: + SecretInteger: '3' + my_input_130: + SecretInteger: '3' + my_input_295: + SecretInteger: '3' + my_model_coef_0_396: + SecretInteger: '3' + my_model_coef_0_239: + SecretInteger: '3' + my_model_coef_0_318: + SecretInteger: '3' + my_model_coef_0_324: + SecretInteger: '3' + my_model_coef_0_332: + SecretInteger: '3' + my_input_28: + SecretInteger: '3' + my_input_111: + SecretInteger: '3' + my_input_312: + SecretInteger: '3' + my_input_40: + SecretInteger: '3' + my_input_214: + SecretInteger: '3' + my_model_coef_0_51: + SecretInteger: '3' + my_model_coef_0_75: + SecretInteger: '3' + my_model_coef_0_345: + SecretInteger: '3' + my_model_coef_0_249: + SecretInteger: '3' + my_input_398: + SecretInteger: '3' + my_model_coef_0_269: + SecretInteger: '3' + my_model_coef_0_196: + SecretInteger: '3' + my_input_297: + SecretInteger: '3' + my_model_coef_0_450: + SecretInteger: '3' + my_model_coef_0_183: + SecretInteger: '3' + my_input_263: + SecretInteger: '3' + my_input_410: + SecretInteger: '3' + my_input_367: + SecretInteger: '3' + my_model_coef_0_496: + SecretInteger: '3' + my_input_107: + SecretInteger: '3' + my_model_coef_0_19: + SecretInteger: '3' + my_input_490: + SecretInteger: '3' + my_model_coef_0_218: + SecretInteger: '3' + my_model_coef_0_261: + SecretInteger: '3' + my_model_coef_0_370: + SecretInteger: '3' + my_input_479: + SecretInteger: '3' + my_input_401: + SecretInteger: '3' + my_input_423: + SecretInteger: '3' + my_input_95: + SecretInteger: '3' + my_model_coef_0_456: + SecretInteger: '3' + my_model_coef_0_189: + SecretInteger: '3' + my_model_coef_0_347: + SecretInteger: '3' + my_input_273: + SecretInteger: '3' + my_input_465: + SecretInteger: '3' + my_model_coef_0_356: + SecretInteger: '3' + my_input_311: + SecretInteger: '3' + my_model_coef_0_78: + SecretInteger: '3' + my_input_345: + SecretInteger: '3' + my_model_coef_0_63: + SecretInteger: '3' + my_input_396: + SecretInteger: '3' + my_model_coef_0_111: + SecretInteger: '3' + my_input_192: + SecretInteger: '3' + my_model_coef_0_1: + SecretInteger: '3' + my_input_33: + SecretInteger: '3' + my_model_coef_0_471: + SecretInteger: '3' + my_input_80: + SecretInteger: '3' + my_input_281: + SecretInteger: '3' + my_model_coef_0_3: + SecretInteger: '3' + my_model_coef_0_417: + SecretInteger: '3' + my_model_coef_0_462: + SecretInteger: '3' + my_model_coef_0_224: + SecretInteger: '3' + my_input_437: + SecretInteger: '3' + my_input_386: + SecretInteger: '3' + my_input_27: + SecretInteger: '3' + my_input_166: + SecretInteger: '3' + my_input_279: + SecretInteger: '3' + my_model_coef_0_197: + SecretInteger: '3' + my_model_coef_0_369: + SecretInteger: '3' + my_model_coef_0_133: + SecretInteger: '3' + my_input_141: + SecretInteger: '3' + my_model_coef_0_372: + SecretInteger: '3' + my_input_451: + SecretInteger: '3' + my_model_coef_0_415: + SecretInteger: '3' + my_model_coef_0_455: + SecretInteger: '3' + my_input_157: + SecretInteger: '3' + my_model_coef_0_487: + SecretInteger: '3' + my_input_210: + SecretInteger: '3' + my_model_coef_0_319: + SecretInteger: '3' + my_input_301: + SecretInteger: '3' + my_input_68: + SecretInteger: '3' + my_model_coef_0_431: + SecretInteger: '3' + my_input_234: + SecretInteger: '3' + my_model_coef_0_448: + SecretInteger: '3' + my_input_285: + SecretInteger: '3' + my_input_184: + SecretInteger: '3' + my_model_coef_0_228: + SecretInteger: '3' + my_input_360: + SecretInteger: '3' + my_input_436: + SecretInteger: '3' + my_input_331: + SecretInteger: '3' + my_model_coef_0_364: + SecretInteger: '3' + my_model_coef_0_317: + SecretInteger: '3' + my_model_coef_0_402: + SecretInteger: '3' + my_input_17: + SecretInteger: '3' + my_model_coef_0_61: + SecretInteger: '3' + my_input_351: + SecretInteger: '3' + my_input_370: + SecretInteger: '3' + my_input_429: + SecretInteger: '3' + my_input_393: + SecretInteger: '3' + my_input_211: + SecretInteger: '3' + my_model_coef_0_36: + SecretInteger: '3' + my_input_108: + SecretInteger: '3' + my_model_coef_0_278: + SecretInteger: '3' + my_model_coef_0_18: + SecretInteger: '3' + my_model_coef_0_84: + SecretInteger: '3' + my_model_coef_0_467: + SecretInteger: '3' + my_input_193: + SecretInteger: '3' + my_input_290: + SecretInteger: '3' + my_input_104: + SecretInteger: '3' + my_model_coef_0_490: + SecretInteger: '3' + my_input_78: + SecretInteger: '3' + my_input_457: + SecretInteger: '3' + my_input_238: + SecretInteger: '3' + my_input_259: + SecretInteger: '3' + my_model_coef_0_297: + SecretInteger: '3' + my_input_283: + SecretInteger: '3' + my_input_198: + SecretInteger: '3' + my_model_coef_0_195: + SecretInteger: '3' + my_model_coef_0_299: + SecretInteger: '3' + my_model_coef_0_257: + SecretInteger: '3' + my_model_coef_0_287: + SecretInteger: '3' + my_input_261: + SecretInteger: '3' + my_input_344: + SecretInteger: '3' + my_input_332: + SecretInteger: '3' + my_model_coef_0_419: + SecretInteger: '3' + my_model_coef_0_98: + SecretInteger: '3' + my_input_105: + SecretInteger: '3' + my_input_171: + SecretInteger: '3' + my_input_152: + SecretInteger: '3' + my_model_coef_0_237: + SecretInteger: '3' + my_model_coef_0_301: + SecretInteger: '3' + my_input_408: + SecretInteger: '3' + my_input_335: + SecretInteger: '3' + my_model_coef_0_207: + SecretInteger: '3' + my_model_coef_0_380: + SecretInteger: '3' + my_model_coef_0_393: + SecretInteger: '3' + my_input_317: + SecretInteger: '3' + my_input_163: + SecretInteger: '3' + my_input_415: + SecretInteger: '3' + my_input_467: + SecretInteger: '3' + my_input_21: + SecretInteger: '3' + my_input_88: + SecretInteger: '3' + my_model_coef_0_242: + SecretInteger: '3' + my_input_308: + SecretInteger: '3' + my_model_coef_0_7: + SecretInteger: '3' + my_model_coef_0_375: + SecretInteger: '3' + my_model_coef_0_285: + SecretInteger: '3' + my_input_215: + SecretInteger: '3' + my_input_12: + SecretInteger: '3' + my_input_343: + SecretInteger: '3' + my_model_coef_0_35: + SecretInteger: '3' + my_input_151: + SecretInteger: '3' + my_model_coef_0_271: + SecretInteger: '3' + my_input_397: + SecretInteger: '3' + my_input_389: + SecretInteger: '3' + my_input_425: + SecretInteger: '3' + my_input_388: + SecretInteger: '3' + my_model_coef_0_454: + SecretInteger: '3' + my_input_77: + SecretInteger: '3' + my_input_201: + SecretInteger: '3' + my_model_coef_0_407: + SecretInteger: '3' + my_input_51: + SecretInteger: '3' + my_input_334: + SecretInteger: '3' + my_model_coef_0_437: + SecretInteger: '3' + my_input_14: + SecretInteger: '3' + my_model_coef_0_206: + SecretInteger: '3' + my_model_coef_0_412: + SecretInteger: '3' + my_input_44: + SecretInteger: '3' + my_input_30: + SecretInteger: '3' + my_model_coef_0_71: + SecretInteger: '3' + my_model_coef_0_124: + SecretInteger: '3' + my_model_coef_0_286: + SecretInteger: '3' + my_input_2: + SecretInteger: '3' + my_model_coef_0_140: + SecretInteger: '3' + my_input_197: + SecretInteger: '3' + my_model_coef_0_66: + SecretInteger: '3' + my_model_coef_0_144: + SecretInteger: '3' + my_input_131: + SecretInteger: '3' expected_outputs: logit_0: - SecretInteger: "3" + SecretInteger: '3' diff --git a/examples/time_series/main.py b/examples/time_series/main.py index ed58710..fd73e27 100644 --- a/examples/time_series/main.py +++ b/examples/time_series/main.py @@ -3,7 +3,7 @@ import os import sys -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))) +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import asyncio @@ -12,39 +12,56 @@ import numpy as np import pandas as pd import py_nillion_client as nillion +from common.utils import compute, store_program, store_secrets +from cosmpy.aerial.client import LedgerClient +from cosmpy.aerial.wallet import LocalWallet +from cosmpy.crypto.keypairs import PrivateKey from dotenv import load_dotenv -# Import helper functions for creating nillion client and getting keys -from nillion_python_helpers import (create_nillion_client, getNodeKeyFromFile, - getUserKeyFromFile) +from nillion_python_helpers import (create_nillion_client, + create_payments_config) from prophet import Prophet +from py_nillion_client import NodeKey, UserKey -from examples.common.utils import compute, store_program, store_secrets from nada_ai.client import ProphetClient -# Load environment variables from a .env file -load_dotenv() +home = os.getenv("HOME") +load_dotenv(f"{home}/.config/nillion/nillion-devnet.env") -# Main asynchronous function to coordinate the process -async def main(): +async def main() -> None: + """Main nada program""" + cluster_id = os.getenv("NILLION_CLUSTER_ID") - userkey = getUserKeyFromFile(os.getenv("NILLION_USERKEY_PATH_PARTY_1")) - nodekey = getNodeKeyFromFile(os.getenv("NILLION_NODEKEY_PATH_PARTY_1")) + grpc_endpoint = os.getenv("NILLION_NILCHAIN_GRPC") + chain_id = os.getenv("NILLION_NILCHAIN_CHAIN_ID") + seed = "my_seed" + userkey = UserKey.from_seed((seed)) + nodekey = NodeKey.from_seed((seed)) client = create_nillion_client(userkey, nodekey) party_id = client.party_id user_id = client.user_id - party_names = na_client.parties(2) - program_name = "main" - program_mir_path = f"./target/{program_name}.nada.bin" - if not os.path.exists("bench"): - os.mkdir("bench") - - na.set_log_scale(50) + party_names = na_client.parties(2) + program_name = "time_series" + program_mir_path = f"target/{program_name}.nada.bin" + + # Configure payments + payments_config = create_payments_config(chain_id, grpc_endpoint) + payments_client = LedgerClient(payments_config) + payments_wallet = LocalWallet( + PrivateKey(bytes.fromhex(os.getenv("NILLION_NILCHAIN_PRIVATE_KEY_0"))), + prefix="nillion", + ) - # Store the program + # Store program program_id = await store_program( - client, user_id, cluster_id, program_name, program_mir_path + client, + payments_wallet, + payments_client, + user_id, + cluster_id, + program_name, + program_mir_path, ) # Train prophet model @@ -60,12 +77,20 @@ async def main(): # Create and store model secrets via ModelClient model_client = ProphetClient(fit_model) - model_secrets = nillion.Secrets( + model_secrets = nillion.NadaValues( model_client.export_state_as_secrets("my_prophet", na.SecretRational) ) + permissions = nillion.Permissions.default_for_user(client.user_id) + permissions.add_compute_permissions({client.user_id: {program_id}}) model_store_id = await store_secrets( - client, cluster_id, program_id, party_id, party_names[0], model_secrets + client, + payments_wallet, + payments_client, + cluster_id, + model_secrets, + 1, + permissions, ) # Store inputs to perform inference for @@ -80,30 +105,42 @@ async def main(): na_client.array(inference_ds["t"].to_numpy(), "t", na.SecretRational) ) - input_secrets = nillion.Secrets(my_input) + input_secrets = nillion.NadaValues(my_input) data_store_id = await store_secrets( - client, cluster_id, program_id, party_id, party_names[1], input_secrets + client, + payments_wallet, + payments_client, + cluster_id, + input_secrets, + 1, + permissions, ) # Set up the compute bindings for the parties compute_bindings = nillion.ProgramBindings(program_id) - [ + + for party_name in party_names: compute_bindings.add_input_party(party_name, party_id) - for party_name in party_names - ] - compute_bindings.add_output_party(party_names[1], party_id) + compute_bindings.add_output_party(party_names[-1], party_id) print(f"Computing using program {program_id}") print(f"Use secret store_id: {model_store_id} {data_store_id}") - # Perform the computation and return the result + # Create a computation time secret to use + computation_time_secrets = nillion.NadaValues({}) + + # Compute, passing all params including the receipt that shows proof of payment result = await compute( client, + payments_wallet, + payments_client, + program_id, cluster_id, compute_bindings, [model_store_id, data_store_id], - nillion.Secrets({}), + computation_time_secrets, + verbose=True, ) # Sort & rescale the obtained results by the quantization scale @@ -115,13 +152,12 @@ async def main(): ) ] - print(f"🖥️ The result is {outputs}") + print(f"🖥️ The processed result is {outputs} @ {na.get_log_scale()}-bit precision") expected = fit_model.predict(inference_ds)["yhat"].to_numpy() - print(f"🖥️ VS expected plain-text result {expected}") - return result + + print(f"🖥️ VS expected result {expected}") -# Run the main function if the script is executed directly if __name__ == "__main__": asyncio.run(main()) diff --git a/examples/time_series/src/time_series.py b/examples/time_series/src/time_series.py index d3eca93..7ac7de6 100644 --- a/examples/time_series/src/time_series.py +++ b/examples/time_series/src/time_series.py @@ -5,8 +5,6 @@ def nada_main(): - na.set_log_scale(50) - # Step 1: We use Nada NumPy wrapper to create "Party0" and "Party1" parties = na.parties(2) diff --git a/examples/time_series/tests/time_series.yaml b/examples/time_series/tests/time_series.yaml index b0e2b98..bad8616 100644 --- a/examples/time_series/tests/time_series.yaml +++ b/examples/time_series/tests/time_series.yaml @@ -1,192 +1,189 @@ ---- program: time_series inputs: - secrets: - my_prophet_changepoints_t_8: - SecretInteger: "3" - my_prophet_changepoints_t_11: - SecretInteger: "3" - floor_17: - SecretInteger: "3" - floor_4: - SecretInteger: "3" - my_prophet_beta_0_3: - SecretInteger: "3" - t_7: - SecretInteger: "3" - t_3: - SecretInteger: "3" - my_prophet_beta_0_0: - SecretInteger: "3" - t_1: - SecretInteger: "3" - floor_5: - SecretInteger: "3" - my_prophet_changepoints_t_6: - SecretInteger: "3" - floor_16: - SecretInteger: "3" - my_prophet_y_scale_0: - SecretInteger: "3" - floor_2: - SecretInteger: "3" - floor_19: - SecretInteger: "3" - my_prophet_beta_0_5: - SecretInteger: "3" - my_prophet_changepoints_t_7: - SecretInteger: "3" - my_prophet_delta_0_5: - SecretInteger: "3" - t_8: - SecretInteger: "3" - floor_18: - SecretInteger: "3" - my_prophet_beta_0_2: - SecretInteger: "3" - floor_10: - SecretInteger: "3" - t_12: - SecretInteger: "3" - my_prophet_delta_0_4: - SecretInteger: "3" - t_14: - SecretInteger: "3" - t_16: - SecretInteger: "3" - t_2: - SecretInteger: "3" - t_5: - SecretInteger: "3" - floor_11: - SecretInteger: "3" - my_prophet_delta_0_2: - SecretInteger: "3" - my_prophet_delta_0_7: - SecretInteger: "3" - my_prophet_k_0_0: - SecretInteger: "3" - my_prophet_changepoints_t_1: - SecretInteger: "3" - t_13: - SecretInteger: "3" - t_18: - SecretInteger: "3" - my_prophet_delta_0_0: - SecretInteger: "3" - my_prophet_changepoints_t_9: - SecretInteger: "3" - floor_13: - SecretInteger: "3" - t_15: - SecretInteger: "3" - t_17: - SecretInteger: "3" - my_prophet_delta_0_6: - SecretInteger: "3" - t_10: - SecretInteger: "3" - my_prophet_changepoints_t_10: - SecretInteger: "3" - my_prophet_beta_0_4: - SecretInteger: "3" - floor_3: - SecretInteger: "3" - my_prophet_changepoints_t_2: - SecretInteger: "3" - t_9: - SecretInteger: "3" - floor_9: - SecretInteger: "3" - t_11: - SecretInteger: "3" - my_prophet_delta_0_3: - SecretInteger: "3" - my_prophet_delta_0_10: - SecretInteger: "3" - my_prophet_changepoints_t_3: - SecretInteger: "3" - floor_1: - SecretInteger: "3" - my_prophet_delta_0_8: - SecretInteger: "3" - t_19: - SecretInteger: "3" - floor_7: - SecretInteger: "3" - floor_0: - SecretInteger: "3" - floor_14: - SecretInteger: "3" - floor_8: - SecretInteger: "3" - my_prophet_changepoints_t_4: - SecretInteger: "3" - floor_12: - SecretInteger: "3" - my_prophet_changepoints_t_0: - SecretInteger: "3" - my_prophet_delta_0_9: - SecretInteger: "3" - my_prophet_m_0_0: - SecretInteger: "3" - my_prophet_changepoints_t_5: - SecretInteger: "3" - t_6: - SecretInteger: "3" - my_prophet_beta_0_1: - SecretInteger: "3" - t_0: - SecretInteger: "3" - floor_15: - SecretInteger: "3" - t_4: - SecretInteger: "3" - my_prophet_delta_0_11: - SecretInteger: "3" - my_prophet_delta_0_1: - SecretInteger: "3" - floor_6: - SecretInteger: "3" - public_variables: {} + my_prophet_changepoints_t_8: + SecretInteger: '3' + my_prophet_changepoints_t_11: + SecretInteger: '3' + floor_17: + SecretInteger: '3' + floor_4: + SecretInteger: '3' + my_prophet_beta_0_3: + SecretInteger: '3' + t_7: + SecretInteger: '3' + t_3: + SecretInteger: '3' + my_prophet_beta_0_0: + SecretInteger: '3' + t_1: + SecretInteger: '3' + floor_5: + SecretInteger: '3' + my_prophet_changepoints_t_6: + SecretInteger: '3' + floor_16: + SecretInteger: '3' + my_prophet_y_scale_0: + SecretInteger: '3' + floor_2: + SecretInteger: '3' + floor_19: + SecretInteger: '3' + my_prophet_beta_0_5: + SecretInteger: '3' + my_prophet_changepoints_t_7: + SecretInteger: '3' + my_prophet_delta_0_5: + SecretInteger: '3' + t_8: + SecretInteger: '3' + floor_18: + SecretInteger: '3' + my_prophet_beta_0_2: + SecretInteger: '3' + floor_10: + SecretInteger: '3' + t_12: + SecretInteger: '3' + my_prophet_delta_0_4: + SecretInteger: '3' + t_14: + SecretInteger: '3' + t_16: + SecretInteger: '3' + t_2: + SecretInteger: '3' + t_5: + SecretInteger: '3' + floor_11: + SecretInteger: '3' + my_prophet_delta_0_2: + SecretInteger: '3' + my_prophet_delta_0_7: + SecretInteger: '3' + my_prophet_k_0_0: + SecretInteger: '3' + my_prophet_changepoints_t_1: + SecretInteger: '3' + t_13: + SecretInteger: '3' + t_18: + SecretInteger: '3' + my_prophet_delta_0_0: + SecretInteger: '3' + my_prophet_changepoints_t_9: + SecretInteger: '3' + floor_13: + SecretInteger: '3' + t_15: + SecretInteger: '3' + t_17: + SecretInteger: '3' + my_prophet_delta_0_6: + SecretInteger: '3' + t_10: + SecretInteger: '3' + my_prophet_changepoints_t_10: + SecretInteger: '3' + my_prophet_beta_0_4: + SecretInteger: '3' + floor_3: + SecretInteger: '3' + my_prophet_changepoints_t_2: + SecretInteger: '3' + t_9: + SecretInteger: '3' + floor_9: + SecretInteger: '3' + t_11: + SecretInteger: '3' + my_prophet_delta_0_3: + SecretInteger: '3' + my_prophet_delta_0_10: + SecretInteger: '3' + my_prophet_changepoints_t_3: + SecretInteger: '3' + floor_1: + SecretInteger: '3' + my_prophet_delta_0_8: + SecretInteger: '3' + t_19: + SecretInteger: '3' + floor_7: + SecretInteger: '3' + floor_0: + SecretInteger: '3' + floor_14: + SecretInteger: '3' + floor_8: + SecretInteger: '3' + my_prophet_changepoints_t_4: + SecretInteger: '3' + floor_12: + SecretInteger: '3' + my_prophet_changepoints_t_0: + SecretInteger: '3' + my_prophet_delta_0_9: + SecretInteger: '3' + my_prophet_m_0_0: + SecretInteger: '3' + my_prophet_changepoints_t_5: + SecretInteger: '3' + t_6: + SecretInteger: '3' + my_prophet_beta_0_1: + SecretInteger: '3' + t_0: + SecretInteger: '3' + floor_15: + SecretInteger: '3' + t_4: + SecretInteger: '3' + my_prophet_delta_0_11: + SecretInteger: '3' + my_prophet_delta_0_1: + SecretInteger: '3' + floor_6: + SecretInteger: '3' expected_outputs: my_output_1: - SecretInteger: "3" + SecretInteger: '2' my_output_16: - SecretInteger: "3" + SecretInteger: '2' my_output_17: - SecretInteger: "3" + SecretInteger: '1' my_output_14: - SecretInteger: "3" + SecretInteger: '1' my_output_19: - SecretInteger: "3" + SecretInteger: '1' my_output_3: - SecretInteger: "3" + SecretInteger: '1' my_output_2: - SecretInteger: "3" + SecretInteger: '2' my_output_0: - SecretInteger: "3" + SecretInteger: '1' my_output_11: - SecretInteger: "3" + SecretInteger: '2' my_output_10: - SecretInteger: "3" + SecretInteger: '1' my_output_5: - SecretInteger: "3" + SecretInteger: '1' my_output_6: - SecretInteger: "3" + SecretInteger: '1' my_output_7: - SecretInteger: "3" + SecretInteger: '1' my_output_12: - SecretInteger: "3" + SecretInteger: '1' my_output_9: - SecretInteger: "3" + SecretInteger: '2' my_output_4: - SecretInteger: "3" + SecretInteger: '2' my_output_8: - SecretInteger: "3" + SecretInteger: '2' my_output_15: - SecretInteger: "3" + SecretInteger: '2' my_output_18: - SecretInteger: "3" + SecretInteger: '2' my_output_13: - SecretInteger: "3" + SecretInteger: '1' diff --git a/nada_ai/client/model_client.py b/nada_ai/client/model_client.py index a1bff7f..ceaf4a6 100644 --- a/nada_ai/client/model_client.py +++ b/nada_ai/client/model_client.py @@ -3,7 +3,6 @@ from abc import ABC, ABCMeta from typing import Any, Dict, Sequence -import nada_numpy as na import nada_numpy.client as na_client import numpy as np import torch @@ -54,9 +53,6 @@ def export_state_as_secrets( Returns: Dict[str, NillionType]: Dict of Nillion secret types that represents model state. """ - if nada_type not in (na.Rational, na.SecretRational): - raise NotImplementedError("Exporting non-rational state is not supported") - state_secrets = {} for state_layer_name, state_layer_weight in self.state_dict.items(): layer_name = f"{name}_{state_layer_name}" diff --git a/nada_ai/nada_typing.py b/nada_ai/nada_typing.py index b238b3e..a919fee 100644 --- a/nada_ai/nada_typing.py +++ b/nada_ai/nada_typing.py @@ -5,9 +5,8 @@ import nada_dsl as dsl import nada_numpy as na # pylint:disable=no-name-in-module -from py_nillion_client import (PublicVariableInteger, - PublicVariableUnsignedInteger, SecretInteger, - SecretUnsignedInteger) +from py_nillion_client import (Integer, SecretInteger, SecretUnsignedInteger, + UnsignedInteger) from sklearn.linear_model import (LinearRegression, LogisticRegression, LogisticRegressionCV) @@ -18,8 +17,8 @@ na.SecretRational, SecretInteger, SecretUnsignedInteger, - PublicVariableInteger, - PublicVariableUnsignedInteger, + Integer, + UnsignedInteger, ] LinearModel = Union[LinearRegression, LogisticRegression, LogisticRegressionCV] diff --git a/nada_ai/nn/modules/conv.py b/nada_ai/nn/modules/conv.py index 32bd7cc..3e43761 100644 --- a/nada_ai/nn/modules/conv.py +++ b/nada_ai/nn/modules/conv.py @@ -97,22 +97,26 @@ def forward(self, x: na.NadaArray) -> na.NadaArray: (batch_size, out_channels, out_height, out_width), x.cleartext_nada_type, ) - for b in range(batch_size): - for oc in range(out_channels): - for i in range(out_height): - for j in range(out_width): - start_i = i * self.stride[0] - start_j = j * self.stride[1] - - receptive_field = x[ - b, - :, - start_i : start_i + kernel_rows, - start_j : start_j + kernel_cols, - ] - output_tensor[b, oc, i, j] = na.sum( - self.weight[oc] * receptive_field - ) + with na.context.UnsafeArithmeticSession(): + for b in range(batch_size): + for oc in range(out_channels): + for i in range(out_height): + for j in range(out_width): + start_i = i * self.stride[0] + start_j = j * self.stride[1] + + receptive_field = x[ + b, + :, + start_i : start_i + kernel_rows, + start_j : start_j + kernel_cols, + ] + output_tensor[b, oc, i, j] = na.sum( + self.weight[oc] * receptive_field + ) + + if x.is_rational: + output_tensor = output_tensor.apply(lambda value: value.rescale_down()) if self.bias is not None: output_tensor += self.bias.reshape(1, out_channels, 1, 1) diff --git a/poetry.lock b/poetry.lock index 22b27f4..5c6daf2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -32,6 +32,146 @@ six = ">=1.12.0" astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] +[[package]] +name = "attrs" +version = "23.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] + +[[package]] +name = "bech32" +version = "1.2.0" +description = "Reference implementation for Bech32 and segwit addresses." +optional = false +python-versions = ">=3.5" +files = [ + {file = "bech32-1.2.0-py3-none-any.whl", hash = "sha256:990dc8e5a5e4feabbdf55207b5315fdd9b73db40be294a19b3752cde9e79d981"}, + {file = "bech32-1.2.0.tar.gz", hash = "sha256:7d6db8214603bd7871fcfa6c0826ef68b85b0abd90fa21c285a9c5e21d2bd899"}, +] + +[[package]] +name = "certifi" +version = "2024.7.4" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + [[package]] name = "cmdstanpy" version = "1.2.4" @@ -128,6 +268,28 @@ mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.8.0)", "types-Pill test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] +[[package]] +name = "cosmpy" +version = "0.9.2" +description = "A library for interacting with the cosmos networks" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "cosmpy-0.9.2-py3-none-any.whl", hash = "sha256:3591311198b08a0aa75340851ca166669974f17ffaa207a8d2cb26504fb0fa19"}, + {file = "cosmpy-0.9.2.tar.gz", hash = "sha256:0f0eb80152f28ef5ee4d846d581d2e34ba2d952900f0e3570cacb84bb376f664"}, +] + +[package.dependencies] +bech32 = "*" +ecdsa = "*" +googleapis-common-protos = "*" +grpcio = "*" +jsonschema = ">=3.2.0,<5" +protobuf = ">=4.21.6,<5.0dev" +pycryptodome = ">=3.18.0,<4.0.0" +python-dateutil = "*" +requests = "*" + [[package]] name = "cycler" version = "0.12.1" @@ -158,6 +320,24 @@ files = [ graph = ["objgraph (>=1.7.2)"] profile = ["gprof2dot (>=2022.7.29)"] +[[package]] +name = "ecdsa" +version = "0.19.0" +description = "ECDSA cryptographic signature library (pure python)" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.6" +files = [ + {file = "ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a"}, + {file = "ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8"}, +] + +[package.dependencies] +six = ">=1.9.0" + +[package.extras] +gmpy = ["gmpy"] +gmpy2 = ["gmpy2"] + [[package]] name = "exceptiongroup" version = "1.2.1" @@ -190,53 +370,53 @@ typing = ["typing-extensions (>=4.8)"] [[package]] name = "fonttools" -version = "4.53.0" +version = "4.53.1" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.53.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:52a6e0a7a0bf611c19bc8ec8f7592bdae79c8296c70eb05917fd831354699b20"}, - {file = "fonttools-4.53.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:099634631b9dd271d4a835d2b2a9e042ccc94ecdf7e2dd9f7f34f7daf333358d"}, - {file = "fonttools-4.53.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e40013572bfb843d6794a3ce076c29ef4efd15937ab833f520117f8eccc84fd6"}, - {file = "fonttools-4.53.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:715b41c3e231f7334cbe79dfc698213dcb7211520ec7a3bc2ba20c8515e8a3b5"}, - {file = "fonttools-4.53.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74ae2441731a05b44d5988d3ac2cf784d3ee0a535dbed257cbfff4be8bb49eb9"}, - {file = "fonttools-4.53.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:95db0c6581a54b47c30860d013977b8a14febc206c8b5ff562f9fe32738a8aca"}, - {file = "fonttools-4.53.0-cp310-cp310-win32.whl", hash = "sha256:9cd7a6beec6495d1dffb1033d50a3f82dfece23e9eb3c20cd3c2444d27514068"}, - {file = "fonttools-4.53.0-cp310-cp310-win_amd64.whl", hash = "sha256:daaef7390e632283051e3cf3e16aff2b68b247e99aea916f64e578c0449c9c68"}, - {file = "fonttools-4.53.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a209d2e624ba492df4f3bfad5996d1f76f03069c6133c60cd04f9a9e715595ec"}, - {file = "fonttools-4.53.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f520d9ac5b938e6494f58a25c77564beca7d0199ecf726e1bd3d56872c59749"}, - {file = "fonttools-4.53.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eceef49f457253000e6a2d0f7bd08ff4e9fe96ec4ffce2dbcb32e34d9c1b8161"}, - {file = "fonttools-4.53.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1f3e34373aa16045484b4d9d352d4c6b5f9f77ac77a178252ccbc851e8b2ee"}, - {file = "fonttools-4.53.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:28d072169fe8275fb1a0d35e3233f6df36a7e8474e56cb790a7258ad822b6fd6"}, - {file = "fonttools-4.53.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4a2a6ba400d386e904fd05db81f73bee0008af37799a7586deaa4aef8cd5971e"}, - {file = "fonttools-4.53.0-cp311-cp311-win32.whl", hash = "sha256:bb7273789f69b565d88e97e9e1da602b4ee7ba733caf35a6c2affd4334d4f005"}, - {file = "fonttools-4.53.0-cp311-cp311-win_amd64.whl", hash = "sha256:9fe9096a60113e1d755e9e6bda15ef7e03391ee0554d22829aa506cdf946f796"}, - {file = "fonttools-4.53.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d8f191a17369bd53a5557a5ee4bab91d5330ca3aefcdf17fab9a497b0e7cff7a"}, - {file = "fonttools-4.53.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:93156dd7f90ae0a1b0e8871032a07ef3178f553f0c70c386025a808f3a63b1f4"}, - {file = "fonttools-4.53.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bff98816cb144fb7b85e4b5ba3888a33b56ecef075b0e95b95bcd0a5fbf20f06"}, - {file = "fonttools-4.53.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:973d030180eca8255b1bce6ffc09ef38a05dcec0e8320cc9b7bcaa65346f341d"}, - {file = "fonttools-4.53.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4ee5a24e281fbd8261c6ab29faa7fd9a87a12e8c0eed485b705236c65999109"}, - {file = "fonttools-4.53.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bd5bc124fae781a4422f61b98d1d7faa47985f663a64770b78f13d2c072410c2"}, - {file = "fonttools-4.53.0-cp312-cp312-win32.whl", hash = "sha256:a239afa1126b6a619130909c8404070e2b473dd2b7fc4aacacd2e763f8597fea"}, - {file = "fonttools-4.53.0-cp312-cp312-win_amd64.whl", hash = "sha256:45b4afb069039f0366a43a5d454bc54eea942bfb66b3fc3e9a2c07ef4d617380"}, - {file = "fonttools-4.53.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:93bc9e5aaa06ff928d751dc6be889ff3e7d2aa393ab873bc7f6396a99f6fbb12"}, - {file = "fonttools-4.53.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2367d47816cc9783a28645bc1dac07f8ffc93e0f015e8c9fc674a5b76a6da6e4"}, - {file = "fonttools-4.53.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:907fa0b662dd8fc1d7c661b90782ce81afb510fc4b7aa6ae7304d6c094b27bce"}, - {file = "fonttools-4.53.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e0ad3c6ea4bd6a289d958a1eb922767233f00982cf0fe42b177657c86c80a8f"}, - {file = "fonttools-4.53.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:73121a9b7ff93ada888aaee3985a88495489cc027894458cb1a736660bdfb206"}, - {file = "fonttools-4.53.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ee595d7ba9bba130b2bec555a40aafa60c26ce68ed0cf509983e0f12d88674fd"}, - {file = "fonttools-4.53.0-cp38-cp38-win32.whl", hash = "sha256:fca66d9ff2ac89b03f5aa17e0b21a97c21f3491c46b583bb131eb32c7bab33af"}, - {file = "fonttools-4.53.0-cp38-cp38-win_amd64.whl", hash = "sha256:31f0e3147375002aae30696dd1dc596636abbd22fca09d2e730ecde0baad1d6b"}, - {file = "fonttools-4.53.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7d6166192dcd925c78a91d599b48960e0a46fe565391c79fe6de481ac44d20ac"}, - {file = "fonttools-4.53.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef50ec31649fbc3acf6afd261ed89d09eb909b97cc289d80476166df8438524d"}, - {file = "fonttools-4.53.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f193f060391a455920d61684a70017ef5284ccbe6023bb056e15e5ac3de11d1"}, - {file = "fonttools-4.53.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba9f09ff17f947392a855e3455a846f9855f6cf6bec33e9a427d3c1d254c712f"}, - {file = "fonttools-4.53.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0c555e039d268445172b909b1b6bdcba42ada1cf4a60e367d68702e3f87e5f64"}, - {file = "fonttools-4.53.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a4788036201c908079e89ae3f5399b33bf45b9ea4514913f4dbbe4fac08efe0"}, - {file = "fonttools-4.53.0-cp39-cp39-win32.whl", hash = "sha256:d1a24f51a3305362b94681120c508758a88f207fa0a681c16b5a4172e9e6c7a9"}, - {file = "fonttools-4.53.0-cp39-cp39-win_amd64.whl", hash = "sha256:1e677bfb2b4bd0e5e99e0f7283e65e47a9814b0486cb64a41adf9ef110e078f2"}, - {file = "fonttools-4.53.0-py3-none-any.whl", hash = "sha256:6b4f04b1fbc01a3569d63359f2227c89ab294550de277fd09d8fca6185669fa4"}, - {file = "fonttools-4.53.0.tar.gz", hash = "sha256:c93ed66d32de1559b6fc348838c7572d5c0ac1e4a258e76763a5caddd8944002"}, + {file = "fonttools-4.53.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0679a30b59d74b6242909945429dbddb08496935b82f91ea9bf6ad240ec23397"}, + {file = "fonttools-4.53.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8bf06b94694251861ba7fdeea15c8ec0967f84c3d4143ae9daf42bbc7717fe3"}, + {file = "fonttools-4.53.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b96cd370a61f4d083c9c0053bf634279b094308d52fdc2dd9a22d8372fdd590d"}, + {file = "fonttools-4.53.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1c7c5aa18dd3b17995898b4a9b5929d69ef6ae2af5b96d585ff4005033d82f0"}, + {file = "fonttools-4.53.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e013aae589c1c12505da64a7d8d023e584987e51e62006e1bb30d72f26522c41"}, + {file = "fonttools-4.53.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9efd176f874cb6402e607e4cc9b4a9cd584d82fc34a4b0c811970b32ba62501f"}, + {file = "fonttools-4.53.1-cp310-cp310-win32.whl", hash = "sha256:c8696544c964500aa9439efb6761947393b70b17ef4e82d73277413f291260a4"}, + {file = "fonttools-4.53.1-cp310-cp310-win_amd64.whl", hash = "sha256:8959a59de5af6d2bec27489e98ef25a397cfa1774b375d5787509c06659b3671"}, + {file = "fonttools-4.53.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:da33440b1413bad53a8674393c5d29ce64d8c1a15ef8a77c642ffd900d07bfe1"}, + {file = "fonttools-4.53.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ff7e5e9bad94e3a70c5cd2fa27f20b9bb9385e10cddab567b85ce5d306ea923"}, + {file = "fonttools-4.53.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6e7170d675d12eac12ad1a981d90f118c06cf680b42a2d74c6c931e54b50719"}, + {file = "fonttools-4.53.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bee32ea8765e859670c4447b0817514ca79054463b6b79784b08a8df3a4d78e3"}, + {file = "fonttools-4.53.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e08f572625a1ee682115223eabebc4c6a2035a6917eac6f60350aba297ccadb"}, + {file = "fonttools-4.53.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b21952c092ffd827504de7e66b62aba26fdb5f9d1e435c52477e6486e9d128b2"}, + {file = "fonttools-4.53.1-cp311-cp311-win32.whl", hash = "sha256:9dfdae43b7996af46ff9da520998a32b105c7f098aeea06b2226b30e74fbba88"}, + {file = "fonttools-4.53.1-cp311-cp311-win_amd64.whl", hash = "sha256:d4d0096cb1ac7a77b3b41cd78c9b6bc4a400550e21dc7a92f2b5ab53ed74eb02"}, + {file = "fonttools-4.53.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d92d3c2a1b39631a6131c2fa25b5406855f97969b068e7e08413325bc0afba58"}, + {file = "fonttools-4.53.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3b3c8ebafbee8d9002bd8f1195d09ed2bd9ff134ddec37ee8f6a6375e6a4f0e8"}, + {file = "fonttools-4.53.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f029c095ad66c425b0ee85553d0dc326d45d7059dbc227330fc29b43e8ba60"}, + {file = "fonttools-4.53.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f5e6c3510b79ea27bb1ebfcc67048cde9ec67afa87c7dd7efa5c700491ac7f"}, + {file = "fonttools-4.53.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f677ce218976496a587ab17140da141557beb91d2a5c1a14212c994093f2eae2"}, + {file = "fonttools-4.53.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9e6ceba2a01b448e36754983d376064730690401da1dd104ddb543519470a15f"}, + {file = "fonttools-4.53.1-cp312-cp312-win32.whl", hash = "sha256:791b31ebbc05197d7aa096bbc7bd76d591f05905d2fd908bf103af4488e60670"}, + {file = "fonttools-4.53.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ed170b5e17da0264b9f6fae86073be3db15fa1bd74061c8331022bca6d09bab"}, + {file = "fonttools-4.53.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c818c058404eb2bba05e728d38049438afd649e3c409796723dfc17cd3f08749"}, + {file = "fonttools-4.53.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:651390c3b26b0c7d1f4407cad281ee7a5a85a31a110cbac5269de72a51551ba2"}, + {file = "fonttools-4.53.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e54f1bba2f655924c1138bbc7fa91abd61f45c68bd65ab5ed985942712864bbb"}, + {file = "fonttools-4.53.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9cd19cf4fe0595ebdd1d4915882b9440c3a6d30b008f3cc7587c1da7b95be5f"}, + {file = "fonttools-4.53.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2af40ae9cdcb204fc1d8f26b190aa16534fcd4f0df756268df674a270eab575d"}, + {file = "fonttools-4.53.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:35250099b0cfb32d799fb5d6c651220a642fe2e3c7d2560490e6f1d3f9ae9169"}, + {file = "fonttools-4.53.1-cp38-cp38-win32.whl", hash = "sha256:f08df60fbd8d289152079a65da4e66a447efc1d5d5a4d3f299cdd39e3b2e4a7d"}, + {file = "fonttools-4.53.1-cp38-cp38-win_amd64.whl", hash = "sha256:7b6b35e52ddc8fb0db562133894e6ef5b4e54e1283dff606fda3eed938c36fc8"}, + {file = "fonttools-4.53.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75a157d8d26c06e64ace9df037ee93a4938a4606a38cb7ffaf6635e60e253b7a"}, + {file = "fonttools-4.53.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4824c198f714ab5559c5be10fd1adf876712aa7989882a4ec887bf1ef3e00e31"}, + {file = "fonttools-4.53.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:becc5d7cb89c7b7afa8321b6bb3dbee0eec2b57855c90b3e9bf5fb816671fa7c"}, + {file = "fonttools-4.53.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84ec3fb43befb54be490147b4a922b5314e16372a643004f182babee9f9c3407"}, + {file = "fonttools-4.53.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:73379d3ffdeecb376640cd8ed03e9d2d0e568c9d1a4e9b16504a834ebadc2dfb"}, + {file = "fonttools-4.53.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:02569e9a810f9d11f4ae82c391ebc6fb5730d95a0657d24d754ed7763fb2d122"}, + {file = "fonttools-4.53.1-cp39-cp39-win32.whl", hash = "sha256:aae7bd54187e8bf7fd69f8ab87b2885253d3575163ad4d669a262fe97f0136cb"}, + {file = "fonttools-4.53.1-cp39-cp39-win_amd64.whl", hash = "sha256:e5b708073ea3d684235648786f5f6153a48dc8762cdfe5563c57e80787c29fbb"}, + {file = "fonttools-4.53.1-py3-none-any.whl", hash = "sha256:f1f8758a2ad110bd6432203a344269f445a2907dc24ef6bccfd0ac4e14e0d71d"}, + {file = "fonttools-4.53.1.tar.gz", hash = "sha256:e128778a8e9bc11159ce5447f76766cefbd876f44bd79aff030287254e4752c4"}, ] [package.extras] @@ -255,13 +435,13 @@ woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] name = "fsspec" -version = "2024.6.0" +version = "2024.6.1" description = "File-system specification" optional = false python-versions = ">=3.8" files = [ - {file = "fsspec-2024.6.0-py3-none-any.whl", hash = "sha256:58d7122eb8a1a46f7f13453187bfea4972d66bf01618d37366521b1998034cee"}, - {file = "fsspec-2024.6.0.tar.gz", hash = "sha256:f579960a56e6d8038a9efc8f9c77279ec12e6299aa86b0769a7e9c46b94527c2"}, + {file = "fsspec-2024.6.1-py3-none-any.whl", hash = "sha256:3cb443f8bcd2efb31295a5b9fdb02aee81d8452c80d28f97a6d0959e6cee101e"}, + {file = "fsspec-2024.6.1.tar.gz", hash = "sha256:fad7d7e209dd4c1208e3bbfda706620e0da5142bebbd9c384afb95b07e798e49"}, ] [package.extras] @@ -292,20 +472,106 @@ test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask-expr", "dask[dataframe, test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard"] tqdm = ["tqdm"] +[[package]] +name = "googleapis-common-protos" +version = "1.63.2" +description = "Common protobufs used in Google APIs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "googleapis-common-protos-1.63.2.tar.gz", hash = "sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87"}, + {file = "googleapis_common_protos-1.63.2-py2.py3-none-any.whl", hash = "sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945"}, +] + +[package.dependencies] +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" + +[package.extras] +grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] + +[[package]] +name = "grpcio" +version = "1.64.1" +description = "HTTP/2-based RPC framework" +optional = false +python-versions = ">=3.8" +files = [ + {file = "grpcio-1.64.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:55697ecec192bc3f2f3cc13a295ab670f51de29884ca9ae6cd6247df55df2502"}, + {file = "grpcio-1.64.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:3b64ae304c175671efdaa7ec9ae2cc36996b681eb63ca39c464958396697daff"}, + {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:bac71b4b28bc9af61efcdc7630b166440bbfbaa80940c9a697271b5e1dabbc61"}, + {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c024ffc22d6dc59000faf8ad781696d81e8e38f4078cb0f2630b4a3cf231a90"}, + {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7cd5c1325f6808b8ae31657d281aadb2a51ac11ab081ae335f4f7fc44c1721d"}, + {file = "grpcio-1.64.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0a2813093ddb27418a4c99f9b1c223fab0b053157176a64cc9db0f4557b69bd9"}, + {file = "grpcio-1.64.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2981c7365a9353f9b5c864595c510c983251b1ab403e05b1ccc70a3d9541a73b"}, + {file = "grpcio-1.64.1-cp310-cp310-win32.whl", hash = "sha256:1262402af5a511c245c3ae918167eca57342c72320dffae5d9b51840c4b2f86d"}, + {file = "grpcio-1.64.1-cp310-cp310-win_amd64.whl", hash = "sha256:19264fc964576ddb065368cae953f8d0514ecc6cb3da8903766d9fb9d4554c33"}, + {file = "grpcio-1.64.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:58b1041e7c870bb30ee41d3090cbd6f0851f30ae4eb68228955d973d3efa2e61"}, + {file = "grpcio-1.64.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bbc5b1d78a7822b0a84c6f8917faa986c1a744e65d762ef6d8be9d75677af2ca"}, + {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:5841dd1f284bd1b3d8a6eca3a7f062b06f1eec09b184397e1d1d43447e89a7ae"}, + {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8caee47e970b92b3dd948371230fcceb80d3f2277b3bf7fbd7c0564e7d39068e"}, + {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73819689c169417a4f978e562d24f2def2be75739c4bed1992435d007819da1b"}, + {file = "grpcio-1.64.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6503b64c8b2dfad299749cad1b595c650c91e5b2c8a1b775380fcf8d2cbba1e9"}, + {file = "grpcio-1.64.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1de403fc1305fd96cfa75e83be3dee8538f2413a6b1685b8452301c7ba33c294"}, + {file = "grpcio-1.64.1-cp311-cp311-win32.whl", hash = "sha256:d4d29cc612e1332237877dfa7fe687157973aab1d63bd0f84cf06692f04c0367"}, + {file = "grpcio-1.64.1-cp311-cp311-win_amd64.whl", hash = "sha256:5e56462b05a6f860b72f0fa50dca06d5b26543a4e88d0396259a07dc30f4e5aa"}, + {file = "grpcio-1.64.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:4657d24c8063e6095f850b68f2d1ba3b39f2b287a38242dcabc166453e950c59"}, + {file = "grpcio-1.64.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:62b4e6eb7bf901719fce0ca83e3ed474ae5022bb3827b0a501e056458c51c0a1"}, + {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:ee73a2f5ca4ba44fa33b4d7d2c71e2c8a9e9f78d53f6507ad68e7d2ad5f64a22"}, + {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:198908f9b22e2672a998870355e226a725aeab327ac4e6ff3a1399792ece4762"}, + {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b9d0acaa8d835a6566c640f48b50054f422d03e77e49716d4c4e8e279665a1"}, + {file = "grpcio-1.64.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5e42634a989c3aa6049f132266faf6b949ec2a6f7d302dbb5c15395b77d757eb"}, + {file = "grpcio-1.64.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b1a82e0b9b3022799c336e1fc0f6210adc019ae84efb7321d668129d28ee1efb"}, + {file = "grpcio-1.64.1-cp312-cp312-win32.whl", hash = "sha256:55260032b95c49bee69a423c2f5365baa9369d2f7d233e933564d8a47b893027"}, + {file = "grpcio-1.64.1-cp312-cp312-win_amd64.whl", hash = "sha256:c1a786ac592b47573a5bb7e35665c08064a5d77ab88a076eec11f8ae86b3e3f6"}, + {file = "grpcio-1.64.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:a011ac6c03cfe162ff2b727bcb530567826cec85eb8d4ad2bfb4bd023287a52d"}, + {file = "grpcio-1.64.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4d6dab6124225496010bd22690f2d9bd35c7cbb267b3f14e7a3eb05c911325d4"}, + {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:a5e771d0252e871ce194d0fdcafd13971f1aae0ddacc5f25615030d5df55c3a2"}, + {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c3c1b90ab93fed424e454e93c0ed0b9d552bdf1b0929712b094f5ecfe7a23ad"}, + {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20405cb8b13fd779135df23fabadc53b86522d0f1cba8cca0e87968587f50650"}, + {file = "grpcio-1.64.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0cc79c982ccb2feec8aad0e8fb0d168bcbca85bc77b080d0d3c5f2f15c24ea8f"}, + {file = "grpcio-1.64.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a3a035c37ce7565b8f4f35ff683a4db34d24e53dc487e47438e434eb3f701b2a"}, + {file = "grpcio-1.64.1-cp38-cp38-win32.whl", hash = "sha256:1257b76748612aca0f89beec7fa0615727fd6f2a1ad580a9638816a4b2eb18fd"}, + {file = "grpcio-1.64.1-cp38-cp38-win_amd64.whl", hash = "sha256:0a12ddb1678ebc6a84ec6b0487feac020ee2b1659cbe69b80f06dbffdb249122"}, + {file = "grpcio-1.64.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:75dbbf415026d2862192fe1b28d71f209e2fd87079d98470db90bebe57b33179"}, + {file = "grpcio-1.64.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e3d9f8d1221baa0ced7ec7322a981e28deb23749c76eeeb3d33e18b72935ab62"}, + {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5f8b75f64d5d324c565b263c67dbe4f0af595635bbdd93bb1a88189fc62ed2e5"}, + {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c84ad903d0d94311a2b7eea608da163dace97c5fe9412ea311e72c3684925602"}, + {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:940e3ec884520155f68a3b712d045e077d61c520a195d1a5932c531f11883489"}, + {file = "grpcio-1.64.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f10193c69fc9d3d726e83bbf0f3d316f1847c3071c8c93d8090cf5f326b14309"}, + {file = "grpcio-1.64.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac15b6c2c80a4d1338b04d42a02d376a53395ddf0ec9ab157cbaf44191f3ffdd"}, + {file = "grpcio-1.64.1-cp39-cp39-win32.whl", hash = "sha256:03b43d0ccf99c557ec671c7dede64f023c7da9bb632ac65dbc57f166e4970040"}, + {file = "grpcio-1.64.1-cp39-cp39-win_amd64.whl", hash = "sha256:ed6091fa0adcc7e4ff944090cf203a52da35c37a130efa564ded02b7aff63bcd"}, + {file = "grpcio-1.64.1.tar.gz", hash = "sha256:8d51dd1c59d5fa0f34266b80a3805ec29a1f26425c2a54736133f6d87fc4968a"}, +] + +[package.extras] +protobuf = ["grpcio-tools (>=1.64.1)"] + [[package]] name = "holidays" -version = "0.51" +version = "0.52" description = "Generate and work with holidays in Python" optional = false python-versions = ">=3.8" files = [ - {file = "holidays-0.51-py3-none-any.whl", hash = "sha256:c894d61d62a16a05a92ab21534ceb00489f57df07ea34ad3ca96064673314c45"}, - {file = "holidays-0.51.tar.gz", hash = "sha256:499d6952987ac99f94bd6a788222a7f5aa6bf8f1dc7bf834cc54ae42d9bbd713"}, + {file = "holidays-0.52-py3-none-any.whl", hash = "sha256:82df94441ed585afedbdd09328538db6af418dd6008a28948bf8a7664764ae2d"}, + {file = "holidays-0.52.tar.gz", hash = "sha256:2891f548dd34e3596e2537fb32da7ad3b42caa73053cffd582c68ed20257d9c3"}, ] [package.dependencies] python-dateutil = "*" +[[package]] +name = "idna" +version = "3.7" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, +] + [[package]] name = "importlib-resources" version = "6.4.0" @@ -388,6 +654,41 @@ files = [ {file = "joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e"}, ] +[[package]] +name = "jsonschema" +version = "4.22.0" +description = "An implementation of JSON Schema validation for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, + {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +jsonschema-specifications = ">=2023.03.6" +referencing = ">=0.28.4" +rpds-py = ">=0.7.1" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] + +[[package]] +name = "jsonschema-specifications" +version = "2023.12.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, +] + +[package.dependencies] +referencing = ">=0.31.0" + [[package]] name = "kiwisolver" version = "1.4.5" @@ -572,40 +873,40 @@ files = [ [[package]] name = "matplotlib" -version = "3.9.0" +version = "3.9.1" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2bcee1dffaf60fe7656183ac2190bd630842ff87b3153afb3e384d966b57fe56"}, - {file = "matplotlib-3.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f988bafb0fa39d1074ddd5bacd958c853e11def40800c5824556eb630f94d3b"}, - {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe428e191ea016bb278758c8ee82a8129c51d81d8c4bc0846c09e7e8e9057241"}, - {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaf3978060a106fab40c328778b148f590e27f6fa3cd15a19d6892575bce387d"}, - {file = "matplotlib-3.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2e7f03e5cbbfacdd48c8ea394d365d91ee8f3cae7e6ec611409927b5ed997ee4"}, - {file = "matplotlib-3.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:13beb4840317d45ffd4183a778685e215939be7b08616f431c7795276e067463"}, - {file = "matplotlib-3.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:063af8587fceeac13b0936c42a2b6c732c2ab1c98d38abc3337e430e1ff75e38"}, - {file = "matplotlib-3.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a2fa6d899e17ddca6d6526cf6e7ba677738bf2a6a9590d702c277204a7c6152"}, - {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550cdda3adbd596078cca7d13ed50b77879104e2e46392dcd7c75259d8f00e85"}, - {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cce0f31b351e3551d1f3779420cf8f6ec0d4a8cf9c0237a3b549fd28eb4abb"}, - {file = "matplotlib-3.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c53aeb514ccbbcbab55a27f912d79ea30ab21ee0531ee2c09f13800efb272674"}, - {file = "matplotlib-3.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5be985db2596d761cdf0c2eaf52396f26e6a64ab46bd8cd810c48972349d1be"}, - {file = "matplotlib-3.9.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c79f3a585f1368da6049318bdf1f85568d8d04b2e89fc24b7e02cc9b62017382"}, - {file = "matplotlib-3.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bdd1ecbe268eb3e7653e04f451635f0fb0f77f07fd070242b44c076c9106da84"}, - {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d38e85a1a6d732f645f1403ce5e6727fd9418cd4574521d5803d3d94911038e5"}, - {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a490715b3b9984fa609116481b22178348c1a220a4499cda79132000a79b4db"}, - {file = "matplotlib-3.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8146ce83cbc5dc71c223a74a1996d446cd35cfb6a04b683e1446b7e6c73603b7"}, - {file = "matplotlib-3.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:d91a4ffc587bacf5c4ce4ecfe4bcd23a4b675e76315f2866e588686cc97fccdf"}, - {file = "matplotlib-3.9.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:616fabf4981a3b3c5a15cd95eba359c8489c4e20e03717aea42866d8d0465956"}, - {file = "matplotlib-3.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cd53c79fd02f1c1808d2cfc87dd3cf4dbc63c5244a58ee7944497107469c8d8a"}, - {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06a478f0d67636554fa78558cfbcd7b9dba85b51f5c3b5a0c9be49010cf5f321"}, - {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81c40af649d19c85f8073e25e5806926986806fa6d54be506fbf02aef47d5a89"}, - {file = "matplotlib-3.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52146fc3bd7813cc784562cb93a15788be0b2875c4655e2cc6ea646bfa30344b"}, - {file = "matplotlib-3.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:0fc51eaa5262553868461c083d9adadb11a6017315f3a757fc45ec6ec5f02888"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bd4f2831168afac55b881db82a7730992aa41c4f007f1913465fb182d6fb20c0"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:290d304e59be2b33ef5c2d768d0237f5bd132986bdcc66f80bc9bcc300066a03"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff2e239c26be4f24bfa45860c20ffccd118d270c5b5d081fa4ea409b5469fcd"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:af4001b7cae70f7eaacfb063db605280058246de590fa7874f00f62259f2df7e"}, - {file = "matplotlib-3.9.0.tar.gz", hash = "sha256:e6d29ea6c19e34b30fb7d88b7081f869a03014f66fe06d62cc77d5a6ea88ed7a"}, + {file = "matplotlib-3.9.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7ccd6270066feb9a9d8e0705aa027f1ff39f354c72a87efe8fa07632f30fc6bb"}, + {file = "matplotlib-3.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:591d3a88903a30a6d23b040c1e44d1afdd0d778758d07110eb7596f811f31842"}, + {file = "matplotlib-3.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd2a59ff4b83d33bca3b5ec58203cc65985367812cb8c257f3e101632be86d92"}, + {file = "matplotlib-3.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fc001516ffcf1a221beb51198b194d9230199d6842c540108e4ce109ac05cc0"}, + {file = "matplotlib-3.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:83c6a792f1465d174c86d06f3ae85a8fe36e6f5964633ae8106312ec0921fdf5"}, + {file = "matplotlib-3.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:421851f4f57350bcf0811edd754a708d2275533e84f52f6760b740766c6747a7"}, + {file = "matplotlib-3.9.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b3fce58971b465e01b5c538f9d44915640c20ec5ff31346e963c9e1cd66fa812"}, + {file = "matplotlib-3.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a973c53ad0668c53e0ed76b27d2eeeae8799836fd0d0caaa4ecc66bf4e6676c0"}, + {file = "matplotlib-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd5acf8f3ef43f7532c2f230249720f5dc5dd40ecafaf1c60ac8200d46d7eb"}, + {file = "matplotlib-3.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab38a4f3772523179b2f772103d8030215b318fef6360cb40558f585bf3d017f"}, + {file = "matplotlib-3.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2315837485ca6188a4b632c5199900e28d33b481eb083663f6a44cfc8987ded3"}, + {file = "matplotlib-3.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:a0c977c5c382f6696caf0bd277ef4f936da7e2aa202ff66cad5f0ac1428ee15b"}, + {file = "matplotlib-3.9.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:565d572efea2b94f264dd86ef27919515aa6d629252a169b42ce5f570db7f37b"}, + {file = "matplotlib-3.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d397fd8ccc64af2ec0af1f0efc3bacd745ebfb9d507f3f552e8adb689ed730a"}, + {file = "matplotlib-3.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26040c8f5121cd1ad712abffcd4b5222a8aec3a0fe40bc8542c94331deb8780d"}, + {file = "matplotlib-3.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d12cb1837cffaac087ad6b44399d5e22b78c729de3cdae4629e252067b705e2b"}, + {file = "matplotlib-3.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0e835c6988edc3d2d08794f73c323cc62483e13df0194719ecb0723b564e0b5c"}, + {file = "matplotlib-3.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:44a21d922f78ce40435cb35b43dd7d573cf2a30138d5c4b709d19f00e3907fd7"}, + {file = "matplotlib-3.9.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:0c584210c755ae921283d21d01f03a49ef46d1afa184134dd0f95b0202ee6f03"}, + {file = "matplotlib-3.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11fed08f34fa682c2b792942f8902e7aefeed400da71f9e5816bea40a7ce28fe"}, + {file = "matplotlib-3.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0000354e32efcfd86bda75729716b92f5c2edd5b947200be9881f0a671565c33"}, + {file = "matplotlib-3.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4db17fea0ae3aceb8e9ac69c7e3051bae0b3d083bfec932240f9bf5d0197a049"}, + {file = "matplotlib-3.9.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:208cbce658b72bf6a8e675058fbbf59f67814057ae78165d8a2f87c45b48d0ff"}, + {file = "matplotlib-3.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:dc23f48ab630474264276be156d0d7710ac6c5a09648ccdf49fef9200d8cbe80"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3fda72d4d472e2ccd1be0e9ccb6bf0d2eaf635e7f8f51d737ed7e465ac020cb3"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:84b3ba8429935a444f1fdc80ed930babbe06725bcf09fbeb5c8757a2cd74af04"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b918770bf3e07845408716e5bbda17eadfc3fcbd9307dc67f37d6cf834bb3d98"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f1f2e5d29e9435c97ad4c36fb6668e89aee13d48c75893e25cef064675038ac9"}, + {file = "matplotlib-3.9.1.tar.gz", hash = "sha256:de06b19b8db95dd33d0dc17c926c7c9ebed9f572074b6fac4f65068a6814d010"}, ] [package.dependencies] @@ -728,39 +1029,41 @@ files = [ [[package]] name = "nada-dsl" -version = "0.2.1" +version = "0.3.0" description = "Nillion Nada DSL to create Nillion MPC programs." optional = false python-versions = ">=3.10" files = [ - {file = "nada_dsl-0.2.1-py3-none-any.whl", hash = "sha256:da9e0de0d629d76004cea36b64dd274cc3ed3f4699f8d34f14e30d0db13fa814"}, + {file = "nada_dsl-0.3.0-py3-none-any.whl", hash = "sha256:54a72655f03dbbf98d5304eff61890076b5b753b14c2a1c44be0967956774aad"}, ] [package.dependencies] asttokens = ">=2.4,<3.0" parsial = ">=0.1,<1.0" richreports = ">=0.2,<1.0" +sortedcontainers = ">=2.4,<3.0" [package.extras] docs = ["sphinx (>=5,<8)", "sphinx-rtd-theme (>=1.0,<2.1)", "toml (>=0.10.2,<0.11.0)"] -lint = ["pylint (>=2.17,<3.2)"] +lint = ["pylint (>=2.17,<3.3)"] test = ["pytest (>=7.4,<9.0)", "pytest-cov (>=4,<6)"] [[package]] name = "nada-numpy" -version = "0.1.2" +version = "0.2.0" description = "Nada-Numpy is a Python library designed for algebraic operations on NumPy-like array objects on top of Nada DSL and Nillion Network." optional = false python-versions = "<4.0,>=3.10" files = [ - {file = "nada_numpy-0.1.2-py3-none-any.whl", hash = "sha256:1da3b1000b22f818c43f31ccab973288b76cb4b0e561fc627e6229cdb11919d5"}, - {file = "nada_numpy-0.1.2.tar.gz", hash = "sha256:0a14a2ce8509d9e93097b95f7cc7cfbe874e8795d843655a528e7bc9dd19f48e"}, + {file = "nada_numpy-0.2.0-py3-none-any.whl", hash = "sha256:d579226a4fafd7d0aa9c2b7c38ca6d40b989503dc75b3b09f0daa26c6fe99f67"}, + {file = "nada_numpy-0.2.0.tar.gz", hash = "sha256:0dba068f1420016bfc175105352b4e8ed45154f071f6303171216cb411c271da"}, ] [package.dependencies] -nada-dsl = ">=0.2.1,<0.3.0" +nada-dsl = ">=0.3,<0.4" +nillion-python-helpers = ">=0.2.3,<0.3.0" numpy = ">=1.26.4,<2.0.0" -py-nillion-client = ">=0.2.1,<0.3.0" +py-nillion-client = ">=0.3,<0.4" [[package]] name = "networkx" @@ -782,17 +1085,17 @@ test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] [[package]] name = "nillion-python-helpers" -version = "0.1.2" +version = "0.2.3" description = "" optional = false python-versions = "<4.0,>=3.10" files = [ - {file = "nillion_python_helpers-0.1.2-py3-none-any.whl", hash = "sha256:6cfda32d7122d00b343ebc3bc50068537c710beab57f835e026c5989a58d4b5b"}, - {file = "nillion_python_helpers-0.1.2.tar.gz", hash = "sha256:e6eb07517f048dc9410902e356d48ce64a535b60a4b60980c0dafaa28511aa87"}, + {file = "nillion_python_helpers-0.2.3-py3-none-any.whl", hash = "sha256:e047e16bb456923d22409a84b7019af5370e0576437d91fe88fb839105da3f2a"}, + {file = "nillion_python_helpers-0.2.3.tar.gz", hash = "sha256:fcc1293f0c0567518d4e5cf0a91613587ee779839618e9c7e73b6afa8792a8ee"}, ] [package.dependencies] -py-nillion-client = ">=0.2.1,<0.3.0" +cosmpy = ">=0.9.2,<0.10.0" pytest-asyncio = ">=0.23.7,<0.24.0" python-dotenv = "1.0.0" @@ -963,14 +1266,13 @@ files = [ [[package]] name = "nvidia-nvjitlink-cu12" -version = "12.5.40" +version = "12.5.82" description = "Nvidia JIT LTO Library" optional = false python-versions = ">=3" files = [ - {file = "nvidia_nvjitlink_cu12-12.5.40-py3-none-manylinux2014_aarch64.whl", hash = "sha256:004186d5ea6a57758fd6d57052a123c73a4815adf365eb8dd6a85c9eaa7535ff"}, - {file = "nvidia_nvjitlink_cu12-12.5.40-py3-none-manylinux2014_x86_64.whl", hash = "sha256:d9714f27c1d0f0895cd8915c07a87a1d0029a0aa36acaf9156952ec2a8a12189"}, - {file = "nvidia_nvjitlink_cu12-12.5.40-py3-none-win_amd64.whl", hash = "sha256:c3401dc8543b52d3a8158007a0c1ab4e9c768fcbd24153a48c86972102197ddd"}, + {file = "nvidia_nvjitlink_cu12-12.5.82-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f9b37bc5c8cf7509665cb6ada5aaa0ce65618f2332b7d3e78e9790511f111212"}, + {file = "nvidia_nvjitlink_cu12-12.5.82-py3-none-win_amd64.whl", hash = "sha256:e782564d705ff0bf61ac3e1bf730166da66dd2fe9012f111ede5fc49b64ae697"}, ] [[package]] @@ -1036,8 +1338,8 @@ files = [ [package.dependencies] numpy = [ {version = ">=1.22.4", markers = "python_version < \"3.11\""}, - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -1088,84 +1390,95 @@ test = ["pytest (>=7.4,<8.0)", "pytest-cov (>=4.0,<5.0)"] [[package]] name = "pillow" -version = "10.3.0" +version = "10.4.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" files = [ - {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, - {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"}, - {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"}, - {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"}, - {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"}, - {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"}, - {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"}, - {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"}, - {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"}, - {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"}, - {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"}, - {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"}, - {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"}, - {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"}, - {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"}, - {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"}, - {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"}, - {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"}, - {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"}, - {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"}, - {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"}, - {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"}, - {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"}, - {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"}, - {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"}, - {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"}, - {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"}, - {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"}, - {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"}, - {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"}, - {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"}, - {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"}, - {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"}, - {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, - {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, + {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, + {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"}, + {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"}, + {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"}, + {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"}, + {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"}, + {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"}, + {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"}, + {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"}, + {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"}, + {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"}, + {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"}, + {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"}, + {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"}, + {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"}, + {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"}, + {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"}, + {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"}, + {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"}, + {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"}, + {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"}, + {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"}, + {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"}, + {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"}, + {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"}, + {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"}, + {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"}, + {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, ] [package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] fpx = ["olefile"] mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] @@ -1231,31 +1544,95 @@ tqdm = ">=4.36.1" dev = ["jupyterlab", "nbconvert", "plotly", "pytest", "setuptools (>=64)", "wheel"] parallel = ["dask[dataframe]", "distributed"] +[[package]] +name = "protobuf" +version = "4.25.3" +description = "" +optional = false +python-versions = ">=3.8" +files = [ + {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"}, + {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"}, + {file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"}, + {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"}, + {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"}, + {file = "protobuf-4.25.3-cp38-cp38-win32.whl", hash = "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2"}, + {file = "protobuf-4.25.3-cp38-cp38-win_amd64.whl", hash = "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4"}, + {file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"}, + {file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"}, + {file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"}, + {file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"}, +] + [[package]] name = "py-nillion-client" -version = "0.2.1" +version = "0.3.0" description = "Python client for Nillion network and utilities." optional = false python-versions = ">=3.10" files = [ - {file = "py_nillion_client-0.2.1-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:badc041dce6a3faf4ae26cd27992d67a06fa0fdd747196900560e0fb24806c09"}, - {file = "py_nillion_client-0.2.1-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:6b4d9e1b8426c55db9ebbdcae640803d1e326daebd4bef83252d6933af84d94e"}, - {file = "py_nillion_client-0.2.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8bd848896dee63def40c1871f6a43ffe513016c0ef319333fa5430c16f0444d3"}, - {file = "py_nillion_client-0.2.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2377dae91f9feffd3d471050a5c15142a461653b3b1c4ba671d9c18761c90cc3"}, + {file = "py_nillion_client-0.3.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f5036f509e848e5ee5325899e7b7892fe8a5c37782fa7a96c9ed417250bfc1af"}, + {file = "py_nillion_client-0.3.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:4dbe29e25944ece7625a5abd132493097aaaf0c2dcc032838dce032d62b23853"}, + {file = "py_nillion_client-0.3.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9625fbdafe4e1d9299c40d2bc29179944e4c8e4bc2b7a7472d99bd8d7a24d8c6"}, + {file = "py_nillion_client-0.3.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25f6a6b828a92cb32de0ee66767ccec3fab4592691f59eaaf9d7a95313ace1f0"}, ] +[package.dependencies] +protobuf = ">=4.21.6,<5.0.dev0" + [package.extras] -dev = ["maturin (==1.4.0)", "maturin[zig] (==1.4.0)", "pytest (==8.0.0)", "pyyaml (==6.0.1)"] +dev = ["cosmpy (==0.9.2)", "maturin (==1.6.0)", "maturin[zig] (==1.6.0)", "pytest (==8.0.0)", "pyyaml (==6.0.1)"] + +[[package]] +name = "pycryptodome" +version = "3.20.0" +description = "Cryptographic library for Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "pycryptodome-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:417a276aaa9cb3be91f9014e9d18d10e840a7a9b9a9be64a42f553c5b50b4d1d"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1250b7ea809f752b68e3e6f3fd946b5939a52eaeea18c73bdab53e9ba3c2dd"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:d5954acfe9e00bc83ed9f5cb082ed22c592fbbef86dc48b907238be64ead5c33"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:06d6de87c19f967f03b4cf9b34e538ef46e99a337e9a61a77dbe44b2cbcf0690"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ec0bb1188c1d13426039af8ffcb4dbe3aad1d7680c35a62d8eaf2a529b5d3d4f"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5601c934c498cd267640b57569e73793cb9a83506f7c73a8ec57a516f5b0b091"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d29daa681517f4bc318cd8a23af87e1f2a7bad2fe361e8aa29c77d652a065de4"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3427d9e5310af6680678f4cce149f54e0bb4af60101c7f2c16fdf878b39ccccc"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:3cd3ef3aee1079ae44afaeee13393cf68b1058f70576b11439483e34f93cf818"}, + {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044"}, + {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4"}, + {file = "pycryptodome-3.20.0-cp35-abi3-win32.whl", hash = "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72"}, + {file = "pycryptodome-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9"}, + {file = "pycryptodome-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a"}, + {file = "pycryptodome-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e"}, + {file = "pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7"}, +] [[package]] name = "pylint" -version = "3.2.3" +version = "3.2.5" description = "python code static checker" optional = false python-versions = ">=3.8.0" files = [ - {file = "pylint-3.2.3-py3-none-any.whl", hash = "sha256:b3d7d2708a3e04b4679e02d99e72329a8b7ee8afb8d04110682278781f889fa8"}, - {file = "pylint-3.2.3.tar.gz", hash = "sha256:02f6c562b215582386068d52a30f520d84fdbcf2a95fc7e855b816060d048b60"}, + {file = "pylint-3.2.5-py3-none-any.whl", hash = "sha256:32cd6c042b5004b8e857d727708720c54a676d1e22917cf1a2df9b4d4868abd6"}, + {file = "pylint-3.2.5.tar.gz", hash = "sha256:e9b7171e242dcc6ebd0aaa7540481d1a72860748a0a7816b8fe6cf6c80a6fe7e"}, ] [package.dependencies] @@ -1263,8 +1640,8 @@ astroid = ">=3.2.2,<=3.3.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, - {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, + {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, ] isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" mccabe = ">=0.6,<0.8" @@ -1369,6 +1746,42 @@ files = [ {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] +[[package]] +name = "referencing" +version = "0.35.1" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, + {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + +[[package]] +name = "requests" +version = "2.32.3" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.8" +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + [[package]] name = "richreports" version = "0.2.0" @@ -1387,34 +1800,142 @@ lint = ["pylint (>=2.17,<3.0)"] publish = ["build (>=0.10,<1.0)", "twine (>=4.0,<5.0)"] test = ["pytest (>=7.4,<8.0)", "pytest-cov (>=4.0,<5.0)"] +[[package]] +name = "rpds-py" +version = "0.18.1" +description = "Python bindings to Rust's persistent data structures (rpds)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, + {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"}, + {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"}, + {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"}, + {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"}, + {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"}, + {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"}, + {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"}, + {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"}, + {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"}, + {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"}, + {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"}, + {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, +] + [[package]] name = "scikit-learn" -version = "1.5.0" +version = "1.5.1" description = "A set of python modules for machine learning and data mining" optional = false python-versions = ">=3.9" files = [ - {file = "scikit_learn-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12e40ac48555e6b551f0a0a5743cc94cc5a765c9513fe708e01f0aa001da2801"}, - {file = "scikit_learn-1.5.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:f405c4dae288f5f6553b10c4ac9ea7754d5180ec11e296464adb5d6ac68b6ef5"}, - {file = "scikit_learn-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df8ccabbf583315f13160a4bb06037bde99ea7d8211a69787a6b7c5d4ebb6fc3"}, - {file = "scikit_learn-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c75ea812cd83b1385bbfa94ae971f0d80adb338a9523f6bbcb5e0b0381151d4"}, - {file = "scikit_learn-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:a90c5da84829a0b9b4bf00daf62754b2be741e66b5946911f5bdfaa869fcedd6"}, - {file = "scikit_learn-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2a65af2d8a6cce4e163a7951a4cfbfa7fceb2d5c013a4b593686c7f16445cf9d"}, - {file = "scikit_learn-1.5.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:4c0c56c3005f2ec1db3787aeaabefa96256580678cec783986836fc64f8ff622"}, - {file = "scikit_learn-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f77547165c00625551e5c250cefa3f03f2fc92c5e18668abd90bfc4be2e0bff"}, - {file = "scikit_learn-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:118a8d229a41158c9f90093e46b3737120a165181a1b58c03461447aa4657415"}, - {file = "scikit_learn-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:a03b09f9f7f09ffe8c5efffe2e9de1196c696d811be6798ad5eddf323c6f4d40"}, - {file = "scikit_learn-1.5.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:460806030c666addee1f074788b3978329a5bfdc9b7d63e7aad3f6d45c67a210"}, - {file = "scikit_learn-1.5.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:1b94d6440603752b27842eda97f6395f570941857456c606eb1d638efdb38184"}, - {file = "scikit_learn-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d82c2e573f0f2f2f0be897e7a31fcf4e73869247738ab8c3ce7245549af58ab8"}, - {file = "scikit_learn-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3a10e1d9e834e84d05e468ec501a356226338778769317ee0b84043c0d8fb06"}, - {file = "scikit_learn-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:855fc5fa8ed9e4f08291203af3d3e5fbdc4737bd617a371559aaa2088166046e"}, - {file = "scikit_learn-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:40fb7d4a9a2db07e6e0cae4dc7bdbb8fada17043bac24104d8165e10e4cff1a2"}, - {file = "scikit_learn-1.5.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:47132440050b1c5beb95f8ba0b2402bbd9057ce96ec0ba86f2f445dd4f34df67"}, - {file = "scikit_learn-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:174beb56e3e881c90424e21f576fa69c4ffcf5174632a79ab4461c4c960315ac"}, - {file = "scikit_learn-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261fe334ca48f09ed64b8fae13f9b46cc43ac5f580c4a605cbb0a517456c8f71"}, - {file = "scikit_learn-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:057b991ac64b3e75c9c04b5f9395eaf19a6179244c089afdebaad98264bff37c"}, - {file = "scikit_learn-1.5.0.tar.gz", hash = "sha256:789e3db01c750ed6d496fa2db7d50637857b451e57bcae863bff707c1247bef7"}, + {file = "scikit_learn-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:781586c414f8cc58e71da4f3d7af311e0505a683e112f2f62919e3019abd3745"}, + {file = "scikit_learn-1.5.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:f5b213bc29cc30a89a3130393b0e39c847a15d769d6e59539cd86b75d276b1a7"}, + {file = "scikit_learn-1.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ff4ba34c2abff5ec59c803ed1d97d61b036f659a17f55be102679e88f926fac"}, + {file = "scikit_learn-1.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:161808750c267b77b4a9603cf9c93579c7a74ba8486b1336034c2f1579546d21"}, + {file = "scikit_learn-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:10e49170691514a94bb2e03787aa921b82dbc507a4ea1f20fd95557862c98dc1"}, + {file = "scikit_learn-1.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:154297ee43c0b83af12464adeab378dee2d0a700ccd03979e2b821e7dd7cc1c2"}, + {file = "scikit_learn-1.5.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:b5e865e9bd59396220de49cb4a57b17016256637c61b4c5cc81aaf16bc123bbe"}, + {file = "scikit_learn-1.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:909144d50f367a513cee6090873ae582dba019cb3fca063b38054fa42704c3a4"}, + {file = "scikit_learn-1.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:689b6f74b2c880276e365fe84fe4f1befd6a774f016339c65655eaff12e10cbf"}, + {file = "scikit_learn-1.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:9a07f90846313a7639af6a019d849ff72baadfa4c74c778821ae0fad07b7275b"}, + {file = "scikit_learn-1.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5944ce1faada31c55fb2ba20a5346b88e36811aab504ccafb9f0339e9f780395"}, + {file = "scikit_learn-1.5.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0828673c5b520e879f2af6a9e99eee0eefea69a2188be1ca68a6121b809055c1"}, + {file = "scikit_learn-1.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:508907e5f81390e16d754e8815f7497e52139162fd69c4fdbd2dfa5d6cc88915"}, + {file = "scikit_learn-1.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97625f217c5c0c5d0505fa2af28ae424bd37949bb2f16ace3ff5f2f81fb4498b"}, + {file = "scikit_learn-1.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:da3f404e9e284d2b0a157e1b56b6566a34eb2798205cba35a211df3296ab7a74"}, + {file = "scikit_learn-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:88e0672c7ac21eb149d409c74cc29f1d611d5158175846e7a9c2427bd12b3956"}, + {file = "scikit_learn-1.5.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:7b073a27797a283187a4ef4ee149959defc350b46cbf63a84d8514fe16b69855"}, + {file = "scikit_learn-1.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b59e3e62d2be870e5c74af4e793293753565c7383ae82943b83383fdcf5cc5c1"}, + {file = "scikit_learn-1.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bd8d3a19d4bd6dc5a7d4f358c8c3a60934dc058f363c34c0ac1e9e12a31421d"}, + {file = "scikit_learn-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:5f57428de0c900a98389c4a433d4a3cf89de979b3aa24d1c1d251802aa15e44d"}, + {file = "scikit_learn-1.5.1.tar.gz", hash = "sha256:0ea5d40c0e3951df445721927448755d3fe1d80833b0b7308ebff5d2a45e6414"}, ] [package.dependencies] @@ -1425,8 +1946,8 @@ threadpoolctl = ">=3.1.0" [package.extras] benchmark = ["matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "pandas (>=1.1.5)"] -build = ["cython (>=3.0.10)", "meson-python (>=0.15.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)"] -docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "polars (>=0.20.23)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=6.0.0)", "sphinx-copybutton (>=0.5.2)", "sphinx-gallery (>=0.15.0)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] +build = ["cython (>=3.0.10)", "meson-python (>=0.16.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)"] +docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "polars (>=0.20.23)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-gallery (>=0.16.0)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)"] examples = ["matplotlib (>=3.3.4)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)"] install = ["joblib (>=1.2.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)", "threadpoolctl (>=3.1.0)"] maintenance = ["conda-lock (==2.5.6)"] @@ -1485,6 +2006,17 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "sortedcontainers" +version = "2.4.0" +description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +optional = false +python-versions = "*" +files = [ + {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, + {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, +] + [[package]] name = "stanio" version = "0.5.0" @@ -1682,7 +2214,24 @@ files = [ {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] +[[package]] +name = "urllib3" +version = "2.2.2" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "8e7527ac4cf0f1b75fc5c71484d01700d18a03bb5570dd45e4ed53d1e227acbe" +content-hash = "5dbd35a9d64b1d152c07613c092ff86aaf849c36be51b479a0a6b96ac8b507b0" diff --git a/pyproject.toml b/pyproject.toml index 8832541..caef4d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "nada-ai" -version = "0.1.3" +version = "0.2.0" description = "Nada-AI is a Python library designed for AI/ML on top of Nada DSL and Nillion Network." authors = ["Mathias Leys "] readme = "README.md" @@ -11,10 +11,10 @@ numpy = "^1.26.4" torch = "^2.0.0" scikit-learn = "^1.4.2" prophet = "^1.1.5" -nada-dsl = "^0.2.1" -py-nillion-client = "^0.2.1" -nada-numpy = "~0.1" # Any version starting with 0.1 -nillion-python-helpers = "~0.1" # Any version starting with 0.1 +nillion-python-helpers = "~0.2.3" # Works for 0.2.3 version +nada-numpy="~0.2" # Works for any 0.2.x version +nada-dsl="~0.3" # Works for any 0.3.x version +py-nillion-client="~0.3" # Works for any 0.3.x version [tool.poetry.group.dev.dependencies] pytest = "^8.2.0" diff --git a/tests/nada-tests/tests/activations.yaml b/tests/nada-tests/tests/activations.yaml index 8d0291e..4bfb365 100644 --- a/tests/nada-tests/tests/activations.yaml +++ b/tests/nada-tests/tests/activations.yaml @@ -1,38 +1,35 @@ ---- program: activations inputs: - secrets: - input_x_0: - SecretInteger: "-2" - input_x_1: - SecretInteger: "0" - input_x_2: - SecretInteger: "4" - input_x_3: - SecretInteger: "-121" - input_y_0: - SecretInteger: "-131072" - input_y_1: - SecretInteger: "0" - input_y_2: - SecretInteger: "262144" - input_y_3: - SecretInteger: "-7929856" - public_variables: {} + input_x_0: + SecretInteger: '-2' + input_x_1: + SecretInteger: '0' + input_x_2: + SecretInteger: '4' + input_x_3: + SecretInteger: '-121' + input_y_0: + SecretInteger: '-131072' + input_y_1: + SecretInteger: '0' + input_y_2: + SecretInteger: '262144' + input_y_3: + SecretInteger: '-7929856' expected_outputs: relu_x_0: - SecretInteger: "0" + SecretInteger: '0' relu_x_1: - SecretInteger: "0" + SecretInteger: '0' relu_x_2: - SecretInteger: "4" + SecretInteger: '4' relu_x_3: - SecretInteger: "0" + SecretInteger: '0' relu_y_0: - SecretInteger: "0" + SecretInteger: '0' relu_y_1: - SecretInteger: "0" + SecretInteger: '0' relu_y_2: - SecretInteger: "262144" + SecretInteger: '262144' relu_y_3: - SecretInteger: "0" + SecretInteger: '0' diff --git a/tests/nada-tests/tests/conv.yaml b/tests/nada-tests/tests/conv.yaml index 48c385d..a09acec 100644 --- a/tests/nada-tests/tests/conv.yaml +++ b/tests/nada-tests/tests/conv.yaml @@ -1,192 +1,189 @@ ---- program: conv inputs: - secrets: - input_x_0_0_2_1: - SecretInteger: "3" - conv2_weight_1_2_0_1: - SecretInteger: "3" - input_x_0_0_2_0: - SecretInteger: "3" - conv1_weight_0_0_1_1: - SecretInteger: "3" - conv2_weight_1_0_1_0: - SecretInteger: "3" - conv2_weight_1_1_0_1: - SecretInteger: "3" - input_y_1_0_0: - SecretInteger: "3" - input_y_0_2_1: - SecretInteger: "3" - input_y_0_3_0: - SecretInteger: "3" - input_x_0_1_1_0: - SecretInteger: "3" - input_y_0_3_1: - SecretInteger: "3" - conv1_weight_0_1_0_0: - SecretInteger: "3" - conv1_weight_0_2_0_0: - SecretInteger: "3" - input_y_1_2_0: - SecretInteger: "3" - input_y_0_1_1: - SecretInteger: "3" - input_x_0_1_2_1: - SecretInteger: "3" - input_y_2_0_1: - SecretInteger: "3" - input_x_0_0_1_0: - SecretInteger: "3" - conv1_weight_0_1_1_0: - SecretInteger: "3" - input_x_0_2_1_1: - SecretInteger: "3" - conv2_weight_0_1_0_1: - SecretInteger: "3" - input_y_1_0_1: - SecretInteger: "3" - input_y_2_1_0: - SecretInteger: "3" - input_y_1_1_1: - SecretInteger: "3" - input_x_0_1_2_0: - SecretInteger: "3" - input_x_0_0_1_1: - SecretInteger: "3" - conv1_weight_0_0_1_0: - SecretInteger: "3" - input_x_0_0_3_0: - SecretInteger: "3" - input_x_0_1_3_1: - SecretInteger: "3" - input_y_2_1_1: - SecretInteger: "3" - conv2_bias_1: - SecretInteger: "3" - input_y_1_3_1: - SecretInteger: "3" - conv2_weight_0_0_0_0: - SecretInteger: "3" - input_x_0_2_3_0: - SecretInteger: "3" - input_x_0_1_3_0: - SecretInteger: "3" - conv2_weight_0_1_1_0: - SecretInteger: "3" - conv2_weight_1_1_1_1: - SecretInteger: "3" - input_y_1_2_1: - SecretInteger: "3" - input_x_0_0_0_1: - SecretInteger: "3" - input_x_0_2_3_1: - SecretInteger: "3" - input_y_2_3_1: - SecretInteger: "3" - input_x_0_0_3_1: - SecretInteger: "3" - input_y_0_2_0: - SecretInteger: "3" - conv2_weight_0_0_0_1: - SecretInteger: "3" - conv1_weight_0_0_0_1: - SecretInteger: "3" - conv2_weight_1_2_0_0: - SecretInteger: "3" - input_x_0_2_1_0: - SecretInteger: "3" - conv1_weight_0_2_1_0: - SecretInteger: "3" - conv2_weight_0_2_0_0: - SecretInteger: "3" - input_y_1_1_0: - SecretInteger: "3" - input_y_0_0_1: - SecretInteger: "3" - input_x_0_1_0_1: - SecretInteger: "3" - conv2_weight_1_0_0_0: - SecretInteger: "3" - conv1_weight_0_1_1_1: - SecretInteger: "3" - input_x_0_2_0_0: - SecretInteger: "3" - conv1_weight_0_2_1_1: - SecretInteger: "3" - conv2_weight_0_1_0_0: - SecretInteger: "3" - input_y_2_0_0: - SecretInteger: "3" - input_y_2_2_0: - SecretInteger: "3" - input_y_1_3_0: - SecretInteger: "3" - conv2_weight_0_0_1_0: - SecretInteger: "3" - conv1_weight_0_0_0_0: - SecretInteger: "3" - input_x_0_1_0_0: - SecretInteger: "3" - input_x_0_2_2_0: - SecretInteger: "3" - conv2_bias_0: - SecretInteger: "3" - conv2_weight_0_2_0_1: - SecretInteger: "3" - input_x_0_0_0_0: - SecretInteger: "3" - conv2_weight_1_2_1_1: - SecretInteger: "3" - input_y_2_3_0: - SecretInteger: "3" - conv2_weight_0_2_1_0: - SecretInteger: "3" - conv2_weight_1_2_1_0: - SecretInteger: "3" - input_y_2_2_1: - SecretInteger: "3" - conv1_weight_0_2_0_1: - SecretInteger: "3" - input_y_0_0_0: - SecretInteger: "3" - conv2_weight_0_0_1_1: - SecretInteger: "3" - input_y_0_1_0: - SecretInteger: "3" - input_x_0_1_1_1: - SecretInteger: "3" - input_x_0_2_0_1: - SecretInteger: "3" - conv1_weight_0_1_0_1: - SecretInteger: "3" - conv2_weight_0_2_1_1: - SecretInteger: "3" - conv1_bias_0: - SecretInteger: "3" - input_x_0_2_2_1: - SecretInteger: "3" - conv2_weight_1_0_1_1: - SecretInteger: "3" - conv2_weight_0_1_1_1: - SecretInteger: "3" - conv2_weight_1_1_1_0: - SecretInteger: "3" - conv2_weight_1_1_0_0: - SecretInteger: "3" - conv2_weight_1_0_0_1: - SecretInteger: "3" - public_variables: {} + input_x_0_0_2_1: + SecretInteger: '3' + conv2_weight_1_2_0_1: + SecretInteger: '3' + input_x_0_0_2_0: + SecretInteger: '3' + conv1_weight_0_0_1_1: + SecretInteger: '3' + conv2_weight_1_0_1_0: + SecretInteger: '3' + conv2_weight_1_1_0_1: + SecretInteger: '3' + input_y_1_0_0: + SecretInteger: '3' + input_y_0_2_1: + SecretInteger: '3' + input_y_0_3_0: + SecretInteger: '3' + input_x_0_1_1_0: + SecretInteger: '3' + input_y_0_3_1: + SecretInteger: '3' + conv1_weight_0_1_0_0: + SecretInteger: '3' + conv1_weight_0_2_0_0: + SecretInteger: '3' + input_y_1_2_0: + SecretInteger: '3' + input_y_0_1_1: + SecretInteger: '3' + input_x_0_1_2_1: + SecretInteger: '3' + input_y_2_0_1: + SecretInteger: '3' + input_x_0_0_1_0: + SecretInteger: '3' + conv1_weight_0_1_1_0: + SecretInteger: '3' + input_x_0_2_1_1: + SecretInteger: '3' + conv2_weight_0_1_0_1: + SecretInteger: '3' + input_y_1_0_1: + SecretInteger: '3' + input_y_2_1_0: + SecretInteger: '3' + input_y_1_1_1: + SecretInteger: '3' + input_x_0_1_2_0: + SecretInteger: '3' + input_x_0_0_1_1: + SecretInteger: '3' + conv1_weight_0_0_1_0: + SecretInteger: '3' + input_x_0_0_3_0: + SecretInteger: '3' + input_x_0_1_3_1: + SecretInteger: '3' + input_y_2_1_1: + SecretInteger: '3' + conv2_bias_1: + SecretInteger: '3' + input_y_1_3_1: + SecretInteger: '3' + conv2_weight_0_0_0_0: + SecretInteger: '3' + input_x_0_2_3_0: + SecretInteger: '3' + input_x_0_1_3_0: + SecretInteger: '3' + conv2_weight_0_1_1_0: + SecretInteger: '3' + conv2_weight_1_1_1_1: + SecretInteger: '3' + input_y_1_2_1: + SecretInteger: '3' + input_x_0_0_0_1: + SecretInteger: '3' + input_x_0_2_3_1: + SecretInteger: '3' + input_y_2_3_1: + SecretInteger: '3' + input_x_0_0_3_1: + SecretInteger: '3' + input_y_0_2_0: + SecretInteger: '3' + conv2_weight_0_0_0_1: + SecretInteger: '3' + conv1_weight_0_0_0_1: + SecretInteger: '3' + conv2_weight_1_2_0_0: + SecretInteger: '3' + input_x_0_2_1_0: + SecretInteger: '3' + conv1_weight_0_2_1_0: + SecretInteger: '3' + conv2_weight_0_2_0_0: + SecretInteger: '3' + input_y_1_1_0: + SecretInteger: '3' + input_y_0_0_1: + SecretInteger: '3' + input_x_0_1_0_1: + SecretInteger: '3' + conv2_weight_1_0_0_0: + SecretInteger: '3' + conv1_weight_0_1_1_1: + SecretInteger: '3' + input_x_0_2_0_0: + SecretInteger: '3' + conv1_weight_0_2_1_1: + SecretInteger: '3' + conv2_weight_0_1_0_0: + SecretInteger: '3' + input_y_2_0_0: + SecretInteger: '3' + input_y_2_2_0: + SecretInteger: '3' + input_y_1_3_0: + SecretInteger: '3' + conv2_weight_0_0_1_0: + SecretInteger: '3' + conv1_weight_0_0_0_0: + SecretInteger: '3' + input_x_0_1_0_0: + SecretInteger: '3' + input_x_0_2_2_0: + SecretInteger: '3' + conv2_bias_0: + SecretInteger: '3' + conv2_weight_0_2_0_1: + SecretInteger: '3' + input_x_0_0_0_0: + SecretInteger: '3' + conv2_weight_1_2_1_1: + SecretInteger: '3' + input_y_2_3_0: + SecretInteger: '3' + conv2_weight_0_2_1_0: + SecretInteger: '3' + conv2_weight_1_2_1_0: + SecretInteger: '3' + input_y_2_2_1: + SecretInteger: '3' + conv1_weight_0_2_0_1: + SecretInteger: '3' + input_y_0_0_0: + SecretInteger: '3' + conv2_weight_0_0_1_1: + SecretInteger: '3' + input_y_0_1_0: + SecretInteger: '3' + input_x_0_1_1_1: + SecretInteger: '3' + input_x_0_2_0_1: + SecretInteger: '3' + conv1_weight_0_1_0_1: + SecretInteger: '3' + conv2_weight_0_2_1_1: + SecretInteger: '3' + conv1_bias_0: + SecretInteger: '3' + input_x_0_2_2_1: + SecretInteger: '3' + conv2_weight_1_0_1_1: + SecretInteger: '3' + conv2_weight_0_1_1_1: + SecretInteger: '3' + conv2_weight_1_1_1_0: + SecretInteger: '3' + conv2_weight_1_1_0_0: + SecretInteger: '3' + conv2_weight_1_0_0_1: + SecretInteger: '3' expected_outputs: x_conv_0_0_2_0: - SecretInteger: "3" + SecretInteger: '3' y_conv_0_1_0: - SecretInteger: "57" + SecretInteger: '57' y_conv_0_2_0: - SecretInteger: "30" + SecretInteger: '30' x_conv_0_0_0_0: - SecretInteger: "3" + SecretInteger: '3' x_conv_0_0_1_0: - SecretInteger: "3" + SecretInteger: '3' y_conv_0_0_0: - SecretInteger: "30" + SecretInteger: '30' diff --git a/tests/nada-tests/tests/distance.yaml b/tests/nada-tests/tests/distance.yaml index 370ae94..fd65787 100644 --- a/tests/nada-tests/tests/distance.yaml +++ b/tests/nada-tests/tests/distance.yaml @@ -1,68 +1,65 @@ ---- program: distance inputs: - secrets: - input_x_0_0: - SecretInteger: "1" - input_x_0_1: - SecretInteger: "2" - input_x_0_2: - SecretInteger: "3" - input_x_1_0: - SecretInteger: "4" - input_x_1_1: - SecretInteger: "5" - input_x_1_2: - SecretInteger: "6" - input_y_0_0: - SecretInteger: "1" - input_y_0_1: - SecretInteger: "2" - input_y_0_2: - SecretInteger: "3" - input_y_1_0: - SecretInteger: "4" - input_y_1_1: - SecretInteger: "5" - input_y_1_2: - SecretInteger: "6" - input_y_2_0: - SecretInteger: "7" - input_y_2_1: - SecretInteger: "8" - input_y_2_2: - SecretInteger: "9" - input_y_3_0: - SecretInteger: "10" - input_y_3_1: - SecretInteger: "11" - input_y_3_2: - SecretInteger: "12" - input_y_4_0: - SecretInteger: "13" - input_y_4_1: - SecretInteger: "14" - input_y_4_2: - SecretInteger: "15" - public_variables: {} + input_x_0_0: + SecretInteger: '1' + input_x_0_1: + SecretInteger: '2' + input_x_0_2: + SecretInteger: '3' + input_x_1_0: + SecretInteger: '4' + input_x_1_1: + SecretInteger: '5' + input_x_1_2: + SecretInteger: '6' + input_y_0_0: + SecretInteger: '1' + input_y_0_1: + SecretInteger: '2' + input_y_0_2: + SecretInteger: '3' + input_y_1_0: + SecretInteger: '4' + input_y_1_1: + SecretInteger: '5' + input_y_1_2: + SecretInteger: '6' + input_y_2_0: + SecretInteger: '7' + input_y_2_1: + SecretInteger: '8' + input_y_2_2: + SecretInteger: '9' + input_y_3_0: + SecretInteger: '10' + input_y_3_1: + SecretInteger: '11' + input_y_3_2: + SecretInteger: '12' + input_y_4_0: + SecretInteger: '13' + input_y_4_1: + SecretInteger: '14' + input_y_4_2: + SecretInteger: '15' expected_outputs: my_output_0_0: - SecretInteger: "14" + SecretInteger: '14' my_output_0_1: - SecretInteger: "32" + SecretInteger: '32' my_output_0_2: - SecretInteger: "50" + SecretInteger: '50' my_output_0_3: - SecretInteger: "68" + SecretInteger: '68' my_output_0_4: - SecretInteger: "86" + SecretInteger: '86' my_output_1_0: - SecretInteger: "32" + SecretInteger: '32' my_output_1_1: - SecretInteger: "77" + SecretInteger: '77' my_output_1_2: - SecretInteger: "122" + SecretInteger: '122' my_output_1_3: - SecretInteger: "167" + SecretInteger: '167' my_output_1_4: - SecretInteger: "212" + SecretInteger: '212' diff --git a/tests/nada-tests/tests/end-to-end.yaml b/tests/nada-tests/tests/end-to-end.yaml index b8f8280..2c65758 100644 --- a/tests/nada-tests/tests/end-to-end.yaml +++ b/tests/nada-tests/tests/end-to-end.yaml @@ -1,128 +1,125 @@ ---- program: end-to-end inputs: - secrets: - input_x_0_0_2_0: - SecretInteger: "3" - testmod_conv_module.conv.weight_1_2_0_1: - SecretInteger: "3" - testmod_conv_module.conv.weight_0_2_0_0: - SecretInteger: "3" - testmod_linear.weight_1_0: - SecretInteger: "3" - input_x_0_0_1_0: - SecretInteger: "3" - testmod_linear.weight_0_1: - SecretInteger: "3" - testmod_conv_module.conv.weight_0_0_0_0: - SecretInteger: "3" - testmod_conv_module.conv.weight_1_1_0_1: - SecretInteger: "3" - input_x_0_1_1_1: - SecretInteger: "3" - testmod_conv_module.conv.weight_0_1_1_0: - SecretInteger: "3" - input_x_0_2_0_0: - SecretInteger: "3" - input_x_0_0_0_2: - SecretInteger: "3" - input_x_0_0_2_2: - SecretInteger: "3" - testmod_conv_module.conv.weight_1_0_1_0: - SecretInteger: "3" - testmod_conv_module.conv.weight_1_0_1_1: - SecretInteger: "3" - testmod_conv_module.conv.bias_0: - SecretInteger: "3" - testmod_conv_module.conv.weight_1_2_1_0: - SecretInteger: "3" - input_x_0_1_0_2: - SecretInteger: "3" - testmod_linear.weight_0_0: - SecretInteger: "3" - input_x_0_2_2_0: - SecretInteger: "3" - testmod_conv_module.conv.weight_0_0_1_1: - SecretInteger: "3" - input_x_0_2_2_2: - SecretInteger: "3" - testmod_conv_module.conv.weight_0_2_1_0: - SecretInteger: "3" - testmod_conv_module.conv.bias_1: - SecretInteger: "3" - input_x_0_1_1_0: - SecretInteger: "3" - testmod_conv_module.conv.weight_1_0_0_1: - SecretInteger: "3" - input_x_0_0_1_2: - SecretInteger: "3" - testmod_conv_module.conv.weight_1_0_0_0: - SecretInteger: "3" - testmod_conv_module.conv.weight_0_1_0_0: - SecretInteger: "3" - testmod_conv_module.conv.weight_1_2_0_0: - SecretInteger: "3" - input_x_0_2_2_1: - SecretInteger: "3" - testmod_conv_module.conv.weight_0_1_0_1: - SecretInteger: "3" - input_x_0_1_0_0: - SecretInteger: "3" - testmod_conv_module.conv.weight_0_0_0_1: - SecretInteger: "3" - input_x_0_0_0_0: - SecretInteger: "3" - testmod_linear.weight_1_1: - SecretInteger: "3" - input_x_0_1_1_2: - SecretInteger: "3" - input_x_0_0_0_1: - SecretInteger: "3" - testmod_linear.bias_0: - SecretInteger: "3" - input_x_0_2_0_1: - SecretInteger: "3" - testmod_conv_module.conv.weight_1_1_1_0: - SecretInteger: "3" - input_x_0_2_0_2: - SecretInteger: "3" - input_x_0_1_2_0: - SecretInteger: "3" - testmod_conv_module.conv.weight_1_1_0_0: - SecretInteger: "3" - input_x_0_0_1_1: - SecretInteger: "3" - testmod_conv_module.conv.weight_0_2_0_1: - SecretInteger: "3" - input_x_0_2_1_1: - SecretInteger: "3" - testmod_conv_module.conv.weight_0_2_1_1: - SecretInteger: "3" - input_x_0_2_1_2: - SecretInteger: "3" - input_x_0_1_2_2: - SecretInteger: "3" - testmod_conv_module.conv.weight_1_1_1_1: - SecretInteger: "3" - testmod_linear.bias_1: - SecretInteger: "3" - input_x_0_1_0_1: - SecretInteger: "3" - input_x_0_2_1_0: - SecretInteger: "3" - testmod_conv_module.conv.weight_1_2_1_1: - SecretInteger: "3" - testmod_conv_module.conv.weight_0_0_1_0: - SecretInteger: "3" - testmod_conv_module.conv.weight_0_1_1_1: - SecretInteger: "3" - input_x_0_0_2_1: - SecretInteger: "3" - input_x_0_1_2_1: - SecretInteger: "3" - public_variables: {} + input_x_0_0_2_0: + SecretInteger: '3' + testmod_conv_module.conv.weight_1_2_0_1: + SecretInteger: '3' + testmod_conv_module.conv.weight_0_2_0_0: + SecretInteger: '3' + testmod_linear.weight_1_0: + SecretInteger: '3' + input_x_0_0_1_0: + SecretInteger: '3' + testmod_linear.weight_0_1: + SecretInteger: '3' + testmod_conv_module.conv.weight_0_0_0_0: + SecretInteger: '3' + testmod_conv_module.conv.weight_1_1_0_1: + SecretInteger: '3' + input_x_0_1_1_1: + SecretInteger: '3' + testmod_conv_module.conv.weight_0_1_1_0: + SecretInteger: '3' + input_x_0_2_0_0: + SecretInteger: '3' + input_x_0_0_0_2: + SecretInteger: '3' + input_x_0_0_2_2: + SecretInteger: '3' + testmod_conv_module.conv.weight_1_0_1_0: + SecretInteger: '3' + testmod_conv_module.conv.weight_1_0_1_1: + SecretInteger: '3' + testmod_conv_module.conv.bias_0: + SecretInteger: '3' + testmod_conv_module.conv.weight_1_2_1_0: + SecretInteger: '3' + input_x_0_1_0_2: + SecretInteger: '3' + testmod_linear.weight_0_0: + SecretInteger: '3' + input_x_0_2_2_0: + SecretInteger: '3' + testmod_conv_module.conv.weight_0_0_1_1: + SecretInteger: '3' + input_x_0_2_2_2: + SecretInteger: '3' + testmod_conv_module.conv.weight_0_2_1_0: + SecretInteger: '3' + testmod_conv_module.conv.bias_1: + SecretInteger: '3' + input_x_0_1_1_0: + SecretInteger: '3' + testmod_conv_module.conv.weight_1_0_0_1: + SecretInteger: '3' + input_x_0_0_1_2: + SecretInteger: '3' + testmod_conv_module.conv.weight_1_0_0_0: + SecretInteger: '3' + testmod_conv_module.conv.weight_0_1_0_0: + SecretInteger: '3' + testmod_conv_module.conv.weight_1_2_0_0: + SecretInteger: '3' + input_x_0_2_2_1: + SecretInteger: '3' + testmod_conv_module.conv.weight_0_1_0_1: + SecretInteger: '3' + input_x_0_1_0_0: + SecretInteger: '3' + testmod_conv_module.conv.weight_0_0_0_1: + SecretInteger: '3' + input_x_0_0_0_0: + SecretInteger: '3' + testmod_linear.weight_1_1: + SecretInteger: '3' + input_x_0_1_1_2: + SecretInteger: '3' + input_x_0_0_0_1: + SecretInteger: '3' + testmod_linear.bias_0: + SecretInteger: '3' + input_x_0_2_0_1: + SecretInteger: '3' + testmod_conv_module.conv.weight_1_1_1_0: + SecretInteger: '3' + input_x_0_2_0_2: + SecretInteger: '3' + input_x_0_1_2_0: + SecretInteger: '3' + testmod_conv_module.conv.weight_1_1_0_0: + SecretInteger: '3' + input_x_0_0_1_1: + SecretInteger: '3' + testmod_conv_module.conv.weight_0_2_0_1: + SecretInteger: '3' + input_x_0_2_1_1: + SecretInteger: '3' + testmod_conv_module.conv.weight_0_2_1_1: + SecretInteger: '3' + input_x_0_2_1_2: + SecretInteger: '3' + input_x_0_1_2_2: + SecretInteger: '3' + testmod_conv_module.conv.weight_1_1_1_1: + SecretInteger: '3' + testmod_linear.bias_1: + SecretInteger: '3' + input_x_0_1_0_1: + SecretInteger: '3' + input_x_0_2_1_0: + SecretInteger: '3' + testmod_conv_module.conv.weight_1_2_1_1: + SecretInteger: '3' + testmod_conv_module.conv.weight_0_0_1_0: + SecretInteger: '3' + testmod_conv_module.conv.weight_0_1_1_1: + SecretInteger: '3' + input_x_0_0_2_1: + SecretInteger: '3' + input_x_0_1_2_1: + SecretInteger: '3' expected_outputs: output_0: - SecretInteger: "669" + SecretInteger: '669' output_1: - SecretInteger: "669" + SecretInteger: '669' diff --git a/tests/nada-tests/tests/flatten.yaml b/tests/nada-tests/tests/flatten.yaml index 357093e..23d5945 100644 --- a/tests/nada-tests/tests/flatten.yaml +++ b/tests/nada-tests/tests/flatten.yaml @@ -1,38 +1,35 @@ ---- program: flatten inputs: - secrets: - input_x_0_0_0_0: - SecretInteger: "1" - input_x_0_0_1_0: - SecretInteger: "2" - input_x_0_1_0_0: - SecretInteger: "3" - input_x_0_1_1_0: - SecretInteger: "4" - input_x_1_0_0_0: - SecretInteger: "5" - input_x_1_0_1_0: - SecretInteger: "6" - input_x_1_1_0_0: - SecretInteger: "7" - input_x_1_1_1_0: - SecretInteger: "8" - public_variables: {} + input_x_0_0_0_0: + SecretInteger: '1' + input_x_0_0_1_0: + SecretInteger: '2' + input_x_0_1_0_0: + SecretInteger: '3' + input_x_0_1_1_0: + SecretInteger: '4' + input_x_1_0_0_0: + SecretInteger: '5' + input_x_1_0_1_0: + SecretInteger: '6' + input_x_1_1_0_0: + SecretInteger: '7' + input_x_1_1_1_0: + SecretInteger: '8' expected_outputs: x_flat_0: - SecretInteger: "1" + SecretInteger: '1' x_flat_1: - SecretInteger: "2" + SecretInteger: '2' x_flat_2: - SecretInteger: "3" + SecretInteger: '3' x_flat_3: - SecretInteger: "4" + SecretInteger: '4' x_flat_4: - SecretInteger: "5" + SecretInteger: '5' x_flat_5: - SecretInteger: "6" + SecretInteger: '6' x_flat_6: - SecretInteger: "7" + SecretInteger: '7' x_flat_7: - SecretInteger: "8" + SecretInteger: '8' diff --git a/tests/nada-tests/tests/linear_layers.yaml b/tests/nada-tests/tests/linear_layers.yaml index 0c4c87e..bfae38d 100644 --- a/tests/nada-tests/tests/linear_layers.yaml +++ b/tests/nada-tests/tests/linear_layers.yaml @@ -1,36 +1,33 @@ ---- program: linear_layers inputs: - secrets: - input_0: - SecretInteger: "1" - input_1: - SecretInteger: "2" - input_2: - SecretInteger: "3" - testmod_linear_0.weight_0_0: - SecretInteger: "1" - testmod_linear_0.weight_0_1: - SecretInteger: "2" - testmod_linear_0.weight_0_2: - SecretInteger: "3" - testmod_linear_0.weight_1_0: - SecretInteger: "4" - testmod_linear_0.weight_1_1: - SecretInteger: "5" - testmod_linear_0.weight_1_2: - SecretInteger: "6" - testmod_linear_0.bias_0: - SecretInteger: "4" - testmod_linear_0.bias_1: - SecretInteger: "5" - testmod_linear_1.weight_0_0: - SecretInteger: "3" - testmod_linear_1.weight_0_1: - SecretInteger: "4" - testmod_linear_1.bias_0: - SecretInteger: "5" - public_variables: {} + input_0: + SecretInteger: '1' + input_1: + SecretInteger: '2' + input_2: + SecretInteger: '3' + testmod_linear_0.weight_0_0: + SecretInteger: '1' + testmod_linear_0.weight_0_1: + SecretInteger: '2' + testmod_linear_0.weight_0_2: + SecretInteger: '3' + testmod_linear_0.weight_1_0: + SecretInteger: '4' + testmod_linear_0.weight_1_1: + SecretInteger: '5' + testmod_linear_0.weight_1_2: + SecretInteger: '6' + testmod_linear_0.bias_0: + SecretInteger: '4' + testmod_linear_0.bias_1: + SecretInteger: '5' + testmod_linear_1.weight_0_0: + SecretInteger: '3' + testmod_linear_1.weight_0_1: + SecretInteger: '4' + testmod_linear_1.bias_0: + SecretInteger: '5' expected_outputs: output_0: - SecretInteger: "207" + SecretInteger: '207' diff --git a/tests/nada-tests/tests/linear_regression.yaml b/tests/nada-tests/tests/linear_regression.yaml index 38e4f17..57988e6 100644 --- a/tests/nada-tests/tests/linear_regression.yaml +++ b/tests/nada-tests/tests/linear_regression.yaml @@ -1,26 +1,23 @@ ---- program: linear_regression inputs: - secrets: - input_0: - SecretInteger: "1" - input_1: - SecretInteger: "2" - input_2: - SecretInteger: "3" - input_3: - SecretInteger: "3" - testmod_coef_0: - SecretInteger: "4" - testmod_coef_1: - SecretInteger: "3" - testmod_coef_2: - SecretInteger: "2" - testmod_coef_3: - SecretInteger: "1" - testmod_intercept_0: - SecretInteger: "3" - public_variables: {} + input_0: + SecretInteger: '1' + input_1: + SecretInteger: '2' + input_2: + SecretInteger: '3' + input_3: + SecretInteger: '3' + testmod_coef_0: + SecretInteger: '4' + testmod_coef_1: + SecretInteger: '3' + testmod_coef_2: + SecretInteger: '2' + testmod_coef_3: + SecretInteger: '1' + testmod_intercept_0: + SecretInteger: '3' expected_outputs: - output: - SecretInteger: "22" + my_output: + SecretInteger: '22' diff --git a/tests/nada-tests/tests/load_state.yaml b/tests/nada-tests/tests/load_state.yaml index e95dbff..da649fa 100644 --- a/tests/nada-tests/tests/load_state.yaml +++ b/tests/nada-tests/tests/load_state.yaml @@ -1,70 +1,67 @@ ---- program: load_state inputs: - secrets: - module1_param1_0_0: - SecretInteger: "1" - module1_param1_0_1: - SecretInteger: "2" - module1_param1_1_0: - SecretInteger: "3" - module1_param1_1_1: - SecretInteger: "4" - module1_param1_2_0: - SecretInteger: "5" - module1_param1_2_1: - SecretInteger: "6" - module1_param2_0: - SecretInteger: "7" - module1_param2_1: - SecretInteger: "8" - public_variables: - module2_param1_0_0: - Integer: "1" - module2_param1_0_1: - Integer: "2" - module2_param1_1_0: - Integer: "3" - module2_param1_1_1: - Integer: "4" - module2_param1_2_0: - Integer: "5" - module2_param1_2_1: - Integer: "6" - module2_param2_0: - Integer: "7" - module2_param2_1: - Integer: "8" + module1_param1_0_0: + SecretInteger: '1' + module1_param1_0_1: + SecretInteger: '2' + module1_param1_1_0: + SecretInteger: '3' + module1_param1_1_1: + SecretInteger: '4' + module1_param1_2_0: + SecretInteger: '5' + module1_param1_2_1: + SecretInteger: '6' + module1_param2_0: + SecretInteger: '7' + module1_param2_1: + SecretInteger: '8' + module2_param1_0_0: + Integer: '1' + module2_param1_0_1: + Integer: '2' + module2_param1_1_0: + Integer: '3' + module2_param1_1_1: + Integer: '4' + module2_param1_2_0: + Integer: '5' + module2_param1_2_1: + Integer: '6' + module2_param2_0: + Integer: '7' + module2_param2_1: + Integer: '8' expected_outputs: module1_param1_0_0: - SecretInteger: "1" + SecretInteger: '1' module1_param1_0_1: - SecretInteger: "2" + SecretInteger: '2' module1_param1_1_0: - SecretInteger: "3" + SecretInteger: '3' module1_param1_1_1: - SecretInteger: "4" + SecretInteger: '4' module1_param1_2_0: - SecretInteger: "5" + SecretInteger: '5' module1_param1_2_1: - SecretInteger: "6" + SecretInteger: '6' module1_param2_0: - SecretInteger: "7" + SecretInteger: '7' module1_param2_1: - SecretInteger: "8" + SecretInteger: '8' module2_param1_0_0: - Integer: "1" + Integer: '1' module2_param1_0_1: - Integer: "2" + Integer: '2' module2_param1_1_0: - Integer: "3" + Integer: '3' module2_param1_1_1: - Integer: "4" + Integer: '4' module2_param1_2_0: - Integer: "5" + Integer: '5' module2_param1_2_1: - Integer: "6" + Integer: '6' module2_param2_0: - Integer: "7" + Integer: '7' module2_param2_1: - Integer: "8" + Integer: '8' diff --git a/tests/nada-tests/tests/logistic_regression.yaml b/tests/nada-tests/tests/logistic_regression.yaml index 37f5b75..3b3ae1d 100644 --- a/tests/nada-tests/tests/logistic_regression.yaml +++ b/tests/nada-tests/tests/logistic_regression.yaml @@ -1,50 +1,47 @@ ---- program: logistic_regression inputs: - secrets: - testmod_coef_1_2: - SecretInteger: "3" - testmod_intercept_2: - SecretInteger: "3" - testmod_coef_1_1: - SecretInteger: "3" - testmod_coef_0_0: - SecretInteger: "3" - input_1: - SecretInteger: "3" - testmod_coef_2_1: - SecretInteger: "3" - testmod_coef_1_0: - SecretInteger: "3" - testmod_coef_1_3: - SecretInteger: "3" - testmod_coef_0_2: - SecretInteger: "3" - input_3: - SecretInteger: "3" - testmod_intercept_0: - SecretInteger: "3" - testmod_coef_2_2: - SecretInteger: "3" - testmod_coef_0_3: - SecretInteger: "3" - input_2: - SecretInteger: "3" - testmod_coef_2_3: - SecretInteger: "3" - testmod_coef_0_1: - SecretInteger: "3" - testmod_intercept_1: - SecretInteger: "3" - input_0: - SecretInteger: "3" - testmod_coef_2_0: - SecretInteger: "3" - public_variables: {} + testmod_coef_1_2: + SecretInteger: '3' + testmod_intercept_2: + SecretInteger: '3' + testmod_coef_1_1: + SecretInteger: '3' + testmod_coef_0_0: + SecretInteger: '3' + input_1: + SecretInteger: '3' + testmod_coef_2_1: + SecretInteger: '3' + testmod_coef_1_0: + SecretInteger: '3' + testmod_coef_1_3: + SecretInteger: '3' + testmod_coef_0_2: + SecretInteger: '3' + input_3: + SecretInteger: '3' + testmod_intercept_0: + SecretInteger: '3' + testmod_coef_2_2: + SecretInteger: '3' + testmod_coef_0_3: + SecretInteger: '3' + input_2: + SecretInteger: '3' + testmod_coef_2_3: + SecretInteger: '3' + testmod_coef_0_1: + SecretInteger: '3' + testmod_intercept_1: + SecretInteger: '3' + input_0: + SecretInteger: '3' + testmod_coef_2_0: + SecretInteger: '3' expected_outputs: my_output_0: - SecretInteger: "39" + SecretInteger: '39' my_output_1: - SecretInteger: "39" + SecretInteger: '39' my_output_2: - SecretInteger: "39" + SecretInteger: '39' diff --git a/tests/nada-tests/tests/nested_modules.yaml b/tests/nada-tests/tests/nested_modules.yaml index aa0dedf..155d93b 100644 --- a/tests/nada-tests/tests/nested_modules.yaml +++ b/tests/nada-tests/tests/nested_modules.yaml @@ -1,40 +1,37 @@ ---- program: nested_modules inputs: - secrets: - input_0: - SecretInteger: "1" - input_1: - SecretInteger: "2" - testmod_mod.param1_0_0: - SecretInteger: "1" - testmod_mod.param1_0_1: - SecretInteger: "2" - testmod_mod.param1_1_0: - SecretInteger: "3" - testmod_mod.param1_1_1: - SecretInteger: "4" - testmod_mod.param1_2_0: - SecretInteger: "5" - testmod_mod.param1_2_1: - SecretInteger: "6" - testmod_mod.param2_0: - SecretInteger: "7" - testmod_mod.param2_1: - SecretInteger: "8" - testmod_mod.param2_2: - SecretInteger: "9" - testmod_param1_0: - SecretInteger: "1" - testmod_param1_1: - SecretInteger: "2" - testmod_param1_2: - SecretInteger: "3" - public_variables: {} + input_0: + SecretInteger: '1' + input_1: + SecretInteger: '2' + testmod_mod.param1_0_0: + SecretInteger: '1' + testmod_mod.param1_0_1: + SecretInteger: '2' + testmod_mod.param1_1_0: + SecretInteger: '3' + testmod_mod.param1_1_1: + SecretInteger: '4' + testmod_mod.param1_2_0: + SecretInteger: '5' + testmod_mod.param1_2_1: + SecretInteger: '6' + testmod_mod.param2_0: + SecretInteger: '7' + testmod_mod.param2_1: + SecretInteger: '8' + testmod_mod.param2_2: + SecretInteger: '9' + testmod_param1_0: + SecretInteger: '1' + testmod_param1_1: + SecretInteger: '2' + testmod_param1_2: + SecretInteger: '3' expected_outputs: output_0: - SecretInteger: "8" + SecretInteger: '8' output_1: - SecretInteger: "10" + SecretInteger: '10' output_2: - SecretInteger: "12" + SecretInteger: '12' diff --git a/tests/nada-tests/tests/parameters.yaml b/tests/nada-tests/tests/parameters.yaml index 0f21414..5188d82 100644 --- a/tests/nada-tests/tests/parameters.yaml +++ b/tests/nada-tests/tests/parameters.yaml @@ -1,34 +1,31 @@ ---- program: parameters inputs: - secrets: - input_0: - SecretInteger: "1" - input_1: - SecretInteger: "2" - testmod_param1_0_0: - SecretInteger: "1" - testmod_param1_0_1: - SecretInteger: "2" - testmod_param1_1_0: - SecretInteger: "3" - testmod_param1_1_1: - SecretInteger: "4" - testmod_param1_2_0: - SecretInteger: "5" - testmod_param1_2_1: - SecretInteger: "6" - testmod_param2_0: - SecretInteger: "7" - testmod_param2_1: - SecretInteger: "8" - testmod_param2_2: - SecretInteger: "9" - public_variables: {} + input_0: + SecretInteger: '1' + input_1: + SecretInteger: '2' + testmod_param1_0_0: + SecretInteger: '1' + testmod_param1_0_1: + SecretInteger: '2' + testmod_param1_1_0: + SecretInteger: '3' + testmod_param1_1_1: + SecretInteger: '4' + testmod_param1_2_0: + SecretInteger: '5' + testmod_param1_2_1: + SecretInteger: '6' + testmod_param2_0: + SecretInteger: '7' + testmod_param2_1: + SecretInteger: '8' + testmod_param2_2: + SecretInteger: '9' expected_outputs: output_0: - SecretInteger: "7" + SecretInteger: '7' output_1: - SecretInteger: "8" + SecretInteger: '8' output_2: - SecretInteger: "9" + SecretInteger: '9' diff --git a/tests/nada-tests/tests/pool.yaml b/tests/nada-tests/tests/pool.yaml index 9e9a23f..47e8e0c 100644 --- a/tests/nada-tests/tests/pool.yaml +++ b/tests/nada-tests/tests/pool.yaml @@ -1,278 +1,275 @@ ---- program: pool inputs: - secrets: - input_x_0_0_0_0: - SecretInteger: "4" - input_x_0_2_0_0: - SecretInteger: "4" - input_x_0_3_1_0: - SecretInteger: "4" - input_x_0_2_2_1: - SecretInteger: "4" - input_x_0_1_2_0: - SecretInteger: "4" - input_x_0_1_0_1: - SecretInteger: "4" - input_x_0_1_1_1: - SecretInteger: "4" - input_x_0_1_2_1: - SecretInteger: "4" - input_x_0_2_0_1: - SecretInteger: "4" - input_x_0_2_1_1: - SecretInteger: "4" - input_x_0_0_2_1: - SecretInteger: "4" - input_x_0_0_1_0: - SecretInteger: "4" - input_x_0_2_3_0: - SecretInteger: "4" - input_x_0_3_3_1: - SecretInteger: "4" - input_x_0_2_3_1: - SecretInteger: "4" - input_x_0_2_2_0: - SecretInteger: "4" - input_x_0_0_3_1: - SecretInteger: "4" - input_x_0_1_3_0: - SecretInteger: "4" - input_x_0_3_3_0: - SecretInteger: "4" - input_x_0_2_1_0: - SecretInteger: "4" - input_x_0_0_2_0: - SecretInteger: "4" - input_x_0_0_3_0: - SecretInteger: "4" - input_x_0_1_3_1: - SecretInteger: "4" - input_x_0_0_0_1: - SecretInteger: "4" - input_x_0_1_1_0: - SecretInteger: "4" - input_x_0_1_0_0: - SecretInteger: "4" - input_x_0_3_2_0: - SecretInteger: "4" - input_x_0_3_0_1: - SecretInteger: "4" - input_x_0_3_0_0: - SecretInteger: "4" - input_x_0_3_2_1: - SecretInteger: "4" - input_x_0_3_1_1: - SecretInteger: "4" - input_x_0_0_1_1: - SecretInteger: "4" - input_y_0_0_0: - SecretInteger: "4" - input_y_2_0_0: - SecretInteger: "4" - input_y_3_1_0: - SecretInteger: "4" - input_y_2_2_1: - SecretInteger: "4" - input_y_1_2_0: - SecretInteger: "4" - input_y_1_0_1: - SecretInteger: "4" - input_y_1_1_1: - SecretInteger: "4" - input_y_1_2_1: - SecretInteger: "4" - input_y_2_0_1: - SecretInteger: "4" - input_y_2_1_1: - SecretInteger: "4" - input_y_0_2_1: - SecretInteger: "4" - input_y_0_1_0: - SecretInteger: "4" - input_y_2_3_0: - SecretInteger: "4" - input_y_3_3_1: - SecretInteger: "4" - input_y_2_3_1: - SecretInteger: "4" - input_y_2_2_0: - SecretInteger: "4" - input_y_0_3_1: - SecretInteger: "4" - input_y_1_3_0: - SecretInteger: "4" - input_y_3_3_0: - SecretInteger: "4" - input_y_2_1_0: - SecretInteger: "4" - input_y_0_2_0: - SecretInteger: "4" - input_y_0_3_0: - SecretInteger: "4" - input_y_1_3_1: - SecretInteger: "4" - input_y_0_0_1: - SecretInteger: "4" - input_y_1_1_0: - SecretInteger: "4" - input_y_1_0_0: - SecretInteger: "4" - input_y_3_2_0: - SecretInteger: "4" - input_y_3_0_1: - SecretInteger: "4" - input_y_3_0_0: - SecretInteger: "4" - input_y_3_2_1: - SecretInteger: "4" - input_y_3_1_1: - SecretInteger: "4" - input_y_0_1_1: - SecretInteger: "4" - public_variables: {} + input_x_0_0_0_0: + SecretInteger: '4' + input_x_0_2_0_0: + SecretInteger: '4' + input_x_0_3_1_0: + SecretInteger: '4' + input_x_0_2_2_1: + SecretInteger: '4' + input_x_0_1_2_0: + SecretInteger: '4' + input_x_0_1_0_1: + SecretInteger: '4' + input_x_0_1_1_1: + SecretInteger: '4' + input_x_0_1_2_1: + SecretInteger: '4' + input_x_0_2_0_1: + SecretInteger: '4' + input_x_0_2_1_1: + SecretInteger: '4' + input_x_0_0_2_1: + SecretInteger: '4' + input_x_0_0_1_0: + SecretInteger: '4' + input_x_0_2_3_0: + SecretInteger: '4' + input_x_0_3_3_1: + SecretInteger: '4' + input_x_0_2_3_1: + SecretInteger: '4' + input_x_0_2_2_0: + SecretInteger: '4' + input_x_0_0_3_1: + SecretInteger: '4' + input_x_0_1_3_0: + SecretInteger: '4' + input_x_0_3_3_0: + SecretInteger: '4' + input_x_0_2_1_0: + SecretInteger: '4' + input_x_0_0_2_0: + SecretInteger: '4' + input_x_0_0_3_0: + SecretInteger: '4' + input_x_0_1_3_1: + SecretInteger: '4' + input_x_0_0_0_1: + SecretInteger: '4' + input_x_0_1_1_0: + SecretInteger: '4' + input_x_0_1_0_0: + SecretInteger: '4' + input_x_0_3_2_0: + SecretInteger: '4' + input_x_0_3_0_1: + SecretInteger: '4' + input_x_0_3_0_0: + SecretInteger: '4' + input_x_0_3_2_1: + SecretInteger: '4' + input_x_0_3_1_1: + SecretInteger: '4' + input_x_0_0_1_1: + SecretInteger: '4' + input_y_0_0_0: + SecretInteger: '4' + input_y_2_0_0: + SecretInteger: '4' + input_y_3_1_0: + SecretInteger: '4' + input_y_2_2_1: + SecretInteger: '4' + input_y_1_2_0: + SecretInteger: '4' + input_y_1_0_1: + SecretInteger: '4' + input_y_1_1_1: + SecretInteger: '4' + input_y_1_2_1: + SecretInteger: '4' + input_y_2_0_1: + SecretInteger: '4' + input_y_2_1_1: + SecretInteger: '4' + input_y_0_2_1: + SecretInteger: '4' + input_y_0_1_0: + SecretInteger: '4' + input_y_2_3_0: + SecretInteger: '4' + input_y_3_3_1: + SecretInteger: '4' + input_y_2_3_1: + SecretInteger: '4' + input_y_2_2_0: + SecretInteger: '4' + input_y_0_3_1: + SecretInteger: '4' + input_y_1_3_0: + SecretInteger: '4' + input_y_3_3_0: + SecretInteger: '4' + input_y_2_1_0: + SecretInteger: '4' + input_y_0_2_0: + SecretInteger: '4' + input_y_0_3_0: + SecretInteger: '4' + input_y_1_3_1: + SecretInteger: '4' + input_y_0_0_1: + SecretInteger: '4' + input_y_1_1_0: + SecretInteger: '4' + input_y_1_0_0: + SecretInteger: '4' + input_y_3_2_0: + SecretInteger: '4' + input_y_3_0_1: + SecretInteger: '4' + input_y_3_0_0: + SecretInteger: '4' + input_y_3_2_1: + SecretInteger: '4' + input_y_3_1_1: + SecretInteger: '4' + input_y_0_1_1: + SecretInteger: '4' expected_outputs: x_pool2_0_2_1_1: - SecretInteger: "2" + SecretInteger: '2' x_pool2_0_1_2_0: - SecretInteger: "1" + SecretInteger: '1' x_pool2_0_3_2_1: - SecretInteger: "1" + SecretInteger: '1' x_pool1_0_2_1_0: - SecretInteger: "4" + SecretInteger: '4' x_pool1_0_3_0_0: - SecretInteger: "4" + SecretInteger: '4' x_pool1_0_1_1_0: - SecretInteger: "4" + SecretInteger: '4' x_pool2_0_3_0_0: - SecretInteger: "1" + SecretInteger: '1' x_pool2_0_3_1_1: - SecretInteger: "2" + SecretInteger: '2' x_pool1_0_3_2_0: - SecretInteger: "4" + SecretInteger: '4' x_pool1_0_0_1_0: - SecretInteger: "4" + SecretInteger: '4' x_pool1_0_3_1_0: - SecretInteger: "4" + SecretInteger: '4' x_pool2_0_2_1_0: - SecretInteger: "2" + SecretInteger: '2' x_pool1_0_0_0_0: - SecretInteger: "4" + SecretInteger: '4' x_pool2_0_1_0_1: - SecretInteger: "1" + SecretInteger: '1' x_pool2_0_1_0_0: - SecretInteger: "1" + SecretInteger: '1' x_pool2_0_2_2_1: - SecretInteger: "1" + SecretInteger: '1' x_pool2_0_0_2_1: - SecretInteger: "1" + SecretInteger: '1' x_pool2_0_0_0_0: - SecretInteger: "1" + SecretInteger: '1' x_pool2_0_1_1_1: - SecretInteger: "2" + SecretInteger: '2' x_pool1_0_0_2_0: - SecretInteger: "4" + SecretInteger: '4' x_pool2_0_3_2_0: - SecretInteger: "1" + SecretInteger: '1' x_pool1_0_1_2_0: - SecretInteger: "4" + SecretInteger: '4' x_pool1_0_2_0_0: - SecretInteger: "4" + SecretInteger: '4' x_pool2_0_0_1_0: - SecretInteger: "2" + SecretInteger: '2' x_pool2_0_3_1_0: - SecretInteger: "2" + SecretInteger: '2' x_pool2_0_1_2_1: - SecretInteger: "1" + SecretInteger: '1' x_pool2_0_1_1_0: - SecretInteger: "2" + SecretInteger: '2' x_pool2_0_2_2_0: - SecretInteger: "1" + SecretInteger: '1' x_pool2_0_2_0_1: - SecretInteger: "1" + SecretInteger: '1' x_pool1_0_1_0_0: - SecretInteger: "4" + SecretInteger: '4' x_pool2_0_3_0_1: - SecretInteger: "1" + SecretInteger: '1' x_pool1_0_2_2_0: - SecretInteger: "4" + SecretInteger: '4' x_pool2_0_0_1_1: - SecretInteger: "2" + SecretInteger: '2' x_pool2_0_0_0_1: - SecretInteger: "1" + SecretInteger: '1' x_pool2_0_0_2_0: - SecretInteger: "1" + SecretInteger: '1' x_pool2_0_2_0_0: - SecretInteger: "1" + SecretInteger: '1' y_pool2_2_1_1: - SecretInteger: "2" + SecretInteger: '2' y_pool2_1_2_0: - SecretInteger: "1" + SecretInteger: '1' y_pool2_3_2_1: - SecretInteger: "1" + SecretInteger: '1' y_pool1_2_1_0: - SecretInteger: "4" + SecretInteger: '4' y_pool1_3_0_0: - SecretInteger: "4" + SecretInteger: '4' y_pool1_1_1_0: - SecretInteger: "4" + SecretInteger: '4' y_pool2_3_0_0: - SecretInteger: "1" + SecretInteger: '1' y_pool2_3_1_1: - SecretInteger: "2" + SecretInteger: '2' y_pool1_3_2_0: - SecretInteger: "4" + SecretInteger: '4' y_pool1_0_1_0: - SecretInteger: "4" + SecretInteger: '4' y_pool1_3_1_0: - SecretInteger: "4" + SecretInteger: '4' y_pool2_2_1_0: - SecretInteger: "2" + SecretInteger: '2' y_pool1_0_0_0: - SecretInteger: "4" + SecretInteger: '4' y_pool2_1_0_1: - SecretInteger: "1" + SecretInteger: '1' y_pool2_1_0_0: - SecretInteger: "1" + SecretInteger: '1' y_pool2_2_2_1: - SecretInteger: "1" + SecretInteger: '1' y_pool2_0_2_1: - SecretInteger: "1" + SecretInteger: '1' y_pool2_0_0_0: - SecretInteger: "1" + SecretInteger: '1' y_pool2_1_1_1: - SecretInteger: "2" + SecretInteger: '2' y_pool1_0_2_0: - SecretInteger: "4" + SecretInteger: '4' y_pool2_3_2_0: - SecretInteger: "1" + SecretInteger: '1' y_pool1_1_2_0: - SecretInteger: "4" + SecretInteger: '4' y_pool1_2_0_0: - SecretInteger: "4" + SecretInteger: '4' y_pool2_0_1_0: - SecretInteger: "2" + SecretInteger: '2' y_pool2_3_1_0: - SecretInteger: "2" + SecretInteger: '2' y_pool2_1_2_1: - SecretInteger: "1" + SecretInteger: '1' y_pool2_1_1_0: - SecretInteger: "2" + SecretInteger: '2' y_pool2_2_2_0: - SecretInteger: "1" + SecretInteger: '1' y_pool2_2_0_1: - SecretInteger: "1" + SecretInteger: '1' y_pool1_1_0_0: - SecretInteger: "4" + SecretInteger: '4' y_pool2_3_0_1: - SecretInteger: "1" + SecretInteger: '1' y_pool1_2_2_0: - SecretInteger: "4" + SecretInteger: '4' y_pool2_0_1_1: - SecretInteger: "2" + SecretInteger: '2' y_pool2_0_0_1: - SecretInteger: "1" + SecretInteger: '1' y_pool2_0_2_0: - SecretInteger: "1" + SecretInteger: '1' y_pool2_2_0_0: - SecretInteger: "1" + SecretInteger: '1' diff --git a/tests/nada-tests/tests/prophet.yaml b/tests/nada-tests/tests/prophet.yaml index 429838c..ef2318d 100644 --- a/tests/nada-tests/tests/prophet.yaml +++ b/tests/nada-tests/tests/prophet.yaml @@ -1,56 +1,53 @@ ---- program: prophet inputs: - secrets: - my_prophet_m_0_0: - SecretInteger: "3" - my_prophet_beta_0_4: - SecretInteger: "3" - my_prophet_beta_0_5: - SecretInteger: "3" - my_prophet_changepoints_t_1: - SecretInteger: "3" - my_prophet_delta_0_1: - SecretInteger: "3" - my_prophet_y_scale_0: - SecretInteger: "3" - floor_2: - SecretInteger: "3" - my_prophet_delta_0_0: - SecretInteger: "3" - floor_3: - SecretInteger: "3" - t_2: - SecretInteger: "3" - floor_0: - SecretInteger: "3" - my_prophet_changepoints_t_0: - SecretInteger: "3" - my_prophet_beta_0_1: - SecretInteger: "3" - t_1: - SecretInteger: "3" - my_prophet_beta_0_3: - SecretInteger: "3" - my_prophet_k_0_0: - SecretInteger: "3" - my_prophet_beta_0_2: - SecretInteger: "3" - floor_1: - SecretInteger: "3" - t_0: - SecretInteger: "3" - t_3: - SecretInteger: "3" - my_prophet_beta_0_0: - SecretInteger: "3" - public_variables: {} + my_prophet_m_0_0: + SecretInteger: '3' + my_prophet_beta_0_4: + SecretInteger: '3' + my_prophet_beta_0_5: + SecretInteger: '3' + my_prophet_changepoints_t_1: + SecretInteger: '3' + my_prophet_delta_0_1: + SecretInteger: '3' + my_prophet_y_scale_0: + SecretInteger: '3' + floor_2: + SecretInteger: '3' + my_prophet_delta_0_0: + SecretInteger: '3' + floor_3: + SecretInteger: '3' + t_2: + SecretInteger: '3' + floor_0: + SecretInteger: '3' + my_prophet_changepoints_t_0: + SecretInteger: '3' + my_prophet_beta_0_1: + SecretInteger: '3' + t_1: + SecretInteger: '3' + my_prophet_beta_0_3: + SecretInteger: '3' + my_prophet_k_0_0: + SecretInteger: '3' + my_prophet_beta_0_2: + SecretInteger: '3' + floor_1: + SecretInteger: '3' + t_0: + SecretInteger: '3' + t_3: + SecretInteger: '3' + my_prophet_beta_0_0: + SecretInteger: '3' expected_outputs: forecast_2: - SecretInteger: "3" + SecretInteger: '3' forecast_0: - SecretInteger: "3" + SecretInteger: '3' forecast_3: - SecretInteger: "3" + SecretInteger: '3' forecast_1: - SecretInteger: "2" + SecretInteger: '2' diff --git a/tests/python-tests/test_model_client.py b/tests/python-tests/test_model_client.py index 5207e29..5534935 100644 --- a/tests/python-tests/test_model_client.py +++ b/tests/python-tests/test_model_client.py @@ -62,19 +62,6 @@ def test_sklearn_3(self): assert "test_model_coef_0_1" in secrets.keys() assert "test_model_coef_0_2" in secrets.keys() - def test_sklearn_4(self): - log_reg = LogisticRegression(fit_intercept=False) - - X = np.array([[1, 2, 3], [2, 3, 4]]) - y = np.array([0, 1]) - - log_reg_fit = log_reg.fit(X, y) - - model_client = SklearnClient(log_reg_fit) - - with pytest.raises(NotImplementedError): - model_client.export_state_as_secrets("test_model", nillion.SecretInteger) - def test_custom_client_1(self): class MyModelClient(ModelClient): def __init__(self) -> None: diff --git a/tests/test_all_nada.py b/tests/test_all_nada.py index 523f188..0453130 100644 --- a/tests/test_all_nada.py +++ b/tests/test_all_nada.py @@ -25,7 +25,7 @@ "multi_layer_perceptron", "neural_net", "spam_detection", - # "time_series", + "time_series", ] TESTS = [("tests/nada-tests/", test) for test in TESTS] + [ @@ -39,20 +39,21 @@ def testname(request): def build_nada(test_dir): - print(test_dir) result = subprocess.run( ["nada", "build", test_dir[1]], cwd=test_dir[0], capture_output=True, text=True ) - if result.returncode != 0: - pytest.fail(f"Build failed: {result.stderr}") + err = result.stderr.lower() + result.stdout.lower() + if result.returncode != 0 or "error" in err or "fail" in err: + pytest.fail(f"Build {test_dir}:\n{result.stdout + result.stderr}") def run_nada(test_dir): result = subprocess.run( ["nada", "test", test_dir[1]], cwd=test_dir[0], capture_output=True, text=True ) - if result.returncode != 0: - pytest.fail(f"Tests failed: {result.stderr}") + err = result.stderr.lower() + result.stdout.lower() + if result.returncode != 0 or "error" in err or "fail" in err: + pytest.fail(f"Run {test_dir}:\n{result.stdout + result.stderr}") class TestSuite: @@ -87,7 +88,7 @@ def test_client(): assert parties is not None - secrets = nillion.Secrets( + secrets = nillion.NadaValues( na_client.concat( [ na_client.array(np.ones((3, 3)), "A", nillion.SecretInteger), @@ -98,13 +99,11 @@ def test_client(): assert secrets is not None - public_variables = nillion.PublicVariables( + public_variables = nillion.NadaValues( na_client.concat( [ - na_client.array(np.zeros((4, 4)), "C", nillion.PublicVariableInteger), - na_client.array( - np.zeros((3, 3)), "D", nillion.PublicVariableUnsignedInteger - ), + na_client.array(np.zeros((4, 4)), "C", nillion.Integer), + na_client.array(np.zeros((3, 3)), "D", nillion.UnsignedInteger), ] ) )