From e3623dec5b6da2c2f359b1136d89e0dd8fa0c5e1 Mon Sep 17 00:00:00 2001 From: ltcptgeneral <35508619+ltcptgeneral@users.noreply.github.com> Date: Fri, 1 May 2020 16:07:57 -0500 Subject: [PATCH] fixes --- analysis-master/analysis.egg-info/PKG-INFO | 14 + analysis-master/analysis.egg-info/SOURCES.txt | 15 + .../analysis.egg-info/dependency_links.txt | 1 + .../analysis.egg-info/requires.txt | 6 + .../analysis.egg-info/top_level.txt | 1 + analysis-master/build.sh | 1 + .../build/lib/analysis/__init__.py | 0 .../build/lib/analysis/analysis.py | 923 ++++++++++++++++++ analysis-master/build/lib/analysis/glicko2.py | 99 ++ .../build/lib/analysis/metrics/__init__.py | 0 .../build/lib/analysis/metrics/elo.py | 7 + .../build/lib/analysis/metrics/glicko2.py | 99 ++ .../build/lib/analysis/metrics/trueskill.py | 907 +++++++++++++++++ .../build/lib/analysis/regression.py | 220 +++++ .../build/lib/analysis/titanlearn.py | 122 +++ .../build/lib/analysis/trueskill.py | 907 +++++++++++++++++ .../build/lib/analysis/visualization.py | 34 + .../dist/analysis-1.0.0.10-py3-none-any.whl | Bin 0 -> 20742 bytes analysis-master/dist/analysis-1.0.0.10.tar.gz | Bin 0 -> 18950 bytes .../dist/analysis-1.0.0.11-py3-none-any.whl | Bin 0 -> 20782 bytes analysis-master/dist/analysis-1.0.0.11.tar.gz | Bin 0 -> 19444 bytes .../dist/analysis-1.0.0.12-py3-none-any.whl | Bin 0 -> 32026 bytes analysis-master/dist/analysis-1.0.0.12.tar.gz | Bin 0 -> 21001 bytes .../dist/analysis-1.0.0.8-py3-none-any.whl | Bin 0 -> 20459 bytes analysis-master/dist/analysis-1.0.0.8.tar.gz | Bin 0 -> 18782 bytes .../dist/analysis-1.0.0.9-py3-none-any.whl | Bin 0 -> 20332 bytes analysis-master/dist/analysis-1.0.0.9.tar.gz | Bin 0 -> 19036 bytes analysis-master/docker/Dockerfile | 5 + analysis-master/docker/start-docker.sh | 3 + analysis-master/requirements.txt | 6 + analysis-master/setup.py | 26 + 31 files changed, 3396 insertions(+) create mode 100644 analysis-master/analysis.egg-info/PKG-INFO create mode 100644 analysis-master/analysis.egg-info/SOURCES.txt create mode 100644 analysis-master/analysis.egg-info/dependency_links.txt create mode 100644 analysis-master/analysis.egg-info/requires.txt create mode 100644 analysis-master/analysis.egg-info/top_level.txt create mode 100644 analysis-master/build.sh create mode 100644 analysis-master/build/lib/analysis/__init__.py create mode 100644 analysis-master/build/lib/analysis/analysis.py create mode 100644 analysis-master/build/lib/analysis/glicko2.py create mode 100644 analysis-master/build/lib/analysis/metrics/__init__.py create mode 100644 analysis-master/build/lib/analysis/metrics/elo.py create mode 100644 analysis-master/build/lib/analysis/metrics/glicko2.py create mode 100644 analysis-master/build/lib/analysis/metrics/trueskill.py create mode 100644 analysis-master/build/lib/analysis/regression.py create mode 100644 analysis-master/build/lib/analysis/titanlearn.py create mode 100644 analysis-master/build/lib/analysis/trueskill.py create mode 100644 analysis-master/build/lib/analysis/visualization.py create mode 100644 analysis-master/dist/analysis-1.0.0.10-py3-none-any.whl create mode 100644 analysis-master/dist/analysis-1.0.0.10.tar.gz create mode 100644 analysis-master/dist/analysis-1.0.0.11-py3-none-any.whl create mode 100644 analysis-master/dist/analysis-1.0.0.11.tar.gz create mode 100644 analysis-master/dist/analysis-1.0.0.12-py3-none-any.whl create mode 100644 analysis-master/dist/analysis-1.0.0.12.tar.gz create mode 100644 analysis-master/dist/analysis-1.0.0.8-py3-none-any.whl create mode 100644 analysis-master/dist/analysis-1.0.0.8.tar.gz create mode 100644 analysis-master/dist/analysis-1.0.0.9-py3-none-any.whl create mode 100644 analysis-master/dist/analysis-1.0.0.9.tar.gz create mode 100644 analysis-master/docker/Dockerfile create mode 100644 analysis-master/docker/start-docker.sh create mode 100644 analysis-master/requirements.txt create mode 100644 analysis-master/setup.py diff --git a/analysis-master/analysis.egg-info/PKG-INFO b/analysis-master/analysis.egg-info/PKG-INFO new file mode 100644 index 00000000..83058193 --- /dev/null +++ b/analysis-master/analysis.egg-info/PKG-INFO @@ -0,0 +1,14 @@ +Metadata-Version: 2.1 +Name: analysis +Version: 1.0.0.12 +Summary: analysis package developed by Titan Scouting for The Red Alliance +Home-page: https://github.com/titanscout2022/tr2022-strategy +Author: The Titan Scouting Team +Author-email: titanscout2022@gmail.com +License: GNU General Public License v3.0 +Description: UNKNOWN +Platform: UNKNOWN +Classifier: Programming Language :: Python :: 3 +Classifier: Operating System :: OS Independent +Requires-Python: >=3.6 +Description-Content-Type: text/markdown diff --git a/analysis-master/analysis.egg-info/SOURCES.txt b/analysis-master/analysis.egg-info/SOURCES.txt new file mode 100644 index 00000000..2d8be231 --- /dev/null +++ b/analysis-master/analysis.egg-info/SOURCES.txt @@ -0,0 +1,15 @@ +setup.py +analysis/__init__.py +analysis/analysis.py +analysis/regression.py +analysis/titanlearn.py +analysis/visualization.py +analysis.egg-info/PKG-INFO +analysis.egg-info/SOURCES.txt +analysis.egg-info/dependency_links.txt +analysis.egg-info/requires.txt +analysis.egg-info/top_level.txt +analysis/metrics/__init__.py +analysis/metrics/elo.py +analysis/metrics/glicko2.py +analysis/metrics/trueskill.py \ No newline at end of file diff --git a/analysis-master/analysis.egg-info/dependency_links.txt b/analysis-master/analysis.egg-info/dependency_links.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/analysis-master/analysis.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/analysis-master/analysis.egg-info/requires.txt b/analysis-master/analysis.egg-info/requires.txt new file mode 100644 index 00000000..6868226f --- /dev/null +++ b/analysis-master/analysis.egg-info/requires.txt @@ -0,0 +1,6 @@ +numba +numpy +scipy +scikit-learn +six +matplotlib diff --git a/analysis-master/analysis.egg-info/top_level.txt b/analysis-master/analysis.egg-info/top_level.txt new file mode 100644 index 00000000..09ad3be3 --- /dev/null +++ b/analysis-master/analysis.egg-info/top_level.txt @@ -0,0 +1 @@ +analysis diff --git a/analysis-master/build.sh b/analysis-master/build.sh new file mode 100644 index 00000000..de0cce90 --- /dev/null +++ b/analysis-master/build.sh @@ -0,0 +1 @@ +python setup.py sdist bdist_wheel || python3 setup.py sdist bdist_wheel \ No newline at end of file diff --git a/analysis-master/build/lib/analysis/__init__.py b/analysis-master/build/lib/analysis/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/analysis-master/build/lib/analysis/analysis.py b/analysis-master/build/lib/analysis/analysis.py new file mode 100644 index 00000000..c13aef90 --- /dev/null +++ b/analysis-master/build/lib/analysis/analysis.py @@ -0,0 +1,923 @@ +# Titan Robotics Team 2022: Data Analysis Module +# Written by Arthur Lu & Jacob Levine +# Notes: +# this should be imported as a python module using 'from analysis import analysis' +# this should be included in the local directory or environment variable +# this module has been optimized for multhreaded computing +# current benchmark of optimization: 1.33 times faster +# setup: + +__version__ = "1.2.0.004" + +# changelog should be viewed using print(analysis.__changelog__) +__changelog__ = """changelog: + 1.2.0.004: + - fixed __all__ to reflected the correct functions and classes + - fixed CorrelationTests and StatisticalTests class functions to require self invocation + - added missing math import + - fixed KNN class functions to require self invocation + - fixed Metrics class functions to require self invocation + - various spelling fixes in CorrelationTests and StatisticalTests + 1.2.0.003: + - bug fixes with CorrelationTests and StatisticalTests + - moved glicko2 and trueskill to the metrics subpackage + - moved elo to a new metrics subpackage + 1.2.0.002: + - fixed docs + 1.2.0.001: + - fixed docs + 1.2.0.000: + - cleaned up wild card imports with scipy and sklearn + - added CorrelationTests class + - added StatisticalTests class + - added several correlation tests to CorrelationTests + - added several statistical tests to StatisticalTests + 1.1.13.009: + - moved elo, glicko2, trueskill functions under class Metrics + 1.1.13.008: + - moved Glicko2 to a seperate package + 1.1.13.007: + - fixed bug with trueskill + 1.1.13.006: + - cleaned up imports + 1.1.13.005: + - cleaned up package + 1.1.13.004: + - small fixes to regression to improve performance + 1.1.13.003: + - filtered nans from regression + 1.1.13.002: + - removed torch requirement, and moved Regression back to regression.py + 1.1.13.001: + - bug fix with linear regression not returning a proper value + - cleaned up regression + - fixed bug with polynomial regressions + 1.1.13.000: + - fixed all regressions to now properly work + 1.1.12.006: + - fixed bg with a division by zero in histo_analysis + 1.1.12.005: + - fixed numba issues by removing numba from elo, glicko2 and trueskill + 1.1.12.004: + - renamed gliko to glicko + 1.1.12.003: + - removed depreciated code + 1.1.12.002: + - removed team first time trueskill instantiation in favor of integration in superscript.py + 1.1.12.001: + - improved readibility of regression outputs by stripping tensor data + - used map with lambda to acheive the improved readibility + - lost numba jit support with regression, and generated_jit hangs at execution + - TODO: reimplement correct numba integration in regression + 1.1.12.000: + - temporarily fixed polynomial regressions by using sklearn's PolynomialFeatures + 1.1.11.010: + - alphabeticaly ordered import lists + 1.1.11.009: + - bug fixes + 1.1.11.008: + - bug fixes + 1.1.11.007: + - bug fixes + 1.1.11.006: + - tested min and max + - bug fixes + 1.1.11.005: + - added min and max in basic_stats + 1.1.11.004: + - bug fixes + 1.1.11.003: + - bug fixes + 1.1.11.002: + - consolidated metrics + - fixed __all__ + 1.1.11.001: + - added test/train split to RandomForestClassifier and RandomForestRegressor + 1.1.11.000: + - added RandomForestClassifier and RandomForestRegressor + - note: untested + 1.1.10.000: + - added numba.jit to remaining functions + 1.1.9.002: + - kernelized PCA and KNN + 1.1.9.001: + - fixed bugs with SVM and NaiveBayes + 1.1.9.000: + - added SVM class, subclasses, and functions + - note: untested + 1.1.8.000: + - added NaiveBayes classification engine + - note: untested + 1.1.7.000: + - added knn() + - added confusion matrix to decisiontree() + 1.1.6.002: + - changed layout of __changelog to be vscode friendly + 1.1.6.001: + - added additional hyperparameters to decisiontree() + 1.1.6.000: + - fixed __version__ + - fixed __all__ order + - added decisiontree() + 1.1.5.003: + - added pca + 1.1.5.002: + - reduced import list + - added kmeans clustering engine + 1.1.5.001: + - simplified regression by using .to(device) + 1.1.5.000: + - added polynomial regression to regression(); untested + 1.1.4.000: + - added trueskill() + 1.1.3.002: + - renamed regression class to Regression, regression_engine() to regression gliko2_engine class to Gliko2 + 1.1.3.001: + - changed glicko2() to return tuple instead of array + 1.1.3.000: + - added glicko2_engine class and glicko() + - verified glicko2() accuracy + 1.1.2.003: + - fixed elo() + 1.1.2.002: + - added elo() + - elo() has bugs to be fixed + 1.1.2.001: + - readded regrression import + 1.1.2.000: + - integrated regression.py as regression class + - removed regression import + - fixed metadata for regression class + - fixed metadata for analysis class + 1.1.1.001: + - regression_engine() bug fixes, now actaully regresses + 1.1.1.000: + - added regression_engine() + - added all regressions except polynomial + 1.1.0.007: + - updated _init_device() + 1.1.0.006: + - removed useless try statements + 1.1.0.005: + - removed impossible outcomes + 1.1.0.004: + - added performance metrics (r^2, mse, rms) + 1.1.0.003: + - resolved nopython mode for mean, median, stdev, variance + 1.1.0.002: + - snapped (removed) majority of uneeded imports + - forced object mode (bad) on all jit + - TODO: stop numba complaining about not being able to compile in nopython mode + 1.1.0.001: + - removed from sklearn import * to resolve uneeded wildcard imports + 1.1.0.000: + - removed c_entities,nc_entities,obstacles,objectives from __all__ + - applied numba.jit to all functions + - depreciated and removed stdev_z_split + - cleaned up histo_analysis to include numpy and numba.jit optimizations + - depreciated and removed all regression functions in favor of future pytorch optimizer + - depreciated and removed all nonessential functions (basic_analysis, benchmark, strip_data) + - optimized z_normalize using sklearn.preprocessing.normalize + - TODO: implement kernel/function based pytorch regression optimizer + 1.0.9.000: + - refactored + - numpyed everything + - removed stats in favor of numpy functions + 1.0.8.005: + - minor fixes + 1.0.8.004: + - removed a few unused dependencies + 1.0.8.003: + - added p_value function + 1.0.8.002: + - updated __all__ correctly to contain changes made in v 1.0.8.000 and v 1.0.8.001 + 1.0.8.001: + - refactors + - bugfixes + 1.0.8.000: + - depreciated histo_analysis_old + - depreciated debug + - altered basic_analysis to take array data instead of filepath + - refactor + - optimization + 1.0.7.002: + - bug fixes + 1.0.7.001: + - bug fixes + 1.0.7.000: + - added tanh_regression (logistical regression) + - bug fixes + 1.0.6.005: + - added z_normalize function to normalize dataset + - bug fixes + 1.0.6.004: + - bug fixes + 1.0.6.003: + - bug fixes + 1.0.6.002: + - bug fixes + 1.0.6.001: + - corrected __all__ to contain all of the functions + 1.0.6.000: + - added calc_overfit, which calculates two measures of overfit, error and performance + - added calculating overfit to optimize_regression + 1.0.5.000: + - added optimize_regression function, which is a sample function to find the optimal regressions + - optimize_regression function filters out some overfit funtions (functions with r^2 = 1) + - planned addition: overfit detection in the optimize_regression function + 1.0.4.002: + - added __changelog__ + - updated debug function with log and exponential regressions + 1.0.4.001: + - added log regressions + - added exponential regressions + - added log_regression and exp_regression to __all__ + 1.0.3.008: + - added debug function to further consolidate functions + 1.0.3.007: + - added builtin benchmark function + - added builtin random (linear) data generation function + - added device initialization (_init_device) + 1.0.3.006: + - reorganized the imports list to be in alphabetical order + - added search and regurgitate functions to c_entities, nc_entities, obstacles, objectives + 1.0.3.005: + - major bug fixes + - updated historical analysis + - depreciated old historical analysis + 1.0.3.004: + - added __version__, __author__, __all__ + - added polynomial regression + - added root mean squared function + - added r squared function + 1.0.3.003: + - bug fixes + - added c_entities + 1.0.3.002: + - bug fixes + - added nc_entities, obstacles, objectives + - consolidated statistics.py to analysis.py + 1.0.3.001: + - compiled 1d, column, and row basic stats into basic stats function + 1.0.3.000: + - added historical analysis function + 1.0.2.xxx: + - added z score test + 1.0.1.xxx: + - major bug fixes + 1.0.0.xxx: + - added loading csv + - added 1d, column, row basic stats +""" + +__author__ = ( + "Arthur Lu ", + "Jacob Levine ", +) + +__all__ = [ + 'load_csv', + 'basic_stats', + 'z_score', + 'z_normalize', + 'histo_analysis', + 'regression', + 'Metrics', + 'RegressionMetrics', + 'ClassificationMetrics', + 'kmeans', + 'pca', + 'decisiontree', + 'KNN', + 'NaiveBayes', + 'SVM', + 'random_forest_classifier', + 'random_forest_regressor', + 'CorrelationTests', + 'StatisticalTests', + # all statistics functions left out due to integration in other functions +] + +# now back to your regularly scheduled programming: + +# imports (now in alphabetical order! v 1.0.3.006): + +import csv +from analysis.metrics import elo as Elo +from analysis.metrics import glicko2 as Glicko2 +import math +import numba +from numba import jit +import numpy as np +import scipy +from scipy import optimize, stats +import sklearn +from sklearn import preprocessing, pipeline, linear_model, metrics, cluster, decomposition, tree, neighbors, naive_bayes, svm, model_selection, ensemble +from analysis.metrics import trueskill as Trueskill + +class error(ValueError): + pass + +def load_csv(filepath): + with open(filepath, newline='') as csvfile: + file_array = np.array(list(csv.reader(csvfile))) + csvfile.close() + return file_array + +# expects 1d array +@jit(forceobj=True) +def basic_stats(data): + + data_t = np.array(data).astype(float) + + _mean = mean(data_t) + _median = median(data_t) + _stdev = stdev(data_t) + _variance = variance(data_t) + _min = npmin(data_t) + _max = npmax(data_t) + + return _mean, _median, _stdev, _variance, _min, _max + +# returns z score with inputs of point, mean and standard deviation of spread +@jit(forceobj=True) +def z_score(point, mean, stdev): + score = (point - mean) / stdev + + return score + +# expects 2d array, normalizes across all axes +@jit(forceobj=True) +def z_normalize(array, *args): + + array = np.array(array) + for arg in args: + array = sklearn.preprocessing.normalize(array, axis = arg) + + return array + +@jit(forceobj=True) +# expects 2d array of [x,y] +def histo_analysis(hist_data): + + if(len(hist_data[0]) > 2): + + hist_data = np.array(hist_data) + derivative = np.array(len(hist_data) - 1, dtype = float) + t = np.diff(hist_data) + derivative = t[1] / t[0] + np.sort(derivative) + + return basic_stats(derivative)[0], basic_stats(derivative)[3] + + else: + + return None + +def regression(inputs, outputs, args): # inputs, outputs expects N-D array + + X = np.array(inputs) + y = np.array(outputs) + + regressions = [] + + if 'lin' in args: # formula: ax + b + + try: + + def func(x, a, b): + + return a * x + b + + popt, pcov = scipy.optimize.curve_fit(func, X, y) + + regressions.append((popt.flatten().tolist(), None)) + + except Exception as e: + + pass + + if 'log' in args: # formula: a log (b(x + c)) + d + + try: + + def func(x, a, b, c, d): + + return a * np.log(b*(x + c)) + d + + popt, pcov = scipy.optimize.curve_fit(func, X, y) + + regressions.append((popt.flatten().tolist(), None)) + + except Exception as e: + + pass + + if 'exp' in args: # formula: a e ^ (b(x + c)) + d + + try: + + def func(x, a, b, c, d): + + return a * np.exp(b*(x + c)) + d + + popt, pcov = scipy.optimize.curve_fit(func, X, y) + + regressions.append((popt.flatten().tolist(), None)) + + except Exception as e: + + pass + + if 'ply' in args: # formula: a + bx^1 + cx^2 + dx^3 + ... + + inputs = np.array([inputs]) + outputs = np.array([outputs]) + + plys = [] + limit = len(outputs[0]) + + for i in range(2, limit): + + model = sklearn.preprocessing.PolynomialFeatures(degree = i) + model = sklearn.pipeline.make_pipeline(model, sklearn.linear_model.LinearRegression()) + model = model.fit(np.rot90(inputs), np.rot90(outputs)) + + params = model.steps[1][1].intercept_.tolist() + params = np.append(params, model.steps[1][1].coef_[0].tolist()[1::]) + params.flatten() + params = params.tolist() + + plys.append(params) + + regressions.append(plys) + + if 'sig' in args: # formula: a tanh (b(x + c)) + d + + try: + + def func(x, a, b, c, d): + + return a * np.tanh(b*(x + c)) + d + + popt, pcov = scipy.optimize.curve_fit(func, X, y) + + regressions.append((popt.flatten().tolist(), None)) + + except Exception as e: + + pass + + return regressions + +class Metrics: + + def elo(self, starting_score, opposing_score, observed, N, K): + + return Elo.calculate(starting_score, opposing_score, observed, N, K) + + def glicko2(self, starting_score, starting_rd, starting_vol, opposing_score, opposing_rd, observations): + + player = Glicko2.Glicko2(rating = starting_score, rd = starting_rd, vol = starting_vol) + + player.update_player([x for x in opposing_score], [x for x in opposing_rd], observations) + + return (player.rating, player.rd, player.vol) + + def trueskill(self, teams_data, observations): # teams_data is array of array of tuples ie. [[(mu, sigma), (mu, sigma), (mu, sigma)], [(mu, sigma), (mu, sigma), (mu, sigma)]] + + team_ratings = [] + + for team in teams_data: + team_temp = () + for player in team: + player = Trueskill.Rating(player[0], player[1]) + team_temp = team_temp + (player,) + team_ratings.append(team_temp) + + return Trueskill.rate(team_ratings, ranks=observations) + +class RegressionMetrics(): + + def __new__(cls, predictions, targets): + + return cls.r_squared(cls, predictions, targets), cls.mse(cls, predictions, targets), cls.rms(cls, predictions, targets) + + def r_squared(self, predictions, targets): # assumes equal size inputs + + return sklearn.metrics.r2_score(targets, predictions) + + def mse(self, predictions, targets): + + return sklearn.metrics.mean_squared_error(targets, predictions) + + def rms(self, predictions, targets): + + return math.sqrt(sklearn.metrics.mean_squared_error(targets, predictions)) + +class ClassificationMetrics(): + + def __new__(cls, predictions, targets): + + return cls.cm(cls, predictions, targets), cls.cr(cls, predictions, targets) + + def cm(self, predictions, targets): + + return sklearn.metrics.confusion_matrix(targets, predictions) + + def cr(self, predictions, targets): + + return sklearn.metrics.classification_report(targets, predictions) + +@jit(nopython=True) +def mean(data): + + return np.mean(data) + +@jit(nopython=True) +def median(data): + + return np.median(data) + +@jit(nopython=True) +def stdev(data): + + return np.std(data) + +@jit(nopython=True) +def variance(data): + + return np.var(data) + +@jit(nopython=True) +def npmin(data): + + return np.amin(data) + +@jit(nopython=True) +def npmax(data): + + return np.amax(data) + +@jit(forceobj=True) +def kmeans(data, n_clusters=8, init="k-means++", n_init=10, max_iter=300, tol=0.0001, precompute_distances="auto", verbose=0, random_state=None, copy_x=True, n_jobs=None, algorithm="auto"): + + kernel = sklearn.cluster.KMeans(n_clusters = n_clusters, init = init, n_init = n_init, max_iter = max_iter, tol = tol, precompute_distances = precompute_distances, verbose = verbose, random_state = random_state, copy_x = copy_x, n_jobs = n_jobs, algorithm = algorithm) + kernel.fit(data) + predictions = kernel.predict(data) + centers = kernel.cluster_centers_ + + return centers, predictions + +@jit(forceobj=True) +def pca(data, n_components = None, copy = True, whiten = False, svd_solver = "auto", tol = 0.0, iterated_power = "auto", random_state = None): + + kernel = sklearn.decomposition.PCA(n_components = n_components, copy = copy, whiten = whiten, svd_solver = svd_solver, tol = tol, iterated_power = iterated_power, random_state = random_state) + + return kernel.fit_transform(data) + +@jit(forceobj=True) +def decisiontree(data, labels, test_size = 0.3, criterion = "gini", splitter = "default", max_depth = None): #expects *2d data and 1d labels + + data_train, data_test, labels_train, labels_test = sklearn.model_selection.train_test_split(data, labels, test_size=test_size, random_state=1) + model = sklearn.tree.DecisionTreeClassifier(criterion = criterion, splitter = splitter, max_depth = max_depth) + model = model.fit(data_train,labels_train) + predictions = model.predict(data_test) + metrics = ClassificationMetrics(predictions, labels_test) + + return model, metrics + +class KNN: + + def knn_classifier(self, data, labels, test_size = 0.3, algorithm='auto', leaf_size=30, metric='minkowski', metric_params=None, n_jobs=None, n_neighbors=5, p=2, weights='uniform'): #expects *2d data and 1d labels post-scaling + + data_train, data_test, labels_train, labels_test = sklearn.model_selection.train_test_split(data, labels, test_size=test_size, random_state=1) + model = sklearn.neighbors.KNeighborsClassifier() + model.fit(data_train, labels_train) + predictions = model.predict(data_test) + + return model, ClassificationMetrics(predictions, labels_test) + + def knn_regressor(self, data, outputs, test_size, n_neighbors = 5, weights = "uniform", algorithm = "auto", leaf_size = 30, p = 2, metric = "minkowski", metric_params = None, n_jobs = None): + + data_train, data_test, outputs_train, outputs_test = sklearn.model_selection.train_test_split(data, outputs, test_size=test_size, random_state=1) + model = sklearn.neighbors.KNeighborsRegressor(n_neighbors = n_neighbors, weights = weights, algorithm = algorithm, leaf_size = leaf_size, p = p, metric = metric, metric_params = metric_params, n_jobs = n_jobs) + model.fit(data_train, outputs_train) + predictions = model.predict(data_test) + + return model, RegressionMetrics(predictions, outputs_test) + +class NaiveBayes: + + def guassian(self, data, labels, test_size = 0.3, priors = None, var_smoothing = 1e-09): + + data_train, data_test, labels_train, labels_test = sklearn.model_selection.train_test_split(data, labels, test_size=test_size, random_state=1) + model = sklearn.naive_bayes.GaussianNB(priors = priors, var_smoothing = var_smoothing) + model.fit(data_train, labels_train) + predictions = model.predict(data_test) + + return model, ClassificationMetrics(predictions, labels_test) + + def multinomial(self, data, labels, test_size = 0.3, alpha=1.0, fit_prior=True, class_prior=None): + + data_train, data_test, labels_train, labels_test = sklearn.model_selection.train_test_split(data, labels, test_size=test_size, random_state=1) + model = sklearn.naive_bayes.MultinomialNB(alpha = alpha, fit_prior = fit_prior, class_prior = class_prior) + model.fit(data_train, labels_train) + predictions = model.predict(data_test) + + return model, ClassificationMetrics(predictions, labels_test) + + def bernoulli(self, data, labels, test_size = 0.3, alpha=1.0, binarize=0.0, fit_prior=True, class_prior=None): + + data_train, data_test, labels_train, labels_test = sklearn.model_selection.train_test_split(data, labels, test_size=test_size, random_state=1) + model = sklearn.naive_bayes.BernoulliNB(alpha = alpha, binarize = binarize, fit_prior = fit_prior, class_prior = class_prior) + model.fit(data_train, labels_train) + predictions = model.predict(data_test) + + return model, ClassificationMetrics(predictions, labels_test) + + def complement(self, data, labels, test_size = 0.3, alpha=1.0, fit_prior=True, class_prior=None, norm=False): + + data_train, data_test, labels_train, labels_test = sklearn.model_selection.train_test_split(data, labels, test_size=test_size, random_state=1) + model = sklearn.naive_bayes.ComplementNB(alpha = alpha, fit_prior = fit_prior, class_prior = class_prior, norm = norm) + model.fit(data_train, labels_train) + predictions = model.predict(data_test) + + return model, ClassificationMetrics(predictions, labels_test) + +class SVM: + + class CustomKernel: + + def __new__(cls, C, kernel, degre, gamma, coef0, shrinking, probability, tol, cache_size, class_weight, verbose, max_iter, decision_function_shape, random_state): + + return sklearn.svm.SVC(C = C, kernel = kernel, gamma = gamma, coef0 = coef0, shrinking = shrinking, probability = probability, tol = tol, cache_size = cache_size, class_weight = class_weight, verbose = verbose, max_iter = max_iter, decision_function_shape = decision_function_shape, random_state = random_state) + + class StandardKernel: + + def __new__(cls, kernel, C=1.0, degree=3, gamma='auto_deprecated', coef0=0.0, shrinking=True, probability=False, tol=0.001, cache_size=200, class_weight=None, verbose=False, max_iter=-1, decision_function_shape='ovr', random_state=None): + + return sklearn.svm.SVC(C = C, kernel = kernel, gamma = gamma, coef0 = coef0, shrinking = shrinking, probability = probability, tol = tol, cache_size = cache_size, class_weight = class_weight, verbose = verbose, max_iter = max_iter, decision_function_shape = decision_function_shape, random_state = random_state) + + class PrebuiltKernel: + + class Linear: + + def __new__(cls): + + return sklearn.svm.SVC(kernel = 'linear') + + class Polynomial: + + def __new__(cls, power, r_bias): + + return sklearn.svm.SVC(kernel = 'polynomial', degree = power, coef0 = r_bias) + + class RBF: + + def __new__(cls, gamma): + + return sklearn.svm.SVC(kernel = 'rbf', gamma = gamma) + + class Sigmoid: + + def __new__(cls, r_bias): + + return sklearn.svm.SVC(kernel = 'sigmoid', coef0 = r_bias) + + def fit(self, kernel, train_data, train_outputs): # expects *2d data, 1d labels or outputs + + return kernel.fit(train_data, train_outputs) + + def eval_classification(self, kernel, test_data, test_outputs): + + predictions = kernel.predict(test_data) + + return ClassificationMetrics(predictions, test_outputs) + + def eval_regression(self, kernel, test_data, test_outputs): + + predictions = kernel.predict(test_data) + + return RegressionMetrics(predictions, test_outputs) + +def random_forest_classifier(data, labels, test_size, n_estimators="warn", criterion="gini", max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features="auto", max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, bootstrap=True, oob_score=False, n_jobs=None, random_state=None, verbose=0, warm_start=False, class_weight=None): + + data_train, data_test, labels_train, labels_test = sklearn.model_selection.train_test_split(data, labels, test_size=test_size, random_state=1) + kernel = sklearn.ensemble.RandomForestClassifier(n_estimators = n_estimators, criterion = criterion, max_depth = max_depth, min_samples_split = min_samples_split, min_samples_leaf = min_samples_leaf, min_weight_fraction_leaf = min_weight_fraction_leaf, max_leaf_nodes = max_leaf_nodes, min_impurity_decrease = min_impurity_decrease, bootstrap = bootstrap, oob_score = oob_score, n_jobs = n_jobs, random_state = random_state, verbose = verbose, warm_start = warm_start, class_weight = class_weight) + kernel.fit(data_train, labels_train) + predictions = kernel.predict(data_test) + + return kernel, ClassificationMetrics(predictions, labels_test) + +def random_forest_regressor(data, outputs, test_size, n_estimators="warn", criterion="mse", max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features="auto", max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, bootstrap=True, oob_score=False, n_jobs=None, random_state=None, verbose=0, warm_start=False): + + data_train, data_test, outputs_train, outputs_test = sklearn.model_selection.train_test_split(data, outputs, test_size=test_size, random_state=1) + kernel = sklearn.ensemble.RandomForestRegressor(n_estimators = n_estimators, criterion = criterion, max_depth = max_depth, min_samples_split = min_samples_split, min_weight_fraction_leaf = min_weight_fraction_leaf, max_features = max_features, max_leaf_nodes = max_leaf_nodes, min_impurity_decrease = min_impurity_decrease, min_impurity_split = min_impurity_split, bootstrap = bootstrap, oob_score = oob_score, n_jobs = n_jobs, random_state = random_state, verbose = verbose, warm_start = warm_start) + kernel.fit(data_train, outputs_train) + predictions = kernel.predict(data_test) + + return kernel, RegressionMetrics(predictions, outputs_test) + +class CorrelationTests: + + def anova_oneway(self, *args): #expects arrays of samples + + results = scipy.stats.f_oneway(*args) + return {"F-value": results[0], "p-value": results[1]} + + def pearson(self, x, y): + + results = scipy.stats.pearsonr(x, y) + return {"r-value": results[0], "p-value": results[1]} + + def spearman(self, a, b = None, axis = 0, nan_policy = 'propagate'): + + results = scipy.stats.spearmanr(a, b = b, axis = axis, nan_policy = nan_policy) + return {"r-value": results[0], "p-value": results[1]} + + def point_biserial(self, x,y): + + results = scipy.stats.pointbiserialr(x, y) + return {"r-value": results[0], "p-value": results[1]} + + def kendall(self, x, y, initial_lexsort = None, nan_policy = 'propagate', method = 'auto'): + + results = scipy.stats.kendalltau(x, y, initial_lexsort = initial_lexsort, nan_policy = nan_policy, method = method) + return {"tau": results[0], "p-value": results[1]} + + def kendall_weighted(self, x, y, rank = True, weigher = None, additive = True): + + results = scipy.stats.weightedtau(x, y, rank = rank, weigher = weigher, additive = additive) + return {"tau": results[0], "p-value": results[1]} + + def mgc(self, x, y, compute_distance = None, reps = 1000, workers = 1, is_twosamp = False, random_state = None): + + results = scipy.stats.multiscale_graphcorr(x, y, compute_distance = compute_distance, reps = reps, workers = workers, is_twosamp = is_twosamp, random_state = random_state) + return {"k-value": results[0], "p-value": results[1], "data": results[2]} # unsure if MGC test returns a k value + +class StatisticalTests: + + def ttest_onesample(self, a, popmean, axis = 0, nan_policy = 'propagate'): + + results = scipy.stats.ttest_1samp(a, popmean, axis = axis, nan_policy = nan_policy) + return {"t-value": results[0], "p-value": results[1]} + + def ttest_independent(self, a, b, equal = True, nan_policy = 'propagate'): + + results = scipy.stats.ttest_ind(a, b, equal_var = equal, nan_policy = nan_policy) + return {"t-value": results[0], "p-value": results[1]} + + def ttest_statistic(self, o1, o2, equal = True): + + results = scipy.stats.ttest_ind_from_stats(o1["mean"], o1["std"], o1["nobs"], o2["mean"], o2["std"], o2["nobs"], equal_var = equal) + return {"t-value": results[0], "p-value": results[1]} + + def ttest_related(self, a, b, axis = 0, nan_policy='propagate'): + + results = scipy.stats.ttest_rel(a, b, axis = axis, nan_policy = nan_policy) + return {"t-value": results[0], "p-value": results[1]} + + def ks_fitness(self, rvs, cdf, args = (), N = 20, alternative = 'two-sided', mode = 'approx'): + + results = scipy.stats.kstest(rvs, cdf, args = args, N = N, alternative = alternative, mode = mode) + return {"ks-value": results[0], "p-value": results[1]} + + def chisquare(self, f_obs, f_exp = None, ddof = None, axis = 0): + + results = scipy.stats.chisquare(f_obs, f_exp = f_exp, ddof = ddof, axis = axis) + return {"chisquared-value": results[0], "p-value": results[1]} + + def powerdivergence(self, f_obs, f_exp = None, ddof = None, axis = 0, lambda_ = None): + + results = scipy.stats.power_divergence(f_obs, f_exp = f_exp, ddof = ddof, axis = axis, lambda_ = lambda_) + return {"powerdivergence-value": results[0], "p-value": results[1]} + + def ks_twosample(self, x, y, alternative = 'two_sided', mode = 'auto'): + + results = scipy.stats.ks_2samp(x, y, alternative = alternative, mode = mode) + return {"ks-value": results[0], "p-value": results[1]} + + def es_twosample(self, x, y, t = (0.4, 0.8)): + + results = scipy.stats.epps_singleton_2samp(x, y, t = t) + return {"es-value": results[0], "p-value": results[1]} + + def mw_rank(self, x, y, use_continuity = True, alternative = None): + + results = scipy.stats.mannwhitneyu(x, y, use_continuity = use_continuity, alternative = alternative) + return {"u-value": results[0], "p-value": results[1]} + + def mw_tiecorrection(self, rank_values): + + results = scipy.stats.tiecorrect(rank_values) + return {"correction-factor": results} + + def rankdata(self, a, method = 'average'): + + results = scipy.stats.rankdata(a, method = method) + return results + + def wilcoxon_ranksum(self, a, b): # this seems to be superceded by Mann Whitney Wilcoxon U Test + + results = scipy.stats.ranksums(a, b) + return {"u-value": results[0], "p-value": results[1]} + + def wilcoxon_signedrank(self, x, y = None, zero_method = 'wilcox', correction = False, alternative = 'two-sided'): + + results = scipy.stats.wilcoxon(x, y = y, zero_method = zero_method, correction = correction, alternative = alternative) + return {"t-value": results[0], "p-value": results[1]} + + def kw_htest(self, *args, nan_policy = 'propagate'): + + results = scipy.stats.kruskal(*args, nan_policy = nan_policy) + return {"h-value": results[0], "p-value": results[1]} + + def friedman_chisquare(self, *args): + + results = scipy.stats.friedmanchisquare(*args) + return {"chisquared-value": results[0], "p-value": results[1]} + + def bm_wtest(self, x, y, alternative = 'two-sided', distribution = 't', nan_policy = 'propagate'): + + results = scipy.stats.brunnermunzel(x, y, alternative = alternative, distribution = distribution, nan_policy = nan_policy) + return {"w-value": results[0], "p-value": results[1]} + + def combine_pvalues(self, pvalues, method = 'fisher', weights = None): + + results = scipy.stats.combine_pvalues(pvalues, method = method, weights = weights) + return {"combined-statistic": results[0], "p-value": results[1]} + + def jb_fitness(self, x): + + results = scipy.stats.jarque_bera(x) + return {"jb-value": results[0], "p-value": results[1]} + + def ab_equality(self, x, y): + + results = scipy.stats.ansari(x, y) + return {"ab-value": results[0], "p-value": results[1]} + + def bartlett_variance(self, *args): + + results = scipy.stats.bartlett(*args) + return {"t-value": results[0], "p-value": results[1]} + + def levene_variance(self, *args, center = 'median', proportiontocut = 0.05): + + results = scipy.stats.levene(*args, center = center, proportiontocut = proportiontocut) + return {"w-value": results[0], "p-value": results[1]} + + def sw_normality(self, x): + + results = scipy.stats.shapiro(x) + return {"w-value": results[0], "p-value": results[1]} + + def shapiro(self, x): + + return "destroyed by facts and logic" + + def ad_onesample(self, x, dist = 'norm'): + + results = scipy.stats.anderson(x, dist = dist) + return {"d-value": results[0], "critical-values": results[1], "significance-value": results[2]} + + def ad_ksample(self, samples, midrank = True): + + results = scipy.stats.anderson_ksamp(samples, midrank = midrank) + return {"d-value": results[0], "critical-values": results[1], "significance-value": results[2]} + + def binomial(self, x, n = None, p = 0.5, alternative = 'two-sided'): + + results = scipy.stats.binom_test(x, n = n, p = p, alternative = alternative) + return {"p-value": results} + + def fk_variance(self, *args, center = 'median', proportiontocut = 0.05): + + results = scipy.stats.fligner(*args, center = center, proportiontocut = proportiontocut) + return {"h-value": results[0], "p-value": results[1]} # unknown if the statistic is an h value + + def mood_mediantest(self, *args, ties = 'below', correction = True, lambda_ = 1, nan_policy = 'propagate'): + + results = scipy.stats.median_test(*args, ties = ties, correction = correction, lambda_ = lambda_, nan_policy = nan_policy) + return {"chisquared-value": results[0], "p-value": results[1], "m-value": results[2], "table": results[3]} + + def mood_equalscale(self, x, y, axis = 0): + + results = scipy.stats.mood(x, y, axis = axis) + return {"z-score": results[0], "p-value": results[1]} + + def skewtest(self, a, axis = 0, nan_policy = 'propogate'): + + results = scipy.stats.skewtest(a, axis = axis, nan_policy = nan_policy) + return {"z-score": results[0], "p-value": results[1]} + + def kurtosistest(self, a, axis = 0, nan_policy = 'propogate'): + + results = scipy.stats.kurtosistest(a, axis = axis, nan_policy = nan_policy) + return {"z-score": results[0], "p-value": results[1]} + + def normaltest(self, a, axis = 0, nan_policy = 'propogate'): + + results = scipy.stats.normaltest(a, axis = axis, nan_policy = nan_policy) + return {"z-score": results[0], "p-value": results[1]} \ No newline at end of file diff --git a/analysis-master/build/lib/analysis/glicko2.py b/analysis-master/build/lib/analysis/glicko2.py new file mode 100644 index 00000000..66c0df94 --- /dev/null +++ b/analysis-master/build/lib/analysis/glicko2.py @@ -0,0 +1,99 @@ +import math + +class Glicko2: + _tau = 0.5 + + def getRating(self): + return (self.__rating * 173.7178) + 1500 + + def setRating(self, rating): + self.__rating = (rating - 1500) / 173.7178 + + rating = property(getRating, setRating) + + def getRd(self): + return self.__rd * 173.7178 + + def setRd(self, rd): + self.__rd = rd / 173.7178 + + rd = property(getRd, setRd) + + def __init__(self, rating = 1500, rd = 350, vol = 0.06): + + self.setRating(rating) + self.setRd(rd) + self.vol = vol + + def _preRatingRD(self): + + self.__rd = math.sqrt(math.pow(self.__rd, 2) + math.pow(self.vol, 2)) + + def update_player(self, rating_list, RD_list, outcome_list): + + rating_list = [(x - 1500) / 173.7178 for x in rating_list] + RD_list = [x / 173.7178 for x in RD_list] + + v = self._v(rating_list, RD_list) + self.vol = self._newVol(rating_list, RD_list, outcome_list, v) + self._preRatingRD() + + self.__rd = 1 / math.sqrt((1 / math.pow(self.__rd, 2)) + (1 / v)) + + tempSum = 0 + for i in range(len(rating_list)): + tempSum += self._g(RD_list[i]) * \ + (outcome_list[i] - self._E(rating_list[i], RD_list[i])) + self.__rating += math.pow(self.__rd, 2) * tempSum + + + def _newVol(self, rating_list, RD_list, outcome_list, v): + + i = 0 + delta = self._delta(rating_list, RD_list, outcome_list, v) + a = math.log(math.pow(self.vol, 2)) + tau = self._tau + x0 = a + x1 = 0 + + while x0 != x1: + # New iteration, so x(i) becomes x(i-1) + x0 = x1 + d = math.pow(self.__rating, 2) + v + math.exp(x0) + h1 = -(x0 - a) / math.pow(tau, 2) - 0.5 * math.exp(x0) \ + / d + 0.5 * math.exp(x0) * math.pow(delta / d, 2) + h2 = -1 / math.pow(tau, 2) - 0.5 * math.exp(x0) * \ + (math.pow(self.__rating, 2) + v) \ + / math.pow(d, 2) + 0.5 * math.pow(delta, 2) * math.exp(x0) \ + * (math.pow(self.__rating, 2) + v - math.exp(x0)) / math.pow(d, 3) + x1 = x0 - (h1 / h2) + + return math.exp(x1 / 2) + + def _delta(self, rating_list, RD_list, outcome_list, v): + + tempSum = 0 + for i in range(len(rating_list)): + tempSum += self._g(RD_list[i]) * (outcome_list[i] - self._E(rating_list[i], RD_list[i])) + return v * tempSum + + def _v(self, rating_list, RD_list): + + tempSum = 0 + for i in range(len(rating_list)): + tempE = self._E(rating_list[i], RD_list[i]) + tempSum += math.pow(self._g(RD_list[i]), 2) * tempE * (1 - tempE) + return 1 / tempSum + + def _E(self, p2rating, p2RD): + + return 1 / (1 + math.exp(-1 * self._g(p2RD) * \ + (self.__rating - p2rating))) + + def _g(self, RD): + + return 1 / math.sqrt(1 + 3 * math.pow(RD, 2) / math.pow(math.pi, 2)) + + def did_not_compete(self): + + self._preRatingRD() \ No newline at end of file diff --git a/analysis-master/build/lib/analysis/metrics/__init__.py b/analysis-master/build/lib/analysis/metrics/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/analysis-master/build/lib/analysis/metrics/elo.py b/analysis-master/build/lib/analysis/metrics/elo.py new file mode 100644 index 00000000..3c8ef2e0 --- /dev/null +++ b/analysis-master/build/lib/analysis/metrics/elo.py @@ -0,0 +1,7 @@ +import numpy as np + +def calculate(starting_score, opposing_score, observed, N, K): + + expected = 1/(1+10**((np.array(opposing_score) - starting_score)/N)) + + return starting_score + K*(np.sum(observed) - np.sum(expected)) \ No newline at end of file diff --git a/analysis-master/build/lib/analysis/metrics/glicko2.py b/analysis-master/build/lib/analysis/metrics/glicko2.py new file mode 100644 index 00000000..66c0df94 --- /dev/null +++ b/analysis-master/build/lib/analysis/metrics/glicko2.py @@ -0,0 +1,99 @@ +import math + +class Glicko2: + _tau = 0.5 + + def getRating(self): + return (self.__rating * 173.7178) + 1500 + + def setRating(self, rating): + self.__rating = (rating - 1500) / 173.7178 + + rating = property(getRating, setRating) + + def getRd(self): + return self.__rd * 173.7178 + + def setRd(self, rd): + self.__rd = rd / 173.7178 + + rd = property(getRd, setRd) + + def __init__(self, rating = 1500, rd = 350, vol = 0.06): + + self.setRating(rating) + self.setRd(rd) + self.vol = vol + + def _preRatingRD(self): + + self.__rd = math.sqrt(math.pow(self.__rd, 2) + math.pow(self.vol, 2)) + + def update_player(self, rating_list, RD_list, outcome_list): + + rating_list = [(x - 1500) / 173.7178 for x in rating_list] + RD_list = [x / 173.7178 for x in RD_list] + + v = self._v(rating_list, RD_list) + self.vol = self._newVol(rating_list, RD_list, outcome_list, v) + self._preRatingRD() + + self.__rd = 1 / math.sqrt((1 / math.pow(self.__rd, 2)) + (1 / v)) + + tempSum = 0 + for i in range(len(rating_list)): + tempSum += self._g(RD_list[i]) * \ + (outcome_list[i] - self._E(rating_list[i], RD_list[i])) + self.__rating += math.pow(self.__rd, 2) * tempSum + + + def _newVol(self, rating_list, RD_list, outcome_list, v): + + i = 0 + delta = self._delta(rating_list, RD_list, outcome_list, v) + a = math.log(math.pow(self.vol, 2)) + tau = self._tau + x0 = a + x1 = 0 + + while x0 != x1: + # New iteration, so x(i) becomes x(i-1) + x0 = x1 + d = math.pow(self.__rating, 2) + v + math.exp(x0) + h1 = -(x0 - a) / math.pow(tau, 2) - 0.5 * math.exp(x0) \ + / d + 0.5 * math.exp(x0) * math.pow(delta / d, 2) + h2 = -1 / math.pow(tau, 2) - 0.5 * math.exp(x0) * \ + (math.pow(self.__rating, 2) + v) \ + / math.pow(d, 2) + 0.5 * math.pow(delta, 2) * math.exp(x0) \ + * (math.pow(self.__rating, 2) + v - math.exp(x0)) / math.pow(d, 3) + x1 = x0 - (h1 / h2) + + return math.exp(x1 / 2) + + def _delta(self, rating_list, RD_list, outcome_list, v): + + tempSum = 0 + for i in range(len(rating_list)): + tempSum += self._g(RD_list[i]) * (outcome_list[i] - self._E(rating_list[i], RD_list[i])) + return v * tempSum + + def _v(self, rating_list, RD_list): + + tempSum = 0 + for i in range(len(rating_list)): + tempE = self._E(rating_list[i], RD_list[i]) + tempSum += math.pow(self._g(RD_list[i]), 2) * tempE * (1 - tempE) + return 1 / tempSum + + def _E(self, p2rating, p2RD): + + return 1 / (1 + math.exp(-1 * self._g(p2RD) * \ + (self.__rating - p2rating))) + + def _g(self, RD): + + return 1 / math.sqrt(1 + 3 * math.pow(RD, 2) / math.pow(math.pi, 2)) + + def did_not_compete(self): + + self._preRatingRD() \ No newline at end of file diff --git a/analysis-master/build/lib/analysis/metrics/trueskill.py b/analysis-master/build/lib/analysis/metrics/trueskill.py new file mode 100644 index 00000000..116357df --- /dev/null +++ b/analysis-master/build/lib/analysis/metrics/trueskill.py @@ -0,0 +1,907 @@ +from __future__ import absolute_import + +from itertools import chain +import math + +from six import iteritems +from six.moves import map, range, zip +from six import iterkeys + +import copy +try: + from numbers import Number +except ImportError: + Number = (int, long, float, complex) + +inf = float('inf') + +class Gaussian(object): + #: Precision, the inverse of the variance. + pi = 0 + #: Precision adjusted mean, the precision multiplied by the mean. + tau = 0 + + def __init__(self, mu=None, sigma=None, pi=0, tau=0): + if mu is not None: + if sigma is None: + raise TypeError('sigma argument is needed') + elif sigma == 0: + raise ValueError('sigma**2 should be greater than 0') + pi = sigma ** -2 + tau = pi * mu + self.pi = pi + self.tau = tau + + @property + def mu(self): + return self.pi and self.tau / self.pi + + @property + def sigma(self): + return math.sqrt(1 / self.pi) if self.pi else inf + + def __mul__(self, other): + pi, tau = self.pi + other.pi, self.tau + other.tau + return Gaussian(pi=pi, tau=tau) + + def __truediv__(self, other): + pi, tau = self.pi - other.pi, self.tau - other.tau + return Gaussian(pi=pi, tau=tau) + + __div__ = __truediv__ # for Python 2 + + def __eq__(self, other): + return self.pi == other.pi and self.tau == other.tau + + def __lt__(self, other): + return self.mu < other.mu + + def __le__(self, other): + return self.mu <= other.mu + + def __gt__(self, other): + return self.mu > other.mu + + def __ge__(self, other): + return self.mu >= other.mu + + def __repr__(self): + return 'N(mu={:.3f}, sigma={:.3f})'.format(self.mu, self.sigma) + + def _repr_latex_(self): + latex = r'\mathcal{{ N }}( {:.3f}, {:.3f}^2 )'.format(self.mu, self.sigma) + return '$%s$' % latex + +class Matrix(list): + def __init__(self, src, height=None, width=None): + if callable(src): + f, src = src, {} + size = [height, width] + if not height: + def set_height(height): + size[0] = height + size[0] = set_height + if not width: + def set_width(width): + size[1] = width + size[1] = set_width + try: + for (r, c), val in f(*size): + src[r, c] = val + except TypeError: + raise TypeError('A callable src must return an interable ' + 'which generates a tuple containing ' + 'coordinate and value') + height, width = tuple(size) + if height is None or width is None: + raise TypeError('A callable src must call set_height and ' + 'set_width if the size is non-deterministic') + if isinstance(src, list): + is_number = lambda x: isinstance(x, Number) + unique_col_sizes = set(map(len, src)) + everything_are_number = filter(is_number, sum(src, [])) + if len(unique_col_sizes) != 1 or not everything_are_number: + raise ValueError('src must be a rectangular array of numbers') + two_dimensional_array = src + elif isinstance(src, dict): + if not height or not width: + w = h = 0 + for r, c in iterkeys(src): + if not height: + h = max(h, r + 1) + if not width: + w = max(w, c + 1) + if not height: + height = h + if not width: + width = w + two_dimensional_array = [] + for r in range(height): + row = [] + two_dimensional_array.append(row) + for c in range(width): + row.append(src.get((r, c), 0)) + else: + raise TypeError('src must be a list or dict or callable') + super(Matrix, self).__init__(two_dimensional_array) + + @property + def height(self): + return len(self) + + @property + def width(self): + return len(self[0]) + + def transpose(self): + height, width = self.height, self.width + src = {} + for c in range(width): + for r in range(height): + src[c, r] = self[r][c] + return type(self)(src, height=width, width=height) + + def minor(self, row_n, col_n): + height, width = self.height, self.width + if not (0 <= row_n < height): + raise ValueError('row_n should be between 0 and %d' % height) + elif not (0 <= col_n < width): + raise ValueError('col_n should be between 0 and %d' % width) + two_dimensional_array = [] + for r in range(height): + if r == row_n: + continue + row = [] + two_dimensional_array.append(row) + for c in range(width): + if c == col_n: + continue + row.append(self[r][c]) + return type(self)(two_dimensional_array) + + def determinant(self): + height, width = self.height, self.width + if height != width: + raise ValueError('Only square matrix can calculate a determinant') + tmp, rv = copy.deepcopy(self), 1. + for c in range(width - 1, 0, -1): + pivot, r = max((abs(tmp[r][c]), r) for r in range(c + 1)) + pivot = tmp[r][c] + if not pivot: + return 0. + tmp[r], tmp[c] = tmp[c], tmp[r] + if r != c: + rv = -rv + rv *= pivot + fact = -1. / pivot + for r in range(c): + f = fact * tmp[r][c] + for x in range(c): + tmp[r][x] += f * tmp[c][x] + return rv * tmp[0][0] + + def adjugate(self): + height, width = self.height, self.width + if height != width: + raise ValueError('Only square matrix can be adjugated') + if height == 2: + a, b = self[0][0], self[0][1] + c, d = self[1][0], self[1][1] + return type(self)([[d, -b], [-c, a]]) + src = {} + for r in range(height): + for c in range(width): + sign = -1 if (r + c) % 2 else 1 + src[r, c] = self.minor(r, c).determinant() * sign + return type(self)(src, height, width) + + def inverse(self): + if self.height == self.width == 1: + return type(self)([[1. / self[0][0]]]) + return (1. / self.determinant()) * self.adjugate() + + def __add__(self, other): + height, width = self.height, self.width + if (height, width) != (other.height, other.width): + raise ValueError('Must be same size') + src = {} + for r in range(height): + for c in range(width): + src[r, c] = self[r][c] + other[r][c] + return type(self)(src, height, width) + + def __mul__(self, other): + if self.width != other.height: + raise ValueError('Bad size') + height, width = self.height, other.width + src = {} + for r in range(height): + for c in range(width): + src[r, c] = sum(self[r][x] * other[x][c] + for x in range(self.width)) + return type(self)(src, height, width) + + def __rmul__(self, other): + if not isinstance(other, Number): + raise TypeError('The operand should be a number') + height, width = self.height, self.width + src = {} + for r in range(height): + for c in range(width): + src[r, c] = other * self[r][c] + return type(self)(src, height, width) + + def __repr__(self): + return '{}({})'.format(type(self).__name__, super(Matrix, self).__repr__()) + + def _repr_latex_(self): + rows = [' && '.join(['%.3f' % cell for cell in row]) for row in self] + latex = r'\begin{matrix} %s \end{matrix}' % r'\\'.join(rows) + return '$%s$' % latex + +def _gen_erfcinv(erfc, math=math): + def erfcinv(y): + """The inverse function of erfc.""" + if y >= 2: + return -100. + elif y <= 0: + return 100. + zero_point = y < 1 + if not zero_point: + y = 2 - y + t = math.sqrt(-2 * math.log(y / 2.)) + x = -0.70711 * \ + ((2.30753 + t * 0.27061) / (1. + t * (0.99229 + t * 0.04481)) - t) + for i in range(2): + err = erfc(x) - y + x += err / (1.12837916709551257 * math.exp(-(x ** 2)) - x * err) + return x if zero_point else -x + return erfcinv + +def _gen_ppf(erfc, math=math): + erfcinv = _gen_erfcinv(erfc, math) + def ppf(x, mu=0, sigma=1): + return mu - sigma * math.sqrt(2) * erfcinv(2 * x) + return ppf + +def erfc(x): + z = abs(x) + t = 1. / (1. + z / 2.) + r = t * math.exp(-z * z - 1.26551223 + t * (1.00002368 + t * ( + 0.37409196 + t * (0.09678418 + t * (-0.18628806 + t * ( + 0.27886807 + t * (-1.13520398 + t * (1.48851587 + t * ( + -0.82215223 + t * 0.17087277 + ))) + ))) + ))) + return 2. - r if x < 0 else r + +def cdf(x, mu=0, sigma=1): + return 0.5 * erfc(-(x - mu) / (sigma * math.sqrt(2))) + + +def pdf(x, mu=0, sigma=1): + return (1 / math.sqrt(2 * math.pi) * abs(sigma) * + math.exp(-(((x - mu) / abs(sigma)) ** 2 / 2))) + +ppf = _gen_ppf(erfc) + +def choose_backend(backend): + if backend is None: # fallback + return cdf, pdf, ppf + elif backend == 'mpmath': + try: + import mpmath + except ImportError: + raise ImportError('Install "mpmath" to use this backend') + return mpmath.ncdf, mpmath.npdf, _gen_ppf(mpmath.erfc, math=mpmath) + elif backend == 'scipy': + try: + from scipy.stats import norm + except ImportError: + raise ImportError('Install "scipy" to use this backend') + return norm.cdf, norm.pdf, norm.ppf + raise ValueError('%r backend is not defined' % backend) + +def available_backends(): + backends = [None] + for backend in ['mpmath', 'scipy']: + try: + __import__(backend) + except ImportError: + continue + backends.append(backend) + return backends + +class Node(object): + + pass + +class Variable(Node, Gaussian): + + def __init__(self): + self.messages = {} + super(Variable, self).__init__() + + def set(self, val): + delta = self.delta(val) + self.pi, self.tau = val.pi, val.tau + return delta + + def delta(self, other): + pi_delta = abs(self.pi - other.pi) + if pi_delta == inf: + return 0. + return max(abs(self.tau - other.tau), math.sqrt(pi_delta)) + + def update_message(self, factor, pi=0, tau=0, message=None): + message = message or Gaussian(pi=pi, tau=tau) + old_message, self[factor] = self[factor], message + return self.set(self / old_message * message) + + def update_value(self, factor, pi=0, tau=0, value=None): + value = value or Gaussian(pi=pi, tau=tau) + old_message = self[factor] + self[factor] = value * old_message / self + return self.set(value) + + def __getitem__(self, factor): + return self.messages[factor] + + def __setitem__(self, factor, message): + self.messages[factor] = message + + def __repr__(self): + args = (type(self).__name__, super(Variable, self).__repr__(), + len(self.messages), '' if len(self.messages) == 1 else 's') + return '<%s %s with %d connection%s>' % args + + +class Factor(Node): + + def __init__(self, variables): + self.vars = variables + for var in variables: + var[self] = Gaussian() + + def down(self): + return 0 + + def up(self): + return 0 + + @property + def var(self): + assert len(self.vars) == 1 + return self.vars[0] + + def __repr__(self): + args = (type(self).__name__, len(self.vars), + '' if len(self.vars) == 1 else 's') + return '<%s with %d connection%s>' % args + + +class PriorFactor(Factor): + + def __init__(self, var, val, dynamic=0): + super(PriorFactor, self).__init__([var]) + self.val = val + self.dynamic = dynamic + + def down(self): + sigma = math.sqrt(self.val.sigma ** 2 + self.dynamic ** 2) + value = Gaussian(self.val.mu, sigma) + return self.var.update_value(self, value=value) + + +class LikelihoodFactor(Factor): + + def __init__(self, mean_var, value_var, variance): + super(LikelihoodFactor, self).__init__([mean_var, value_var]) + self.mean = mean_var + self.value = value_var + self.variance = variance + + def calc_a(self, var): + return 1. / (1. + self.variance * var.pi) + + def down(self): + # update value. + msg = self.mean / self.mean[self] + a = self.calc_a(msg) + return self.value.update_message(self, a * msg.pi, a * msg.tau) + + def up(self): + # update mean. + msg = self.value / self.value[self] + a = self.calc_a(msg) + return self.mean.update_message(self, a * msg.pi, a * msg.tau) + + +class SumFactor(Factor): + + def __init__(self, sum_var, term_vars, coeffs): + super(SumFactor, self).__init__([sum_var] + term_vars) + self.sum = sum_var + self.terms = term_vars + self.coeffs = coeffs + + def down(self): + vals = self.terms + msgs = [var[self] for var in vals] + return self.update(self.sum, vals, msgs, self.coeffs) + + def up(self, index=0): + coeff = self.coeffs[index] + coeffs = [] + for x, c in enumerate(self.coeffs): + try: + if x == index: + coeffs.append(1. / coeff) + else: + coeffs.append(-c / coeff) + except ZeroDivisionError: + coeffs.append(0.) + vals = self.terms[:] + vals[index] = self.sum + msgs = [var[self] for var in vals] + return self.update(self.terms[index], vals, msgs, coeffs) + + def update(self, var, vals, msgs, coeffs): + pi_inv = 0 + mu = 0 + for val, msg, coeff in zip(vals, msgs, coeffs): + div = val / msg + mu += coeff * div.mu + if pi_inv == inf: + continue + try: + # numpy.float64 handles floating-point error by different way. + # For example, it can just warn RuntimeWarning on n/0 problem + # instead of throwing ZeroDivisionError. So div.pi, the + # denominator has to be a built-in float. + pi_inv += coeff ** 2 / float(div.pi) + except ZeroDivisionError: + pi_inv = inf + pi = 1. / pi_inv + tau = pi * mu + return var.update_message(self, pi, tau) + + +class TruncateFactor(Factor): + + def __init__(self, var, v_func, w_func, draw_margin): + super(TruncateFactor, self).__init__([var]) + self.v_func = v_func + self.w_func = w_func + self.draw_margin = draw_margin + + def up(self): + val = self.var + msg = self.var[self] + div = val / msg + sqrt_pi = math.sqrt(div.pi) + args = (div.tau / sqrt_pi, self.draw_margin * sqrt_pi) + v = self.v_func(*args) + w = self.w_func(*args) + denom = (1. - w) + pi, tau = div.pi / denom, (div.tau + sqrt_pi * v) / denom + return val.update_value(self, pi, tau) + +#: Default initial mean of ratings. +MU = 25. +#: Default initial standard deviation of ratings. +SIGMA = MU / 3 +#: Default distance that guarantees about 76% chance of winning. +BETA = SIGMA / 2 +#: Default dynamic factor. +TAU = SIGMA / 100 +#: Default draw probability of the game. +DRAW_PROBABILITY = .10 +#: A basis to check reliability of the result. +DELTA = 0.0001 + + +def calc_draw_probability(draw_margin, size, env=None): + if env is None: + env = global_env() + return 2 * env.cdf(draw_margin / (math.sqrt(size) * env.beta)) - 1 + + +def calc_draw_margin(draw_probability, size, env=None): + if env is None: + env = global_env() + return env.ppf((draw_probability + 1) / 2.) * math.sqrt(size) * env.beta + + +def _team_sizes(rating_groups): + team_sizes = [0] + for group in rating_groups: + team_sizes.append(len(group) + team_sizes[-1]) + del team_sizes[0] + return team_sizes + + +def _floating_point_error(env): + if env.backend == 'mpmath': + msg = 'Set "mpmath.mp.dps" to higher' + else: + msg = 'Cannot calculate correctly, set backend to "mpmath"' + return FloatingPointError(msg) + + +class Rating(Gaussian): + def __init__(self, mu=None, sigma=None): + if isinstance(mu, tuple): + mu, sigma = mu + elif isinstance(mu, Gaussian): + mu, sigma = mu.mu, mu.sigma + if mu is None: + mu = global_env().mu + if sigma is None: + sigma = global_env().sigma + super(Rating, self).__init__(mu, sigma) + + def __int__(self): + return int(self.mu) + + def __long__(self): + return long(self.mu) + + def __float__(self): + return float(self.mu) + + def __iter__(self): + return iter((self.mu, self.sigma)) + + def __repr__(self): + c = type(self) + args = ('.'.join([c.__module__, c.__name__]), self.mu, self.sigma) + return '%s(mu=%.3f, sigma=%.3f)' % args + + +class TrueSkill(object): + def __init__(self, mu=MU, sigma=SIGMA, beta=BETA, tau=TAU, + draw_probability=DRAW_PROBABILITY, backend=None): + self.mu = mu + self.sigma = sigma + self.beta = beta + self.tau = tau + self.draw_probability = draw_probability + self.backend = backend + if isinstance(backend, tuple): + self.cdf, self.pdf, self.ppf = backend + else: + self.cdf, self.pdf, self.ppf = choose_backend(backend) + + def create_rating(self, mu=None, sigma=None): + if mu is None: + mu = self.mu + if sigma is None: + sigma = self.sigma + return Rating(mu, sigma) + + def v_win(self, diff, draw_margin): + x = diff - draw_margin + denom = self.cdf(x) + return (self.pdf(x) / denom) if denom else -x + + def v_draw(self, diff, draw_margin): + abs_diff = abs(diff) + a, b = draw_margin - abs_diff, -draw_margin - abs_diff + denom = self.cdf(a) - self.cdf(b) + numer = self.pdf(b) - self.pdf(a) + return ((numer / denom) if denom else a) * (-1 if diff < 0 else +1) + + def w_win(self, diff, draw_margin): + x = diff - draw_margin + v = self.v_win(diff, draw_margin) + w = v * (v + x) + if 0 < w < 1: + return w + raise _floating_point_error(self) + + def w_draw(self, diff, draw_margin): + abs_diff = abs(diff) + a, b = draw_margin - abs_diff, -draw_margin - abs_diff + denom = self.cdf(a) - self.cdf(b) + if not denom: + raise _floating_point_error(self) + v = self.v_draw(abs_diff, draw_margin) + return (v ** 2) + (a * self.pdf(a) - b * self.pdf(b)) / denom + + def validate_rating_groups(self, rating_groups): + # check group sizes + if len(rating_groups) < 2: + raise ValueError('Need multiple rating groups') + elif not all(rating_groups): + raise ValueError('Each group must contain multiple ratings') + # check group types + group_types = set(map(type, rating_groups)) + if len(group_types) != 1: + raise TypeError('All groups should be same type') + elif group_types.pop() is Rating: + raise TypeError('Rating cannot be a rating group') + # normalize rating_groups + if isinstance(rating_groups[0], dict): + dict_rating_groups = rating_groups + rating_groups = [] + keys = [] + for dict_rating_group in dict_rating_groups: + rating_group, key_group = [], [] + for key, rating in iteritems(dict_rating_group): + rating_group.append(rating) + key_group.append(key) + rating_groups.append(tuple(rating_group)) + keys.append(tuple(key_group)) + else: + rating_groups = list(rating_groups) + keys = None + return rating_groups, keys + + def validate_weights(self, weights, rating_groups, keys=None): + if weights is None: + weights = [(1,) * len(g) for g in rating_groups] + elif isinstance(weights, dict): + weights_dict, weights = weights, [] + for x, group in enumerate(rating_groups): + w = [] + weights.append(w) + for y, rating in enumerate(group): + if keys is not None: + y = keys[x][y] + w.append(weights_dict.get((x, y), 1)) + return weights + + def factor_graph_builders(self, rating_groups, ranks, weights): + flatten_ratings = sum(map(tuple, rating_groups), ()) + flatten_weights = sum(map(tuple, weights), ()) + size = len(flatten_ratings) + group_size = len(rating_groups) + # create variables + rating_vars = [Variable() for x in range(size)] + perf_vars = [Variable() for x in range(size)] + team_perf_vars = [Variable() for x in range(group_size)] + team_diff_vars = [Variable() for x in range(group_size - 1)] + team_sizes = _team_sizes(rating_groups) + # layer builders + def build_rating_layer(): + for rating_var, rating in zip(rating_vars, flatten_ratings): + yield PriorFactor(rating_var, rating, self.tau) + def build_perf_layer(): + for rating_var, perf_var in zip(rating_vars, perf_vars): + yield LikelihoodFactor(rating_var, perf_var, self.beta ** 2) + def build_team_perf_layer(): + for team, team_perf_var in enumerate(team_perf_vars): + if team > 0: + start = team_sizes[team - 1] + else: + start = 0 + end = team_sizes[team] + child_perf_vars = perf_vars[start:end] + coeffs = flatten_weights[start:end] + yield SumFactor(team_perf_var, child_perf_vars, coeffs) + def build_team_diff_layer(): + for team, team_diff_var in enumerate(team_diff_vars): + yield SumFactor(team_diff_var, + team_perf_vars[team:team + 2], [+1, -1]) + def build_trunc_layer(): + for x, team_diff_var in enumerate(team_diff_vars): + if callable(self.draw_probability): + # dynamic draw probability + team_perf1, team_perf2 = team_perf_vars[x:x + 2] + args = (Rating(team_perf1), Rating(team_perf2), self) + draw_probability = self.draw_probability(*args) + else: + # static draw probability + draw_probability = self.draw_probability + size = sum(map(len, rating_groups[x:x + 2])) + draw_margin = calc_draw_margin(draw_probability, size, self) + if ranks[x] == ranks[x + 1]: # is a tie? + v_func, w_func = self.v_draw, self.w_draw + else: + v_func, w_func = self.v_win, self.w_win + yield TruncateFactor(team_diff_var, + v_func, w_func, draw_margin) + # build layers + return (build_rating_layer, build_perf_layer, build_team_perf_layer, + build_team_diff_layer, build_trunc_layer) + + def run_schedule(self, build_rating_layer, build_perf_layer, + build_team_perf_layer, build_team_diff_layer, + build_trunc_layer, min_delta=DELTA): + if min_delta <= 0: + raise ValueError('min_delta must be greater than 0') + layers = [] + def build(builders): + layers_built = [list(build()) for build in builders] + layers.extend(layers_built) + return layers_built + # gray arrows + layers_built = build([build_rating_layer, + build_perf_layer, + build_team_perf_layer]) + rating_layer, perf_layer, team_perf_layer = layers_built + for f in chain(*layers_built): + f.down() + # arrow #1, #2, #3 + team_diff_layer, trunc_layer = build([build_team_diff_layer, + build_trunc_layer]) + team_diff_len = len(team_diff_layer) + for x in range(10): + if team_diff_len == 1: + # only two teams + team_diff_layer[0].down() + delta = trunc_layer[0].up() + else: + # multiple teams + delta = 0 + for x in range(team_diff_len - 1): + team_diff_layer[x].down() + delta = max(delta, trunc_layer[x].up()) + team_diff_layer[x].up(1) # up to right variable + for x in range(team_diff_len - 1, 0, -1): + team_diff_layer[x].down() + delta = max(delta, trunc_layer[x].up()) + team_diff_layer[x].up(0) # up to left variable + # repeat until to small update + if delta <= min_delta: + break + # up both ends + team_diff_layer[0].up(0) + team_diff_layer[team_diff_len - 1].up(1) + # up the remainder of the black arrows + for f in team_perf_layer: + for x in range(len(f.vars) - 1): + f.up(x) + for f in perf_layer: + f.up() + return layers + + def rate(self, rating_groups, ranks=None, weights=None, min_delta=DELTA): + rating_groups, keys = self.validate_rating_groups(rating_groups) + weights = self.validate_weights(weights, rating_groups, keys) + group_size = len(rating_groups) + if ranks is None: + ranks = range(group_size) + elif len(ranks) != group_size: + raise ValueError('Wrong ranks') + # sort rating groups by rank + by_rank = lambda x: x[1][1] + sorting = sorted(enumerate(zip(rating_groups, ranks, weights)), + key=by_rank) + sorted_rating_groups, sorted_ranks, sorted_weights = [], [], [] + for x, (g, r, w) in sorting: + sorted_rating_groups.append(g) + sorted_ranks.append(r) + # make weights to be greater than 0 + sorted_weights.append(max(min_delta, w_) for w_ in w) + # build factor graph + args = (sorted_rating_groups, sorted_ranks, sorted_weights) + builders = self.factor_graph_builders(*args) + args = builders + (min_delta,) + layers = self.run_schedule(*args) + # make result + rating_layer, team_sizes = layers[0], _team_sizes(sorted_rating_groups) + transformed_groups = [] + for start, end in zip([0] + team_sizes[:-1], team_sizes): + group = [] + for f in rating_layer[start:end]: + group.append(Rating(float(f.var.mu), float(f.var.sigma))) + transformed_groups.append(tuple(group)) + by_hint = lambda x: x[0] + unsorting = sorted(zip((x for x, __ in sorting), transformed_groups), + key=by_hint) + if keys is None: + return [g for x, g in unsorting] + # restore the structure with input dictionary keys + return [dict(zip(keys[x], g)) for x, g in unsorting] + + def quality(self, rating_groups, weights=None): + rating_groups, keys = self.validate_rating_groups(rating_groups) + weights = self.validate_weights(weights, rating_groups, keys) + flatten_ratings = sum(map(tuple, rating_groups), ()) + flatten_weights = sum(map(tuple, weights), ()) + length = len(flatten_ratings) + # a vector of all of the skill means + mean_matrix = Matrix([[r.mu] for r in flatten_ratings]) + # a matrix whose diagonal values are the variances (sigma ** 2) of each + # of the players. + def variance_matrix(height, width): + variances = (r.sigma ** 2 for r in flatten_ratings) + for x, variance in enumerate(variances): + yield (x, x), variance + variance_matrix = Matrix(variance_matrix, length, length) + # the player-team assignment and comparison matrix + def rotated_a_matrix(set_height, set_width): + t = 0 + for r, (cur, _next) in enumerate(zip(rating_groups[:-1], + rating_groups[1:])): + for x in range(t, t + len(cur)): + yield (r, x), flatten_weights[x] + t += 1 + x += 1 + for x in range(x, x + len(_next)): + yield (r, x), -flatten_weights[x] + set_height(r + 1) + set_width(x + 1) + rotated_a_matrix = Matrix(rotated_a_matrix) + a_matrix = rotated_a_matrix.transpose() + # match quality further derivation + _ata = (self.beta ** 2) * rotated_a_matrix * a_matrix + _atsa = rotated_a_matrix * variance_matrix * a_matrix + start = mean_matrix.transpose() * a_matrix + middle = _ata + _atsa + end = rotated_a_matrix * mean_matrix + # make result + e_arg = (-0.5 * start * middle.inverse() * end).determinant() + s_arg = _ata.determinant() / middle.determinant() + return math.exp(e_arg) * math.sqrt(s_arg) + + def expose(self, rating): + k = self.mu / self.sigma + return rating.mu - k * rating.sigma + + def make_as_global(self): + return setup(env=self) + + def __repr__(self): + c = type(self) + if callable(self.draw_probability): + f = self.draw_probability + draw_probability = '.'.join([f.__module__, f.__name__]) + else: + draw_probability = '%.1f%%' % (self.draw_probability * 100) + if self.backend is None: + backend = '' + elif isinstance(self.backend, tuple): + backend = ', backend=...' + else: + backend = ', backend=%r' % self.backend + args = ('.'.join([c.__module__, c.__name__]), self.mu, self.sigma, + self.beta, self.tau, draw_probability, backend) + return ('%s(mu=%.3f, sigma=%.3f, beta=%.3f, tau=%.3f, ' + 'draw_probability=%s%s)' % args) + + +def rate_1vs1(rating1, rating2, drawn=False, min_delta=DELTA, env=None): + if env is None: + env = global_env() + ranks = [0, 0 if drawn else 1] + teams = env.rate([(rating1,), (rating2,)], ranks, min_delta=min_delta) + return teams[0][0], teams[1][0] + + +def quality_1vs1(rating1, rating2, env=None): + if env is None: + env = global_env() + return env.quality([(rating1,), (rating2,)]) + + +def global_env(): + try: + global_env.__trueskill__ + except AttributeError: + # setup the default environment + setup() + return global_env.__trueskill__ + + +def setup(mu=MU, sigma=SIGMA, beta=BETA, tau=TAU, + draw_probability=DRAW_PROBABILITY, backend=None, env=None): + if env is None: + env = TrueSkill(mu, sigma, beta, tau, draw_probability, backend) + global_env.__trueskill__ = env + return env + + +def rate(rating_groups, ranks=None, weights=None, min_delta=DELTA): + return global_env().rate(rating_groups, ranks, weights, min_delta) + + +def quality(rating_groups, weights=None): + return global_env().quality(rating_groups, weights) + + +def expose(rating): + return global_env().expose(rating) \ No newline at end of file diff --git a/analysis-master/build/lib/analysis/regression.py b/analysis-master/build/lib/analysis/regression.py new file mode 100644 index 00000000..e899e9ff --- /dev/null +++ b/analysis-master/build/lib/analysis/regression.py @@ -0,0 +1,220 @@ +# Titan Robotics Team 2022: CUDA-based Regressions Module +# Written by Arthur Lu & Jacob Levine +# Notes: +# this module has been automatically inegrated into analysis.py, and should be callable as a class from the package +# this module is cuda-optimized and vectorized (except for one small part) +# setup: + +__version__ = "1.0.0.004" + +# changelog should be viewed using print(analysis.regression.__changelog__) +__changelog__ = """ + 1.0.0.004: + - bug fixes + - fixed changelog + 1.0.0.003: + - bug fixes + 1.0.0.002: + -Added more parameters to log, exponential, polynomial + -Added SigmoidalRegKernelArthur, because Arthur apparently needs + to train the scaling and shifting of sigmoids + 1.0.0.001: + -initial release, with linear, log, exponential, polynomial, and sigmoid kernels + -already vectorized (except for polynomial generation) and CUDA-optimized +""" + +__author__ = ( + "Jacob Levine ", + "Arthur Lu " +) + +__all__ = [ + 'factorial', + 'take_all_pwrs', + 'num_poly_terms', + 'set_device', + 'LinearRegKernel', + 'SigmoidalRegKernel', + 'LogRegKernel', + 'PolyRegKernel', + 'ExpRegKernel', + 'SigmoidalRegKernelArthur', + 'SGDTrain', + 'CustomTrain' +] + +import torch + +global device + +device = "cuda:0" if torch.torch.cuda.is_available() else "cpu" + +#todo: document completely + +def set_device(self, new_device): + device=new_device + +class LinearRegKernel(): + parameters= [] + weights=None + bias=None + def __init__(self, num_vars): + self.weights=torch.rand(num_vars, requires_grad=True, device=device) + self.bias=torch.rand(1, requires_grad=True, device=device) + self.parameters=[self.weights,self.bias] + def forward(self,mtx): + long_bias=self.bias.repeat([1,mtx.size()[1]]) + return torch.matmul(self.weights,mtx)+long_bias + +class SigmoidalRegKernel(): + parameters= [] + weights=None + bias=None + sigmoid=torch.nn.Sigmoid() + def __init__(self, num_vars): + self.weights=torch.rand(num_vars, requires_grad=True, device=device) + self.bias=torch.rand(1, requires_grad=True, device=device) + self.parameters=[self.weights,self.bias] + def forward(self,mtx): + long_bias=self.bias.repeat([1,mtx.size()[1]]) + return self.sigmoid(torch.matmul(self.weights,mtx)+long_bias) + +class SigmoidalRegKernelArthur(): + parameters= [] + weights=None + in_bias=None + scal_mult=None + out_bias=None + sigmoid=torch.nn.Sigmoid() + def __init__(self, num_vars): + self.weights=torch.rand(num_vars, requires_grad=True, device=device) + self.in_bias=torch.rand(1, requires_grad=True, device=device) + self.scal_mult=torch.rand(1, requires_grad=True, device=device) + self.out_bias=torch.rand(1, requires_grad=True, device=device) + self.parameters=[self.weights,self.in_bias, self.scal_mult, self.out_bias] + def forward(self,mtx): + long_in_bias=self.in_bias.repeat([1,mtx.size()[1]]) + long_out_bias=self.out_bias.repeat([1,mtx.size()[1]]) + return (self.scal_mult*self.sigmoid(torch.matmul(self.weights,mtx)+long_in_bias))+long_out_bias + +class LogRegKernel(): + parameters= [] + weights=None + in_bias=None + scal_mult=None + out_bias=None + def __init__(self, num_vars): + self.weights=torch.rand(num_vars, requires_grad=True, device=device) + self.in_bias=torch.rand(1, requires_grad=True, device=device) + self.scal_mult=torch.rand(1, requires_grad=True, device=device) + self.out_bias=torch.rand(1, requires_grad=True, device=device) + self.parameters=[self.weights,self.in_bias, self.scal_mult, self.out_bias] + def forward(self,mtx): + long_in_bias=self.in_bias.repeat([1,mtx.size()[1]]) + long_out_bias=self.out_bias.repeat([1,mtx.size()[1]]) + return (self.scal_mult*torch.log(torch.matmul(self.weights,mtx)+long_in_bias))+long_out_bias + +class ExpRegKernel(): + parameters= [] + weights=None + in_bias=None + scal_mult=None + out_bias=None + def __init__(self, num_vars): + self.weights=torch.rand(num_vars, requires_grad=True, device=device) + self.in_bias=torch.rand(1, requires_grad=True, device=device) + self.scal_mult=torch.rand(1, requires_grad=True, device=device) + self.out_bias=torch.rand(1, requires_grad=True, device=device) + self.parameters=[self.weights,self.in_bias, self.scal_mult, self.out_bias] + def forward(self,mtx): + long_in_bias=self.in_bias.repeat([1,mtx.size()[1]]) + long_out_bias=self.out_bias.repeat([1,mtx.size()[1]]) + return (self.scal_mult*torch.exp(torch.matmul(self.weights,mtx)+long_in_bias))+long_out_bias + +class PolyRegKernel(): + parameters= [] + weights=None + bias=None + power=None + def __init__(self, num_vars, power): + self.power=power + num_terms=self.num_poly_terms(num_vars, power) + self.weights=torch.rand(num_terms, requires_grad=True, device=device) + self.bias=torch.rand(1, requires_grad=True, device=device) + self.parameters=[self.weights,self.bias] + def num_poly_terms(self,num_vars, power): + if power == 0: + return 0 + return int(self.factorial(num_vars+power-1) / self.factorial(power) / self.factorial(num_vars-1)) + self.num_poly_terms(num_vars, power-1) + def factorial(self,n): + if n==0: + return 1 + else: + return n*self.factorial(n-1) + def take_all_pwrs(self, vec, pwr): + #todo: vectorize (kinda) + combins=torch.combinations(vec, r=pwr, with_replacement=True) + out=torch.ones(combins.size()[0]).to(device).to(torch.float) + for i in torch.t(combins).to(device).to(torch.float): + out *= i + if pwr == 1: + return out + else: + return torch.cat((out,self.take_all_pwrs(vec, pwr-1))) + def forward(self,mtx): + #TODO: Vectorize the last part + cols=[] + for i in torch.t(mtx): + cols.append(self.take_all_pwrs(i,self.power)) + new_mtx=torch.t(torch.stack(cols)) + long_bias=self.bias.repeat([1,mtx.size()[1]]) + return torch.matmul(self.weights,new_mtx)+long_bias + +def SGDTrain(self, kernel, data, ground, loss=torch.nn.MSELoss(), iterations=1000, learning_rate=.1, return_losses=False): + optim=torch.optim.SGD(kernel.parameters, lr=learning_rate) + data_cuda=data.to(device) + ground_cuda=ground.to(device) + if (return_losses): + losses=[] + for i in range(iterations): + with torch.set_grad_enabled(True): + optim.zero_grad() + pred=kernel.forward(data_cuda) + ls=loss(pred,ground_cuda) + losses.append(ls.item()) + ls.backward() + optim.step() + return [kernel,losses] + else: + for i in range(iterations): + with torch.set_grad_enabled(True): + optim.zero_grad() + pred=kernel.forward(data_cuda) + ls=loss(pred,ground_cuda) + ls.backward() + optim.step() + return kernel + +def CustomTrain(self, kernel, optim, data, ground, loss=torch.nn.MSELoss(), iterations=1000, return_losses=False): + data_cuda=data.to(device) + ground_cuda=ground.to(device) + if (return_losses): + losses=[] + for i in range(iterations): + with torch.set_grad_enabled(True): + optim.zero_grad() + pred=kernel.forward(data) + ls=loss(pred,ground) + losses.append(ls.item()) + ls.backward() + optim.step() + return [kernel,losses] + else: + for i in range(iterations): + with torch.set_grad_enabled(True): + optim.zero_grad() + pred=kernel.forward(data_cuda) + ls=loss(pred,ground_cuda) + ls.backward() + optim.step() + return kernel \ No newline at end of file diff --git a/analysis-master/build/lib/analysis/titanlearn.py b/analysis-master/build/lib/analysis/titanlearn.py new file mode 100644 index 00000000..b69d36e3 --- /dev/null +++ b/analysis-master/build/lib/analysis/titanlearn.py @@ -0,0 +1,122 @@ +# Titan Robotics Team 2022: ML Module +# Written by Arthur Lu & Jacob Levine +# Notes: +# this should be imported as a python module using 'import titanlearn' +# this should be included in the local directory or environment variable +# this module is optimized for multhreaded computing +# this module learns from its mistakes far faster than 2022's captains +# setup: + +__version__ = "2.0.1.001" + +#changelog should be viewed using print(analysis.__changelog__) +__changelog__ = """changelog: + 2.0.1.001: + - removed matplotlib import + - removed graphloss() + 2.0.1.000: + - added net, dataset, dataloader, and stdtrain template definitions + - added graphloss function + 2.0.0.001: + - added clear functions + 2.0.0.000: + - complete rewrite planned + - depreciated 1.0.0.xxx versions + - added simple training loop + 1.0.0.xxx: + -added generation of ANNS, basic SGD training +""" + +__author__ = ( + "Arthur Lu ," + "Jacob Levine ," + ) + +__all__ = [ + 'clear', + 'net', + 'dataset', + 'dataloader', + 'train', + 'stdtrainer', + ] + +import torch +from os import system, name +import numpy as np + +def clear(): + if name == 'nt': + _ = system('cls') + else: + _ = system('clear') + +class net(torch.nn.Module): #template for standard neural net + def __init__(self): + super(Net, self).__init__() + + def forward(self, input): + pass + +class dataset(torch.utils.data.Dataset): #template for standard dataset + + def __init__(self): + super(torch.utils.data.Dataset).__init__() + + def __getitem__(self, index): + pass + + def __len__(self): + pass + +def dataloader(dataset, batch_size, num_workers, shuffle = True): + + return torch.utils.data.DataLoader(dataset, batch_size=batch_size, shuffle=shuffle, num_workers=num_workers) + +def train(device, net, epochs, trainloader, optimizer, criterion): #expects standard dataloader, whch returns (inputs, labels) + + dataset_len = trainloader.dataset.__len__() + iter_count = 0 + running_loss = 0 + running_loss_list = [] + + for epoch in range(epochs): # loop over the dataset multiple times + + for i, data in enumerate(trainloader, 0): + + inputs = data[0].to(device) + labels = data[1].to(device) + + optimizer.zero_grad() + + outputs = net(inputs) + loss = criterion(outputs, labels.to(torch.float)) + + loss.backward() + optimizer.step() + + # monitoring steps below + + iter_count += 1 + running_loss += loss.item() + running_loss_list.append(running_loss) + clear() + + print("training on: " + device) + print("iteration: " + str(i) + "/" + str(int(dataset_len / trainloader.batch_size)) + " | " + "epoch: " + str(epoch) + "/" + str(epochs)) + print("current batch loss: " + str(loss.item)) + print("running loss: " + str(running_loss / iter_count)) + + return net, running_loss_list + print("finished training") + +def stdtrainer(net, criterion, optimizer, dataloader, epochs, batch_size): + + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + net = net.to(device) + criterion = criterion.to(device) + optimizer = optimizer.to(device) + trainloader = dataloader + + return train(device, net, epochs, trainloader, optimizer, criterion) \ No newline at end of file diff --git a/analysis-master/build/lib/analysis/trueskill.py b/analysis-master/build/lib/analysis/trueskill.py new file mode 100644 index 00000000..116357df --- /dev/null +++ b/analysis-master/build/lib/analysis/trueskill.py @@ -0,0 +1,907 @@ +from __future__ import absolute_import + +from itertools import chain +import math + +from six import iteritems +from six.moves import map, range, zip +from six import iterkeys + +import copy +try: + from numbers import Number +except ImportError: + Number = (int, long, float, complex) + +inf = float('inf') + +class Gaussian(object): + #: Precision, the inverse of the variance. + pi = 0 + #: Precision adjusted mean, the precision multiplied by the mean. + tau = 0 + + def __init__(self, mu=None, sigma=None, pi=0, tau=0): + if mu is not None: + if sigma is None: + raise TypeError('sigma argument is needed') + elif sigma == 0: + raise ValueError('sigma**2 should be greater than 0') + pi = sigma ** -2 + tau = pi * mu + self.pi = pi + self.tau = tau + + @property + def mu(self): + return self.pi and self.tau / self.pi + + @property + def sigma(self): + return math.sqrt(1 / self.pi) if self.pi else inf + + def __mul__(self, other): + pi, tau = self.pi + other.pi, self.tau + other.tau + return Gaussian(pi=pi, tau=tau) + + def __truediv__(self, other): + pi, tau = self.pi - other.pi, self.tau - other.tau + return Gaussian(pi=pi, tau=tau) + + __div__ = __truediv__ # for Python 2 + + def __eq__(self, other): + return self.pi == other.pi and self.tau == other.tau + + def __lt__(self, other): + return self.mu < other.mu + + def __le__(self, other): + return self.mu <= other.mu + + def __gt__(self, other): + return self.mu > other.mu + + def __ge__(self, other): + return self.mu >= other.mu + + def __repr__(self): + return 'N(mu={:.3f}, sigma={:.3f})'.format(self.mu, self.sigma) + + def _repr_latex_(self): + latex = r'\mathcal{{ N }}( {:.3f}, {:.3f}^2 )'.format(self.mu, self.sigma) + return '$%s$' % latex + +class Matrix(list): + def __init__(self, src, height=None, width=None): + if callable(src): + f, src = src, {} + size = [height, width] + if not height: + def set_height(height): + size[0] = height + size[0] = set_height + if not width: + def set_width(width): + size[1] = width + size[1] = set_width + try: + for (r, c), val in f(*size): + src[r, c] = val + except TypeError: + raise TypeError('A callable src must return an interable ' + 'which generates a tuple containing ' + 'coordinate and value') + height, width = tuple(size) + if height is None or width is None: + raise TypeError('A callable src must call set_height and ' + 'set_width if the size is non-deterministic') + if isinstance(src, list): + is_number = lambda x: isinstance(x, Number) + unique_col_sizes = set(map(len, src)) + everything_are_number = filter(is_number, sum(src, [])) + if len(unique_col_sizes) != 1 or not everything_are_number: + raise ValueError('src must be a rectangular array of numbers') + two_dimensional_array = src + elif isinstance(src, dict): + if not height or not width: + w = h = 0 + for r, c in iterkeys(src): + if not height: + h = max(h, r + 1) + if not width: + w = max(w, c + 1) + if not height: + height = h + if not width: + width = w + two_dimensional_array = [] + for r in range(height): + row = [] + two_dimensional_array.append(row) + for c in range(width): + row.append(src.get((r, c), 0)) + else: + raise TypeError('src must be a list or dict or callable') + super(Matrix, self).__init__(two_dimensional_array) + + @property + def height(self): + return len(self) + + @property + def width(self): + return len(self[0]) + + def transpose(self): + height, width = self.height, self.width + src = {} + for c in range(width): + for r in range(height): + src[c, r] = self[r][c] + return type(self)(src, height=width, width=height) + + def minor(self, row_n, col_n): + height, width = self.height, self.width + if not (0 <= row_n < height): + raise ValueError('row_n should be between 0 and %d' % height) + elif not (0 <= col_n < width): + raise ValueError('col_n should be between 0 and %d' % width) + two_dimensional_array = [] + for r in range(height): + if r == row_n: + continue + row = [] + two_dimensional_array.append(row) + for c in range(width): + if c == col_n: + continue + row.append(self[r][c]) + return type(self)(two_dimensional_array) + + def determinant(self): + height, width = self.height, self.width + if height != width: + raise ValueError('Only square matrix can calculate a determinant') + tmp, rv = copy.deepcopy(self), 1. + for c in range(width - 1, 0, -1): + pivot, r = max((abs(tmp[r][c]), r) for r in range(c + 1)) + pivot = tmp[r][c] + if not pivot: + return 0. + tmp[r], tmp[c] = tmp[c], tmp[r] + if r != c: + rv = -rv + rv *= pivot + fact = -1. / pivot + for r in range(c): + f = fact * tmp[r][c] + for x in range(c): + tmp[r][x] += f * tmp[c][x] + return rv * tmp[0][0] + + def adjugate(self): + height, width = self.height, self.width + if height != width: + raise ValueError('Only square matrix can be adjugated') + if height == 2: + a, b = self[0][0], self[0][1] + c, d = self[1][0], self[1][1] + return type(self)([[d, -b], [-c, a]]) + src = {} + for r in range(height): + for c in range(width): + sign = -1 if (r + c) % 2 else 1 + src[r, c] = self.minor(r, c).determinant() * sign + return type(self)(src, height, width) + + def inverse(self): + if self.height == self.width == 1: + return type(self)([[1. / self[0][0]]]) + return (1. / self.determinant()) * self.adjugate() + + def __add__(self, other): + height, width = self.height, self.width + if (height, width) != (other.height, other.width): + raise ValueError('Must be same size') + src = {} + for r in range(height): + for c in range(width): + src[r, c] = self[r][c] + other[r][c] + return type(self)(src, height, width) + + def __mul__(self, other): + if self.width != other.height: + raise ValueError('Bad size') + height, width = self.height, other.width + src = {} + for r in range(height): + for c in range(width): + src[r, c] = sum(self[r][x] * other[x][c] + for x in range(self.width)) + return type(self)(src, height, width) + + def __rmul__(self, other): + if not isinstance(other, Number): + raise TypeError('The operand should be a number') + height, width = self.height, self.width + src = {} + for r in range(height): + for c in range(width): + src[r, c] = other * self[r][c] + return type(self)(src, height, width) + + def __repr__(self): + return '{}({})'.format(type(self).__name__, super(Matrix, self).__repr__()) + + def _repr_latex_(self): + rows = [' && '.join(['%.3f' % cell for cell in row]) for row in self] + latex = r'\begin{matrix} %s \end{matrix}' % r'\\'.join(rows) + return '$%s$' % latex + +def _gen_erfcinv(erfc, math=math): + def erfcinv(y): + """The inverse function of erfc.""" + if y >= 2: + return -100. + elif y <= 0: + return 100. + zero_point = y < 1 + if not zero_point: + y = 2 - y + t = math.sqrt(-2 * math.log(y / 2.)) + x = -0.70711 * \ + ((2.30753 + t * 0.27061) / (1. + t * (0.99229 + t * 0.04481)) - t) + for i in range(2): + err = erfc(x) - y + x += err / (1.12837916709551257 * math.exp(-(x ** 2)) - x * err) + return x if zero_point else -x + return erfcinv + +def _gen_ppf(erfc, math=math): + erfcinv = _gen_erfcinv(erfc, math) + def ppf(x, mu=0, sigma=1): + return mu - sigma * math.sqrt(2) * erfcinv(2 * x) + return ppf + +def erfc(x): + z = abs(x) + t = 1. / (1. + z / 2.) + r = t * math.exp(-z * z - 1.26551223 + t * (1.00002368 + t * ( + 0.37409196 + t * (0.09678418 + t * (-0.18628806 + t * ( + 0.27886807 + t * (-1.13520398 + t * (1.48851587 + t * ( + -0.82215223 + t * 0.17087277 + ))) + ))) + ))) + return 2. - r if x < 0 else r + +def cdf(x, mu=0, sigma=1): + return 0.5 * erfc(-(x - mu) / (sigma * math.sqrt(2))) + + +def pdf(x, mu=0, sigma=1): + return (1 / math.sqrt(2 * math.pi) * abs(sigma) * + math.exp(-(((x - mu) / abs(sigma)) ** 2 / 2))) + +ppf = _gen_ppf(erfc) + +def choose_backend(backend): + if backend is None: # fallback + return cdf, pdf, ppf + elif backend == 'mpmath': + try: + import mpmath + except ImportError: + raise ImportError('Install "mpmath" to use this backend') + return mpmath.ncdf, mpmath.npdf, _gen_ppf(mpmath.erfc, math=mpmath) + elif backend == 'scipy': + try: + from scipy.stats import norm + except ImportError: + raise ImportError('Install "scipy" to use this backend') + return norm.cdf, norm.pdf, norm.ppf + raise ValueError('%r backend is not defined' % backend) + +def available_backends(): + backends = [None] + for backend in ['mpmath', 'scipy']: + try: + __import__(backend) + except ImportError: + continue + backends.append(backend) + return backends + +class Node(object): + + pass + +class Variable(Node, Gaussian): + + def __init__(self): + self.messages = {} + super(Variable, self).__init__() + + def set(self, val): + delta = self.delta(val) + self.pi, self.tau = val.pi, val.tau + return delta + + def delta(self, other): + pi_delta = abs(self.pi - other.pi) + if pi_delta == inf: + return 0. + return max(abs(self.tau - other.tau), math.sqrt(pi_delta)) + + def update_message(self, factor, pi=0, tau=0, message=None): + message = message or Gaussian(pi=pi, tau=tau) + old_message, self[factor] = self[factor], message + return self.set(self / old_message * message) + + def update_value(self, factor, pi=0, tau=0, value=None): + value = value or Gaussian(pi=pi, tau=tau) + old_message = self[factor] + self[factor] = value * old_message / self + return self.set(value) + + def __getitem__(self, factor): + return self.messages[factor] + + def __setitem__(self, factor, message): + self.messages[factor] = message + + def __repr__(self): + args = (type(self).__name__, super(Variable, self).__repr__(), + len(self.messages), '' if len(self.messages) == 1 else 's') + return '<%s %s with %d connection%s>' % args + + +class Factor(Node): + + def __init__(self, variables): + self.vars = variables + for var in variables: + var[self] = Gaussian() + + def down(self): + return 0 + + def up(self): + return 0 + + @property + def var(self): + assert len(self.vars) == 1 + return self.vars[0] + + def __repr__(self): + args = (type(self).__name__, len(self.vars), + '' if len(self.vars) == 1 else 's') + return '<%s with %d connection%s>' % args + + +class PriorFactor(Factor): + + def __init__(self, var, val, dynamic=0): + super(PriorFactor, self).__init__([var]) + self.val = val + self.dynamic = dynamic + + def down(self): + sigma = math.sqrt(self.val.sigma ** 2 + self.dynamic ** 2) + value = Gaussian(self.val.mu, sigma) + return self.var.update_value(self, value=value) + + +class LikelihoodFactor(Factor): + + def __init__(self, mean_var, value_var, variance): + super(LikelihoodFactor, self).__init__([mean_var, value_var]) + self.mean = mean_var + self.value = value_var + self.variance = variance + + def calc_a(self, var): + return 1. / (1. + self.variance * var.pi) + + def down(self): + # update value. + msg = self.mean / self.mean[self] + a = self.calc_a(msg) + return self.value.update_message(self, a * msg.pi, a * msg.tau) + + def up(self): + # update mean. + msg = self.value / self.value[self] + a = self.calc_a(msg) + return self.mean.update_message(self, a * msg.pi, a * msg.tau) + + +class SumFactor(Factor): + + def __init__(self, sum_var, term_vars, coeffs): + super(SumFactor, self).__init__([sum_var] + term_vars) + self.sum = sum_var + self.terms = term_vars + self.coeffs = coeffs + + def down(self): + vals = self.terms + msgs = [var[self] for var in vals] + return self.update(self.sum, vals, msgs, self.coeffs) + + def up(self, index=0): + coeff = self.coeffs[index] + coeffs = [] + for x, c in enumerate(self.coeffs): + try: + if x == index: + coeffs.append(1. / coeff) + else: + coeffs.append(-c / coeff) + except ZeroDivisionError: + coeffs.append(0.) + vals = self.terms[:] + vals[index] = self.sum + msgs = [var[self] for var in vals] + return self.update(self.terms[index], vals, msgs, coeffs) + + def update(self, var, vals, msgs, coeffs): + pi_inv = 0 + mu = 0 + for val, msg, coeff in zip(vals, msgs, coeffs): + div = val / msg + mu += coeff * div.mu + if pi_inv == inf: + continue + try: + # numpy.float64 handles floating-point error by different way. + # For example, it can just warn RuntimeWarning on n/0 problem + # instead of throwing ZeroDivisionError. So div.pi, the + # denominator has to be a built-in float. + pi_inv += coeff ** 2 / float(div.pi) + except ZeroDivisionError: + pi_inv = inf + pi = 1. / pi_inv + tau = pi * mu + return var.update_message(self, pi, tau) + + +class TruncateFactor(Factor): + + def __init__(self, var, v_func, w_func, draw_margin): + super(TruncateFactor, self).__init__([var]) + self.v_func = v_func + self.w_func = w_func + self.draw_margin = draw_margin + + def up(self): + val = self.var + msg = self.var[self] + div = val / msg + sqrt_pi = math.sqrt(div.pi) + args = (div.tau / sqrt_pi, self.draw_margin * sqrt_pi) + v = self.v_func(*args) + w = self.w_func(*args) + denom = (1. - w) + pi, tau = div.pi / denom, (div.tau + sqrt_pi * v) / denom + return val.update_value(self, pi, tau) + +#: Default initial mean of ratings. +MU = 25. +#: Default initial standard deviation of ratings. +SIGMA = MU / 3 +#: Default distance that guarantees about 76% chance of winning. +BETA = SIGMA / 2 +#: Default dynamic factor. +TAU = SIGMA / 100 +#: Default draw probability of the game. +DRAW_PROBABILITY = .10 +#: A basis to check reliability of the result. +DELTA = 0.0001 + + +def calc_draw_probability(draw_margin, size, env=None): + if env is None: + env = global_env() + return 2 * env.cdf(draw_margin / (math.sqrt(size) * env.beta)) - 1 + + +def calc_draw_margin(draw_probability, size, env=None): + if env is None: + env = global_env() + return env.ppf((draw_probability + 1) / 2.) * math.sqrt(size) * env.beta + + +def _team_sizes(rating_groups): + team_sizes = [0] + for group in rating_groups: + team_sizes.append(len(group) + team_sizes[-1]) + del team_sizes[0] + return team_sizes + + +def _floating_point_error(env): + if env.backend == 'mpmath': + msg = 'Set "mpmath.mp.dps" to higher' + else: + msg = 'Cannot calculate correctly, set backend to "mpmath"' + return FloatingPointError(msg) + + +class Rating(Gaussian): + def __init__(self, mu=None, sigma=None): + if isinstance(mu, tuple): + mu, sigma = mu + elif isinstance(mu, Gaussian): + mu, sigma = mu.mu, mu.sigma + if mu is None: + mu = global_env().mu + if sigma is None: + sigma = global_env().sigma + super(Rating, self).__init__(mu, sigma) + + def __int__(self): + return int(self.mu) + + def __long__(self): + return long(self.mu) + + def __float__(self): + return float(self.mu) + + def __iter__(self): + return iter((self.mu, self.sigma)) + + def __repr__(self): + c = type(self) + args = ('.'.join([c.__module__, c.__name__]), self.mu, self.sigma) + return '%s(mu=%.3f, sigma=%.3f)' % args + + +class TrueSkill(object): + def __init__(self, mu=MU, sigma=SIGMA, beta=BETA, tau=TAU, + draw_probability=DRAW_PROBABILITY, backend=None): + self.mu = mu + self.sigma = sigma + self.beta = beta + self.tau = tau + self.draw_probability = draw_probability + self.backend = backend + if isinstance(backend, tuple): + self.cdf, self.pdf, self.ppf = backend + else: + self.cdf, self.pdf, self.ppf = choose_backend(backend) + + def create_rating(self, mu=None, sigma=None): + if mu is None: + mu = self.mu + if sigma is None: + sigma = self.sigma + return Rating(mu, sigma) + + def v_win(self, diff, draw_margin): + x = diff - draw_margin + denom = self.cdf(x) + return (self.pdf(x) / denom) if denom else -x + + def v_draw(self, diff, draw_margin): + abs_diff = abs(diff) + a, b = draw_margin - abs_diff, -draw_margin - abs_diff + denom = self.cdf(a) - self.cdf(b) + numer = self.pdf(b) - self.pdf(a) + return ((numer / denom) if denom else a) * (-1 if diff < 0 else +1) + + def w_win(self, diff, draw_margin): + x = diff - draw_margin + v = self.v_win(diff, draw_margin) + w = v * (v + x) + if 0 < w < 1: + return w + raise _floating_point_error(self) + + def w_draw(self, diff, draw_margin): + abs_diff = abs(diff) + a, b = draw_margin - abs_diff, -draw_margin - abs_diff + denom = self.cdf(a) - self.cdf(b) + if not denom: + raise _floating_point_error(self) + v = self.v_draw(abs_diff, draw_margin) + return (v ** 2) + (a * self.pdf(a) - b * self.pdf(b)) / denom + + def validate_rating_groups(self, rating_groups): + # check group sizes + if len(rating_groups) < 2: + raise ValueError('Need multiple rating groups') + elif not all(rating_groups): + raise ValueError('Each group must contain multiple ratings') + # check group types + group_types = set(map(type, rating_groups)) + if len(group_types) != 1: + raise TypeError('All groups should be same type') + elif group_types.pop() is Rating: + raise TypeError('Rating cannot be a rating group') + # normalize rating_groups + if isinstance(rating_groups[0], dict): + dict_rating_groups = rating_groups + rating_groups = [] + keys = [] + for dict_rating_group in dict_rating_groups: + rating_group, key_group = [], [] + for key, rating in iteritems(dict_rating_group): + rating_group.append(rating) + key_group.append(key) + rating_groups.append(tuple(rating_group)) + keys.append(tuple(key_group)) + else: + rating_groups = list(rating_groups) + keys = None + return rating_groups, keys + + def validate_weights(self, weights, rating_groups, keys=None): + if weights is None: + weights = [(1,) * len(g) for g in rating_groups] + elif isinstance(weights, dict): + weights_dict, weights = weights, [] + for x, group in enumerate(rating_groups): + w = [] + weights.append(w) + for y, rating in enumerate(group): + if keys is not None: + y = keys[x][y] + w.append(weights_dict.get((x, y), 1)) + return weights + + def factor_graph_builders(self, rating_groups, ranks, weights): + flatten_ratings = sum(map(tuple, rating_groups), ()) + flatten_weights = sum(map(tuple, weights), ()) + size = len(flatten_ratings) + group_size = len(rating_groups) + # create variables + rating_vars = [Variable() for x in range(size)] + perf_vars = [Variable() for x in range(size)] + team_perf_vars = [Variable() for x in range(group_size)] + team_diff_vars = [Variable() for x in range(group_size - 1)] + team_sizes = _team_sizes(rating_groups) + # layer builders + def build_rating_layer(): + for rating_var, rating in zip(rating_vars, flatten_ratings): + yield PriorFactor(rating_var, rating, self.tau) + def build_perf_layer(): + for rating_var, perf_var in zip(rating_vars, perf_vars): + yield LikelihoodFactor(rating_var, perf_var, self.beta ** 2) + def build_team_perf_layer(): + for team, team_perf_var in enumerate(team_perf_vars): + if team > 0: + start = team_sizes[team - 1] + else: + start = 0 + end = team_sizes[team] + child_perf_vars = perf_vars[start:end] + coeffs = flatten_weights[start:end] + yield SumFactor(team_perf_var, child_perf_vars, coeffs) + def build_team_diff_layer(): + for team, team_diff_var in enumerate(team_diff_vars): + yield SumFactor(team_diff_var, + team_perf_vars[team:team + 2], [+1, -1]) + def build_trunc_layer(): + for x, team_diff_var in enumerate(team_diff_vars): + if callable(self.draw_probability): + # dynamic draw probability + team_perf1, team_perf2 = team_perf_vars[x:x + 2] + args = (Rating(team_perf1), Rating(team_perf2), self) + draw_probability = self.draw_probability(*args) + else: + # static draw probability + draw_probability = self.draw_probability + size = sum(map(len, rating_groups[x:x + 2])) + draw_margin = calc_draw_margin(draw_probability, size, self) + if ranks[x] == ranks[x + 1]: # is a tie? + v_func, w_func = self.v_draw, self.w_draw + else: + v_func, w_func = self.v_win, self.w_win + yield TruncateFactor(team_diff_var, + v_func, w_func, draw_margin) + # build layers + return (build_rating_layer, build_perf_layer, build_team_perf_layer, + build_team_diff_layer, build_trunc_layer) + + def run_schedule(self, build_rating_layer, build_perf_layer, + build_team_perf_layer, build_team_diff_layer, + build_trunc_layer, min_delta=DELTA): + if min_delta <= 0: + raise ValueError('min_delta must be greater than 0') + layers = [] + def build(builders): + layers_built = [list(build()) for build in builders] + layers.extend(layers_built) + return layers_built + # gray arrows + layers_built = build([build_rating_layer, + build_perf_layer, + build_team_perf_layer]) + rating_layer, perf_layer, team_perf_layer = layers_built + for f in chain(*layers_built): + f.down() + # arrow #1, #2, #3 + team_diff_layer, trunc_layer = build([build_team_diff_layer, + build_trunc_layer]) + team_diff_len = len(team_diff_layer) + for x in range(10): + if team_diff_len == 1: + # only two teams + team_diff_layer[0].down() + delta = trunc_layer[0].up() + else: + # multiple teams + delta = 0 + for x in range(team_diff_len - 1): + team_diff_layer[x].down() + delta = max(delta, trunc_layer[x].up()) + team_diff_layer[x].up(1) # up to right variable + for x in range(team_diff_len - 1, 0, -1): + team_diff_layer[x].down() + delta = max(delta, trunc_layer[x].up()) + team_diff_layer[x].up(0) # up to left variable + # repeat until to small update + if delta <= min_delta: + break + # up both ends + team_diff_layer[0].up(0) + team_diff_layer[team_diff_len - 1].up(1) + # up the remainder of the black arrows + for f in team_perf_layer: + for x in range(len(f.vars) - 1): + f.up(x) + for f in perf_layer: + f.up() + return layers + + def rate(self, rating_groups, ranks=None, weights=None, min_delta=DELTA): + rating_groups, keys = self.validate_rating_groups(rating_groups) + weights = self.validate_weights(weights, rating_groups, keys) + group_size = len(rating_groups) + if ranks is None: + ranks = range(group_size) + elif len(ranks) != group_size: + raise ValueError('Wrong ranks') + # sort rating groups by rank + by_rank = lambda x: x[1][1] + sorting = sorted(enumerate(zip(rating_groups, ranks, weights)), + key=by_rank) + sorted_rating_groups, sorted_ranks, sorted_weights = [], [], [] + for x, (g, r, w) in sorting: + sorted_rating_groups.append(g) + sorted_ranks.append(r) + # make weights to be greater than 0 + sorted_weights.append(max(min_delta, w_) for w_ in w) + # build factor graph + args = (sorted_rating_groups, sorted_ranks, sorted_weights) + builders = self.factor_graph_builders(*args) + args = builders + (min_delta,) + layers = self.run_schedule(*args) + # make result + rating_layer, team_sizes = layers[0], _team_sizes(sorted_rating_groups) + transformed_groups = [] + for start, end in zip([0] + team_sizes[:-1], team_sizes): + group = [] + for f in rating_layer[start:end]: + group.append(Rating(float(f.var.mu), float(f.var.sigma))) + transformed_groups.append(tuple(group)) + by_hint = lambda x: x[0] + unsorting = sorted(zip((x for x, __ in sorting), transformed_groups), + key=by_hint) + if keys is None: + return [g for x, g in unsorting] + # restore the structure with input dictionary keys + return [dict(zip(keys[x], g)) for x, g in unsorting] + + def quality(self, rating_groups, weights=None): + rating_groups, keys = self.validate_rating_groups(rating_groups) + weights = self.validate_weights(weights, rating_groups, keys) + flatten_ratings = sum(map(tuple, rating_groups), ()) + flatten_weights = sum(map(tuple, weights), ()) + length = len(flatten_ratings) + # a vector of all of the skill means + mean_matrix = Matrix([[r.mu] for r in flatten_ratings]) + # a matrix whose diagonal values are the variances (sigma ** 2) of each + # of the players. + def variance_matrix(height, width): + variances = (r.sigma ** 2 for r in flatten_ratings) + for x, variance in enumerate(variances): + yield (x, x), variance + variance_matrix = Matrix(variance_matrix, length, length) + # the player-team assignment and comparison matrix + def rotated_a_matrix(set_height, set_width): + t = 0 + for r, (cur, _next) in enumerate(zip(rating_groups[:-1], + rating_groups[1:])): + for x in range(t, t + len(cur)): + yield (r, x), flatten_weights[x] + t += 1 + x += 1 + for x in range(x, x + len(_next)): + yield (r, x), -flatten_weights[x] + set_height(r + 1) + set_width(x + 1) + rotated_a_matrix = Matrix(rotated_a_matrix) + a_matrix = rotated_a_matrix.transpose() + # match quality further derivation + _ata = (self.beta ** 2) * rotated_a_matrix * a_matrix + _atsa = rotated_a_matrix * variance_matrix * a_matrix + start = mean_matrix.transpose() * a_matrix + middle = _ata + _atsa + end = rotated_a_matrix * mean_matrix + # make result + e_arg = (-0.5 * start * middle.inverse() * end).determinant() + s_arg = _ata.determinant() / middle.determinant() + return math.exp(e_arg) * math.sqrt(s_arg) + + def expose(self, rating): + k = self.mu / self.sigma + return rating.mu - k * rating.sigma + + def make_as_global(self): + return setup(env=self) + + def __repr__(self): + c = type(self) + if callable(self.draw_probability): + f = self.draw_probability + draw_probability = '.'.join([f.__module__, f.__name__]) + else: + draw_probability = '%.1f%%' % (self.draw_probability * 100) + if self.backend is None: + backend = '' + elif isinstance(self.backend, tuple): + backend = ', backend=...' + else: + backend = ', backend=%r' % self.backend + args = ('.'.join([c.__module__, c.__name__]), self.mu, self.sigma, + self.beta, self.tau, draw_probability, backend) + return ('%s(mu=%.3f, sigma=%.3f, beta=%.3f, tau=%.3f, ' + 'draw_probability=%s%s)' % args) + + +def rate_1vs1(rating1, rating2, drawn=False, min_delta=DELTA, env=None): + if env is None: + env = global_env() + ranks = [0, 0 if drawn else 1] + teams = env.rate([(rating1,), (rating2,)], ranks, min_delta=min_delta) + return teams[0][0], teams[1][0] + + +def quality_1vs1(rating1, rating2, env=None): + if env is None: + env = global_env() + return env.quality([(rating1,), (rating2,)]) + + +def global_env(): + try: + global_env.__trueskill__ + except AttributeError: + # setup the default environment + setup() + return global_env.__trueskill__ + + +def setup(mu=MU, sigma=SIGMA, beta=BETA, tau=TAU, + draw_probability=DRAW_PROBABILITY, backend=None, env=None): + if env is None: + env = TrueSkill(mu, sigma, beta, tau, draw_probability, backend) + global_env.__trueskill__ = env + return env + + +def rate(rating_groups, ranks=None, weights=None, min_delta=DELTA): + return global_env().rate(rating_groups, ranks, weights, min_delta) + + +def quality(rating_groups, weights=None): + return global_env().quality(rating_groups, weights) + + +def expose(rating): + return global_env().expose(rating) \ No newline at end of file diff --git a/analysis-master/build/lib/analysis/visualization.py b/analysis-master/build/lib/analysis/visualization.py new file mode 100644 index 00000000..72358662 --- /dev/null +++ b/analysis-master/build/lib/analysis/visualization.py @@ -0,0 +1,34 @@ +# Titan Robotics Team 2022: Visualization Module +# Written by Arthur Lu & Jacob Levine +# Notes: +# this should be imported as a python module using 'import visualization' +# this should be included in the local directory or environment variable +# fancy +# setup: + +__version__ = "1.0.0.000" + +#changelog should be viewed using print(analysis.__changelog__) +__changelog__ = """changelog: + 1.0.0.000: + - created visualization.py + - added graphloss() + - added imports +""" + +__author__ = ( + "Arthur Lu ," + "Jacob Levine ," + ) + +__all__ = [ + 'graphloss', + ] + +import matplotlib.pyplot as plt + +def graphloss(losses): + + x = range(0, len(losses)) + plt.plot(x, losses) + plt.show() \ No newline at end of file diff --git a/analysis-master/dist/analysis-1.0.0.10-py3-none-any.whl b/analysis-master/dist/analysis-1.0.0.10-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..a9401521bc24a7d3c97b652f8e3e6fa586d11beb GIT binary patch literal 20742 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 z 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 a_Ak{m)}tonHj$Chk=g~4)(#l_@%BIIzQM%+ literal 0 HcmV?d00001 diff --git a/analysis-master/dist/analysis-1.0.0.10.tar.gz b/analysis-master/dist/analysis-1.0.0.10.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..a970f1b5e6e730256b88c71d5c83aadbfed08b16 GIT binary patch literal 18950 zcmV(?K-a$?iwFo}VQhJGX>%d`82P8oXF$iz~P@*zB|9$JF-_al` z+wmmNkeRW7Mt5~}b#--hb#--|$Jt$#R>y;0AO0KkpM3Jce|`9!pP$oT__=@Sd2n*} z^yK_(aQbxkNq;anADn*@oPP2VeyggE%OLn5jWiqg2l>T~{{Qj2Z;rox`SlMUw*Sx0 z&f5Ba(C-hO{y*vWPd^Fz`~LsUe=m|cp2l^2{Bu%PX^~$9!`|TGgO~9lxdjD_F*pxA8m)rpZl`70YBAjPHUsX&vXm>q)Vy(|jJxiZXa}odmDo z>+>v2<9w1leDFVuMRL4^vKPU1T`#MPCr{>SeZ3m@CdJ}OjUXz7FzgS9PwEo?99MN2 z*U9|u;e+R^`no7D2(DAznzKY9J| z!K>u&tF%n2V}^1Od_Fqqomm(je^KN$WIld#w}i&k$+~_5UH5ic+~yA-e6s)j8~>W} zU#2|ypz{BI^ZyC{+0Xy~+WwECG*9a&>Mien)A?WZ|M2PQ*%?gy{lV$k)4_iJ{}=ba zeE5y~|7>`6ru4u5$tdCG zR+t3oVp)_m=zwt*#KDpkpasj_KCI`?& zRN;ADVgWmG+Lu9ZLghIuCW2X6EDV57$)Q!UOqjO7pOb5NBmEt@vkS~V6@-7KksCwP zY^>i(4;!oqVgpv#Q!M$m z!1gi-r_70$Z(#8U(k+c^l1S6UDb&JjDAs3bS=A(sG@3vfm;v)TC4q&6n#DID_dt?? zWPwgm>D3B)gBO)H0}dMuC1yDN`!@#e7amBWnosSpl&os znBZ0wfLg>$!O-zyJdH^tO|Fv^#w-ecUzH||tbnF-&;63t*ch5#2%<)dhv1x+{y^Ud zv!c9&S*i|_buwAi&KP*}!C}dSoimQBbP~aEXteq1 zPI#W|l*=BV6X?YvOQ$rP7YPi7N!64^Q3NtFiX2D-Pm_>3PwFzp0lS1jfaBy9w6R!x zT>vZ8+P*|BH$RCvrzo9j`krdu4J1Q=`6syuRylX1QCYvGG8##}U$`+Pn(=7nnyvCl zZBH?uHR$^`Df1*Fb?(P6o)d!Ky?kkx82B}pilxKrpI=b1modnizr=TmQ=boGEHgo} zbV1UL=_#pLxHwpECdsoF_!<|k2B<$_8I$C5(!aOEK5v2jHqXOOGZ`3lwj$BJh=EJj z*cVfnhcKxwlSGz5&}U6HC#`b|!ut*+Kh6b)YKovxv8`}AgLySg@@aNwgY)q^{F`E< zK_*_`!Q`}zOPEzbEvvR6=hH$AUA%PwvV3e}(pJ}LLn?6o(xmhTF5-_UN0W9sZ zgtRJ9M3B+rvW)L+Xuj49ST;7KjnD^sNCKyFFKP_p2`oqBiBZ$gvuHtHh9PHCxT!QU zLPj=DrUYImqj2OwOCW7v1E;$f9MWA9p847?Wz$5eO;$gH+KC1Ox8r^Ku93&A%p}7? zY<zsH}$Ez&6lX(*dppRQTU_J8DSyv_NNwTbs zfvfB3Hzd1})}ENkrLAwi`6?b`Y(3#Zp7gPDd>K zh>EIhw`n$=#O1VU$7w2g68HpIxrPZH#zk&C7h_NMOchYvI%?WnXkS`}Kv=WcE+Li(h%+wu+8nNY@B405)o-hlvfOmYiDiR>P7uYZ!dg}sVp zL}omNmR(}#m+(Tj6^09#h)7E0H7+7q)u}*$O-W?jC}4eJC;dLK>l%1TUpXse4^8Yo zGuhW3a#4{@+j345fNfhj*jj6IHa4`5-zKc1k=@DE+-4vqmvMdVYlw&WW1HaT4T3i; z0-R~EOD3LRX^+(KD3KS||?`og;Yx=>M8ERRWXWPtE*=z zTC{;Q1jJ|8x237!v$86y+n8HiTz%415g?^ti~cwtV$qqX&NqlBd56|$NPG_|8U4y|dlcaDvXJNMCIZyF4yU3ke>3$e#l7PqVn zDa{ty*+}pc%QwS#Si@6#*jumHJ~bn#V1iC)<3i^iG;(`cn!T3%fU_c=;siRWZkiuW zayX=T_~78+fSofW!@_J7GK>T5@$x5J)!@s#&`!jkA9O`V(;X)G(=Qo4{5f4zaW9#! zC|^g^LORJPxa5+DhyYNPDxYrfsj7q7hFtEK_Qm+PCox37G*S@b*Pvy)zDBN(}^0W;)`-&sHD%2 zDnv#MQB3S<^9M3U=}c^#&6g^znxrV4*k**!%3`FmuxUVMatuo?xN6@8sPB#Tw|Mw~ zjpn3ehd<*w_$z$u2;s0KQ|-eC(_|LNF&4@-p3Fq*TmegN^#$hQvx>nS?VSOx=;0Bbs7IG}DG$ zvZKDBRg}KrgY%UPXz-E#I^U!L6+X*H7j~Kxg7DY<60iA7yw+bVqD5@9jil8!5@uUf zZI|G82^Q0pOIB(oA{Izv8Qc)le3k@*qzqc*40jkJVNxVDrXM@J3fJ(_w8lDGS_8!VyDL=LRHIu~5J{ zipzPW_@}|-^e=Z0ZH$z25=u};j}KXBiy=_f7_VWhj}V6JT+v=N7QFa3iGclbx$fRw zapUaiFvQo$9vtZ`%wXiJFPHtRPVjj!)H(2{KAUvV&~!!^^yy8Eik&4E%o;k-&4X?* z#lZ)edV0ua7ztX>l{!TX0bZdIXh-s1Z6FGp>qPHZtJ&`D+wsc zs^r20^<|MKQs5e!!aTIP(gmy=Fo(eu>wHli`ttZo(WA1K|7}u~iwUw=+$jJVLPGC` zfx>mAJ08@oG(S|l3&@~(2Ik`n;K$%`FgDv)mv>fsxhrNg$%kub5Kyht$YD?>4vvBb zRGOoTB?yP*q#)^ulV(qvGkTL%d6PslWPPZo8~pEXaMy7G7%lAKCR9ERLj>BJWifhf zhn-$s(9G27QU`S`5Mqn)EBZtB1L%cDOXN(dNLS2TNJoZ^a2#S|C!G%bJH0O3AFQtK){6v+XdKPbsJlX;olwUHS{?fP#6 zZ1DPTLu~Q-Zzu4l*XwDJ`bp>!hD^HTq$@*=OL=GJ5@}afV*o8FxMWfWq{L|grxj5K zr!BJ-PRwb*hO~JS4!c~a*}u3AoV8BWO~+E051?;w?nygaAf?L$b?DwAew#${Eu?H+ zm5U905vBINraqHve<3Rnw-@2K${fFEP}34ur3D|7gt`0nzdW%6WRP&Ic0!lY~&mTpfS3z zM8_NqRoW`vaSQ6B3mvTVk1y!k1(0a1W#(rs3SF@9z#8rh@p=N3rRB1y%=dAXKm(_M zRyX)g)035{WQtoWPr||DLI3C|47I9cfkD00uBh|mWyf7?**TyezB@vI)oKw+ED(@L zk_a#uY>xC^bDN~z%c=2lQ)Hgj%6H7lm9mqCZul~b?~)RlEi4;7@i!EQ>qmiGe>pW1 z5i-odcoyoxL84Vr1M1#Jm2<$?b|J*(!LRih?`}r z@;3R7bkQAs>3fy?HOJ>!XP7ey~zsVI0t*^hd!2mwK5TKR~_fh(lVTJ`f| z*+boqgP>@dlq0H$+rt_c^n47>vR$0J-&UgrgRse~VUZ0Di%){i)_HOpMd2g^NHD8U zQ#M9+L4cR@q^>%?^&8~wm66yz*-*AiITuy3HBY&yHsmoe*7a6NHfuwg?6MUI7vRwZ z@@K$Xza~QI^0Y`Q8p2PoR}O_$MnJUcvGBpxZNg-S%Fvu6TNSa9a%;6nuzOa!i0kWK z^>(|pDR*QTfc2jJqfR(Pe8ORS?*MY|Tc<_e2=r|<*0fek zhA-*0X&Ua7g;v)pYJ|yGf7}8?S#teQ^yiImw9(fG2EOh9!?Fzfz(9r_z-Sw?4@Rs$ zZUZ9B&3+*AW2CPYjHq!S=?HA9CFjbsGWtT)QO<~VrzOoe(^kXP&Ho_ z%J|1XnI9aS^^3(#4ZQ7yjqKuTYr6ZR8uC@RD&9d5SVzUUf3kR-;2ei85D_UbNaho0 zaEbWg@)0OJhXDf=CZBX3Fb4oHUS;(G52Gn8HLn%XgGbVOel(o2%M|Wj4W^k-nb_oX1*8+g%2 zPD7JM>e(Wbe6*>go}D_iHOZiiNe%Bf=Thb{Cpt*j;#kV4MW3?N2ZPow%L#LtIwrhn zzOj5KwlSI(`-eD?4l)4%nuJRNI%;9!M4M0HD$JHdx$Tk0u!?mjQz3*PiM}u+AQZBy*@4;|B zj(G>RlT4&MVFX>&uAM;+qo)D2Q`OBVqeMp^*mJ3zFBF?W8ZsI#sfUucFrVVM1Bc_( zM5g9!d$MWa5P`n@qF&#LN1C+wAWWi8&4)H&jW?6T;;BVhv1zQHnbb>z)cnw-vi06j zkv4L%MeGm2#!WMa#lmK18f#eX8D=e8=PMi&u%h85+!hJBglVPJOb5%4s9F>Sofkrj zYI5BF%wF;R9z~Rw1Ccz@80pjdCSDOuUj8Li4d#btldX3b{w@OT{@n0E1e>zxtkAif z_Oo_l0rIpP4N(6@rH|+$)=qsxkXwy1#0n11^M za>p37`(l-4>AiVloaS+fUC{sc;FP~eN;UaJk^)lXf5#kCx^(uEwnQmF#T@yEIa zD-`@JUGvZ%#We+X4Lcx)-QcXA`PbNtX|KV=EV+rZ$liW+F-?TSy?9i3S{|93wtEx= zpT@9*s$f;yK;Cev|EP#>vBETvCO?Lj<9BVECEA(bIbFmUG-Pye3p{vWY>15Hc8D_L zi@9b2-OZ5TD*W1#C3nG#0_ptc+P~(l?p|5$sHOxvEW7Oe6zZ4$59-RG2Q7 zD~#?0m`utfuEg5U`ozd^nQ>9ncz?}O%&~N^Tvl~N8M{O zRx0qjZGE&H2i~{|vRPm)s$?&(n)2#*zhkqTd@}cJ{uScsog|Os7*VTy{qSO`$ysh* z(UjkZ{Msy{w(n})S4Q1uU+bgY|0A69-~0NXZTCN&4f_Li|IcuEj`#mOefo5N|If$x ziI55ligG7yk>Y%WaG8(lctwWlQ)~A$sfEKlu01*zja34r_afoI9vlUO^ON5B;QSe$ z*BPAl`+*6rvcTa$#upQ;4Q>?3(;LSG43Ejn3e+HzS@|N7`Yu#RcXfpww^h@&7D)`I zMq}JINO$#e>cbt6mB2q9RHrVQQ$}&xaSs*pBA%~ivxtSe(5GmDBVZ?|eR*mH2KJe~ z_9J{W$xBIy#`kGhPTh0{3jg{}oe_2*ycqJUFBL8Q#L&L#^t3E)725y-hR7=R2RZ{Z z?0BhSpTIFm6X8KE5VK#32N7JD-W)e=ogYu4gli9f>BBolZsSCzs0Pcgy~RX^E3;xc zr$$Y`34KWWdx1;j$?eZY7H)4VaD)rT>a33M1gqI!189%#vrxS@Iu3h|KHqe_K=Js? z>lN3=n?TJjf~WP$8>+>Ky-WmX9v z6eSU6r%fC^9<|T`qa!n#J}MYvM)cvXT#G$vF>Y#;5|m+zPr=C0+r9ZCmID;e)o&Yy zJV|hM@T@zD%onoSUnajt}pH(|KE z_yo{+?8|qg;c*{APK4?pfdMj)2Rql^7z^QM3V86K)uBl0(i^bTb2*}UVvgrmUlP%b!N(72tNt}jr%_(ibYvr` zlUCKw(m3{4aQ|NK|F!O2`R&&K!+!t##JT_ZYsE`m z_N=DyvA(i`?lGVXgXuLC!8>pcEAm9#8@pt?;Kti~`+P~wJ6_&v47eTc@ihbBZV9k& zUSp)-*yXpz-fvuT^PF!`M4POA?;61Fn&Ha3jSGj2^1@Xi&Va+%_k=kK?;M%Lt16M4 z6)&L{00<0%SIihK!#f=4zC-MFaZE@sN;=~Z`m;bdD>x0ZVkL_p;V?aBY_vA6&+Tq( zmEcRRLKt;T(#ILbhP-RzF(c-+4r<;Zm^1_xqi&8&yhFg@-69yb1}5g4FUU7W#sx zXZYsJH^@&qs4+QWa+-+VD&x$eLJ5H_REkp`D40Etqge+UlgIWrq9dlDr;qXKu}UHr+{9(oFoa5AObFbg31!}{ybrsI zU=Emy?MBfED_*~XMu-@o2JZmFX!50rVpr90WwhCc=Lc1MD_Z}|-T?pp+kJEQL`Tv z`%&>BM+FlPw`M-bkT7-S{gBuXi9ha;Ks);f84}i_^8NH`IzX};=ZkYJjRC+Q=wBnc z|7yXDY^I^T@D5#&yA3HS`$y2woz@Z=H&8L11tRLxDCl2!&ye*SES8ERygg<6P*i

u#pYqEHC8I(O(ZwWUqNQ32w%I<3n`qn36VJK*B322ZB^$i>#G+%okD zp1nyXfak46W?{Bawyq$2o90vV(uzs37^k`96@KH0rXc|YF260={DuJ$vv@)$gk^Li zBWSt+fwvfk0;&`k{VNR6911qWN6zcsu%R|8g>gp0*;Lx0A71@*GzwCi)ozK=27X#Y zkzKk(PzaG=%VL#J(Lh{P zdP)4^^;h3R0tN?HJ}cE|&`19~@*<~@&*)~}BRPq;fV}$% z-Y{PG<4v-{Zd|Y*Wq;IBws)TS|F{27jgBGW_MYF+|EGW6KN~dse;{e^|MM^Q|9SEK z`}z8?*Nygl;Z1Y&w?TIuj(`BLERx6`zwMa>TCy2!!$;ElJmOW9u~F5aSefwo#DK6aGeN4apdW{A~g$ zz)!OnLwQ4fAT1K}unH#evIa$@+UP2e%=WAZ8?0qjT^5qPRi# zp159SMV+N%(R;p3FncYpY2NABFnyPW=Sj_aS0x|tDqf7P!gs4qg)dLCfQ5gZ;A)l} zb12%m3ryAQ+&4b-`S-|M+_B@#>zK^~{l?|#=y3rpy~VS-cp*%lqaTjW!$Fi%@>f&0 zkq4qvJt$Wx!eoyn?7^%kmK*Le7wuGTLFmi${N>Bn;#y8znkra3UtG>kKiTTfH4J%j z4(c9kbRufxYjF@F+G;nTq}KO)bB|l^-0{XeQ>=AS(PBmpiGOY*s=_-mPr}DOoR=;(^EOU9@>^!h;PX;p~*YQ7;DjG z0&@_9pfb{$=1cz2-ULz7ys>zPR~A|jHMxpL|&jmQLMM0Tr7Wue>a$+fyPTixc%K{PsMFb7-;Wpqb_ zQE5+n>B$a|%U-(s0+uYbK1oupa(JCiv-#}ItczR!8suQ)-dVShAT#ZAFau%M9*p# zK14hXOOdjrtRS3I%Ic6OM&~sT4#~|Y6j6=tk+C(XD%1n3YtV)y%@35g)5=0ffQ-m0 zhJ-U^n3RSFNsZv}!grU4fbg(wI`VFI;Z+<181YzaNC0mzm_{zu0*rm4hLfAi;1eNA z_{E&|7#76&YTxCRhDpt%XvcE{aSoxhB^jFw|O0hLNGXRl1hBNO-^`Qt3}Uv>hlg3k>o^ z%33%0HC_54yiM*ZV-1McfIWPGH%tq~4~u|$HpX*EBF{^DefU6}w)vJ)zrvd@MIp|B z%Vd~iy0o|44M^$fisk>B1bLccG%flN9>U9^;g2mZ%?OL}FQ7Hc#l)ivjH=6#dAp=- zra9UL61rCxUgaH!;@TvPZwzN2rLOMn!Sd+f_P zEw7`+NNp^;=5mlatCNC>jQT`Lhi1W8OltG29RUCcBsf_e3Ud07)%qgKD1m zR=_&cccMO0VSvSLt^qz%Oj7`xSw25_DBK7D0ze*fCOR&zke7*8d=P<`8brW+0^A7x z-?6d4Icb{S+y|3mA124|fk_k*22h2853XczsrVyXwTCv^$=};Cc6uAQTjFc?y!v49 zldxmdyFrJ+`zHZo;etqZ2Qg}aG2b1H&)Y!kj>hM0Xq3sa^q6%-@xzxPh`fJX^iF2~ zltPc+I)}K$3d185Rdn@1o!DkWsshbk>t;QajA6bG{|krOB+mZvkKkqS&wqx2td;-% zZ5V8;(#8G1eOmpu!{Ae{L(e}i__kshnWIJ0SLLJ|T$^F}Z_}v=L+VI*d9FHyGVabb zL&EWe@c!{n`>Tk3e|arp+fx-+jcEcW5YFNe2<>V3z zT+u~cPN+7a4XJ5(mx=nhK5dWvzW|Ly@?}hJvPnrF54Q(1IlR42C)aXQBf-tUdWFWf zNs-sWoU#j;Nl}zjbRA9j1V2vw?v!pZB2LCwQAm_)FahV4+6(R>a;bZ$Gd?O|iott? z>n_bx96}ZcJljrJ+oSrGA5YQiZ-Ew(I-Qt}hPCCx z2kQ&7?4>iG z5vlcNL;HMH7Pp?_tyL-8baC79cko2lx^Y?p2+AkBob=`}Ugd1kH^-UJ5xucsvjz(7 zz5pi3%J^4GKXZ`q?j9>CjcrPA%R3tuH$p3DQSVSh(5DR$cpl#Z0M8GYIv?Hey)3Gv zQP7=XNQ0A!>|kzB^Q=CZn$s?QxigpH%#VjCt^_WZ<<;fns_6$0UCM0pAWkPssNJ6aM-QhPT2=gyk#}Nga?B5Tb{ABC zUx8MF78sC(AS!bdmy;FwPsApQru3{AXc@hs8_Je4F&N6HH#LQd4BrUhu^G-64pN`^iv@aE{t&A|b7} zK+=@BTwmeF_DsN>U_xU=lsDpY{|f$RvOijo=W(6Qxh%sMc#4w_k;66Nx83PWZLWiF2aP;8wf^H1Pg1^2Gfvr6YVNB5pk(U^4JaQ$grx4(;dTcJe{_i7T;wQgf@+EID~AFlppwQN0s7*P^l|) zM8uWt;YVaRhksaPNo)PR^hY1dY}q@IoWsQb4{6r*F8G>s`%64+kZWUi8olzbAuyUa z1d&0g9|_>Z{M4gC|?@t|+&uC%Va!zE=~BnB%xd2ueG@u+k{F>`hogHC600OI0t z22XaNZas=nli)_e?Q?U3A>q<}es72e zwK^2iyeAUFe($r-hQrTPp8nIP&oH*dao~-yz@u&GjONf?|*iBIvAdwoA(VIhilxr9})`ih{c*bwMOC^v?s;tcx^e!3C^(?Zn>Pb zF`LMao5Ft9G=eiAm^Hax^yL=hz_(M6+tk7v!RS^BWG~@k7q2@O;s9MDEhs8L|BCl; zz#32HM{Xf?iu?0dW)J}jms}QMe}%VSaW&Z+o*~_bk}*O$>C+#coIR5%x+(qM$@$a% zXM@kqG{^KmJ3D{&bf9tr4-TH44WB*hpEUt6km32WXJ^m)=c)*>!O7{cfAZNgjm6Vv z&rS!Y&(8fo=rm2g_iQ*EoNDBu>hu1y^Wpiqo!bhjuU^!HAoZ|^r=XCT)-ZPa%txg< zWioB=X0_}+6`e_(dkmRrfcbizdWUyxZJvcB;dC7+R%PUUINnTznuh5cFNC zfc5r>1oX7jPqKTP3je32$ul@Z(h0$YjINTuB>O4PY{`L@3gaacQ13y`yV9pe6#N`i zBEe5xN#LuE6pn<$Bq^K{qG;z(?W zdArK#$@GHXbYhFl3`teRbJ_wn6>!!{C4Aq(H0#Pd8A>Y7%nGdgtN30X%+YYW>zbZ+ zkb{!&ug|lK;Mitiec_MCl`N82ko0T#li5ZqoqdGfb1ebJdLDpxp^ho$Se`vQ}YP<64y!LA8fQYjdKlvIckz^uyHv@p|EMu+7u6R+1mBQDiNEq3NIKJhlkQ7 z#Qs9YM%Kg*E6<#B_$OF}!v82@%cpq6KhOEf=ufN9aSlP`S<_-c`8AP%#N-Cy*i|tG znxRWEoF6fU$Y3vwAQ@*G_0A$PWE)1nki@wFP0o7jTnQ8$?0K`YXU z?NiUA!GPJAFE0VYRpa*0ICCBQc&6k!@B|n?ZDkbUQ*X>OvVxxSgdfUSl@dHHv73Tb z@uvboF0FoVR@py2k5Fg%t)-&Avf?f1y|AX3?%n}-93qmvuu9}3AH8UHgi zjhGIk`eY^}jTf6^=B`Hev1;QHUO_H0co;JCEgDRAd~^|fnatuTiH!q$;c>wYxII%!XQ}&X;Q^s{LU&Upd*9o3; z8e^#V^RrLs7S0JB1P9@RQVSsd<*PRckO4ozBcvuwvGQVr4CH?E{3j#xpx?K%LpPHI zjK^t~)_3yA`5e~KQ25JN&;J_z`09thJpaqL-+%k&{{u+90Yi9Bf#pb&O|Fy4Tf7c4 zb)b|<1(hJ2uf8XoDRkaI?@y7oOsr<$5E{JK4LGn>lHXWnI+%$d$#dc=A$i8vEJpAW zIy-T=jh5fwW`bD_E`p4OEuQ)k8OI44QgJ`ihc%ZD-4=XktPv61>SqpH+5wmT>v@6H?L%xw-;RK;XY@{qE1Xz?IFUmg#x z)IN7+evtJ^KNgD4W`KyAzhW{AJo*prT76QC-`z(tGfL|JF?%)oBv*gviC5I*{sNyf(Kj?dbP zp%hIqVxFP=+HIHDiKE zo^{!jE-guDUy)^aTg;HA5^7EnqXyb;9a2zA;8;Y3gmafB%P1LJsJyx!53Iht{ZM^r zthW$i6PCU7!V^B>4Jch}+xei6hZoU*)bDm+oNQ)~8o#n-ot))n{^58+xXn@tuiw(f zrhB@DD4=om_l;z)8{Qg&4hmy=BxNb_9h)iRjD?@1cQ#r(6|hM>#(*_)nVEgrs-B3{Z)JwVbiJV$us+BqnM20QplF3*qt4a{3q~Gwewxx+ z0%R!EWNt|4Y;KQQeRB*O3oTDkq_15<)wwn1gWYo&-0 zTlj>elXvp@iu*J@k-tTAlV5=g!a*13cpB||hGpI`eO$G#kQH9O5h6ZD_^oSHstWmd zecjat7`-vLQHn}sz{k#_F4^&IkwYwg*VS(1ai9csbbA0u_jn3s$CGV$EhpR5Ie(LK z9G(Qoa)-y;J?Gj)W|NE9DjLysAQA4pOq0?(X;P5Ux0UK0v#ql%#v5+Lc(24+J(@jM zwDDwjN;j~sB$K6ew>za}jZQfcF%22gL7?MKYDU(!(fCNLlzh%+qKxoHyHpOqoyMs` zv@#l9woJ;|I}{@$-;QN<0~-)f?Yb8PH0m~>NXuutozx^^7T>`lK{Ar5ht4=vP70JU z^u}sY)Ha72Zs!{P&~=&4H}>w*1QZL??W_q~yFqt+*itX-hO6u_FSe>T+wp9;X!(G5 z4J(M_OQw<5{L_v(=IPp;=G@X?F=0!v63i5Q?u{x-L$r=dig2Or*;E4f?CM@V6%vpq zUKbl`oEkjPC)cV!#h6gfmjwO-AYHXNUr-2ROHOSp#67BglPqF(U0e)TiI&c!p}bRP z%0chxOeGK6dCt+wR`Ap3$}zDkwh36Lu)A6Q&VSsu_n6sp-98Au!(7)Fax@2Lt#2@QIz!${D=PlbpN3XI!4mD2m!zjpo40)scHXIMAu2}9K|Kf~5MU@Ne#TwL zD>{LfQcTV?`5%5F*xnkpsYD*rrtsw+Ae0Gx2EmP9`ugq$$dw@2Zc6c&m$i2 ztR+-UBT!RA=r-ozu78sAAnKK$-KNa340n(mRg>!kcWHzkyc1R}bn@fcg4$*n8sRPm zlj9>zBXT5gt@rY)_c(pSlBBcC@PzHb-nr+TC6tonp;Y`_fy%{bfkAgp(ZZOEbXXx} z#(*&@L0tJD^pbT=+voj=|&N5<@1qty1VQVwawN-!>X{WsA-HVTJFp z*v{l3rx1ms^|cwPOCFJQ<3xC5(axQ1d*onj4Ot>q@Cc@~M??7kiEou5QPMo>l5s~~ z-$p21fk`9-I9-~C3q7YoC#Zt4{u%T=fdU1vi82MYzg=G`)O?7Xl$0u+S>XEgy0e+c!2J`8D_2)c*dMv z{~ElmrV2F?cnC0tDdDYsMkE*)^>x7Kr#CP>;oY92(F>wmox0e2ZV{uSc`4oL##uah z+mPl;;5ib~x3bXOKz1Z??5&04(ed5dGFCOUSK%qigSC~1F8G+yh&pf=VS*JJe(eTML_i2+L{G^y)N5J8Zq#CS?QEJkf#xHD zLdUKznMMv=l}g~nn_=&#U7xP+C{8%bY`Y`7QCK z-1k4#j{?VWN-7+CuVY0N9rJ6GzD`-`T$wo}bm&Ax_UYh=IL1LTBHQ`etD>wpnaAu9 zGR`rwk9Cl7_}uUJ-uoZipWc7O>-~6cesR2C$zs4B&wRA!AL*s|#1R+yX(Ma8B*>xU zA@kjnoD%Da+w4}`t`a_Meayklq3`Bp7rCEVFG@&hif%J=6Ri*CgM8ej7EPbDJez#; zTh)~qhX;Fg(k_J|b72`y6C*ediV|cnDpP{aJcDHyR%~bx5P5)wL|1El$drd3LoqhN zx8fvfJ3fjQ!QA2p?~Y?`A?n$c+%C_%m?1u={o)zaZGsPuF^fs%`?RQJvLAvD_2y2r z43)DedLdyM+1|6o2}bdz@Y&cF%Le{_!%F@p_j@^Z=EqNdSW(Hg%9G8_^_5zLvnsh! z^gxM-dAVQQjnBbTAe)4C3!^%o`|6{5uezY)kG{up({Kvn2mFkQw|Dyu;yfirs6+e z1JB4Op%|ml%T`d&E@ls;LpSoAt=x#>dPC%__h`4`+zUK1`*k1;$w@vM<~vma9E!%> zv}G}9N0%bEFK;*rZ|C7ShDwF!BgPu?#DXr(AF%75rCTSfYvu2S5n=C$cD~QdH0|5l zVDBr|6D>-ky*pKVQ6R3wtBssdJ?? z{d~}g7Jb?YI=V&aikbp7EqJX61tuR=HILY0Ds!rptUS8>+cL_M2RD}1R?Y5+c3#|~ z^3!fY9;EU9#m`&57tLO^+6*&C9t}^TK#5t6;_~Jd^VSc~HBA4rPSj5q+C{rFI+H3nbVL~&y`EOaFm z5!*HfYC&V%A=}-P%3{d=d~GF+@a}LHVY%6|pf%;CGgu#sPip9|SWr}52qHr9THt=m zP|PGgcfOY2;Mj2EW*gbF%P6q$(NF7Dj95&JNR^=K->(WPgkhCOsl{o_$JMN*SYNR= z^KlM%`%*F@z>3>EwACN8q~xJ`sc^aosTC!Y$hIRbE;KJUghIt6Sl!CC$+cPIOy#QN zTc&#WSb@HM)58&7^juvotag>~BXA!`vS+dAklfou_Igd@_G914RPFWN>&L`gGwE!+ zA5<`V9Y%GOzn0i#rT0R3S?5~t&5Lbpi#ampJjxF~CjYwiz9x;e_|sz{J@<~}<;Rtr z0@}BdZUDt;hP<&n#i9js!64FLko6x*<6+;vC;JbSYL^U%syeBRV`!woL zyL{X%5AgFX6weo)Fpc0S$k|Cf-6B&3mVEq2*fGL@)$!qs{u@g0YN6a{7+z}El{`DG9`~2ohx!kg!4Y>D;!|;iOwQ<-#hG1FZXxAJO=*3styW^TRQ%{dYOV00Zz@ z#`$ieo~JIop}NDY)JV705+2F;prCPuZgM0EsAc^xI4U8UuT0X;+Mn^mYYT7RITzLs zVJVd*mxZQ$y$4wAG?+*qWTs}sqL0-}>|L8O!v_rEtpr4tf&6_K?_3IpLXp-|csKLj z8e`|%c8VfR=Gqc7%RkJ+CCDa`Tl!*81e4!e1ukQ;DDP%zI_7+ugxklmkqon>SI+=7 zpW7vwa_^-iJ%B6M%K9AL`;yEj*XGWDSz+3VwH;=>A}L*Ep*gH~g3l1IAIn8ja84?4 z)GVJsk!S`=oW7bKFP?RzT_CLN>HK^xzhn2_U(!VqeJga|mi{P_WCsD0tQ`M z7b-eRe8s>(KhLZ&WCJ9wA0%`m1#4K>LAbb9?v@(E;Z)6!73A+$u&s$Q7J)Y9%KiaK zQ*l+wzBga*NONNo{xL|+;{ua2s}^ISB@Zr_{W8PxV0Q>|1M#jG8L9ZY1PSO zbGq_(HY>0aQ+WRcO{DvH>+$a~BAMXigDEu{v%(tBhDb9QGMDKg~wg zj}yvQZRW4iJAFOYOwRu2ZpHn;U|JshN^ni`13l;B#q4Qg`?#u*v!}(lGR55WM?&tJ z#1>k{p>zToJfOdLc#&^d93ZrtpsNAY8}iFz@(?i9)h5q|#vZkyLzV^sgdF~42T*<) zbRm!)KEH2}$I8A#Ztz5zr|x4E;0D9djV(2Y4WhtSIrXU+fQisK8?yX;4BVyyr^B;J zXmOxfD!YFPT#-nnwIKmLt(hSJyc~G>U;0M!=>6@RVnatgHV~G>giTA4oqgO%?e3P^ z8JRG%(7J%$-Yfk9#GK+a&vM_h9V`H@^ly)KUWCATg>shoS@r$j;_xD1{XA8#PL*E5 zd792z)ZfXlMt6h4e0qJL2mpKUyR8U>-^Tc>G!+OjEaphz(&$WTN_qz#i_cdib+vKy z5D8u8sNAkQ#~y6QyR0W_@$3!(uQr}?Q9%jpKM$haHcMx%M;e=HUFlJ#4JLMZQ>}mU z%=YC=bc9!ZPLn29n0oZIG>o`;j=X*1=1;gjfKR69d3(rO(yn8Rf*-malznsF$V!OB zD26_%JB$4ZltI(8T-gIAbaf!v4jiAha(Xv*w|PS)SC>S;-xdB+vLPn@yY2KDFa;d^ TzeDcb0vMeIoNF0yj12zfuq^m3+qP}nwr$(CZQC~YvTfV8t-bdA=V9iax%JS|(Gl5CU0qq3r6>ae ziV6S#AOYE}VT%840KosV{1^XoYGiL@>*ZqQ!eC%vWpCwbU_kHa1p-j~|1cWpv5F+q zk!TK>06>`e|AqN~!T(`yd2JH5+1vJEUIZK~2JpDtbhnpZm^^wdbL?SuST~F5x?n(~ z1Z7$!uzIDXS&o0deBcd;siyKvH+Mn1mx)Opojm6by;8ChCK$vdY@SqF?7E0iPB6r2 zn)U0~Gfs52l%Cw=rb8$}y|zyLCi#C3NS-|OUGZur-vs;4cGc!55%@j{o&s2H+D;(c zRaTrgTFOn1kP8kfx`7dosxPN=ZLz4T+Ya%jq0mB;-xl=P*s4yTOEJWHDbB4Si@g6n zLkYU6zi|PmtuKsAZJD)`dk$!?vHc0*C~EttJXJJm?6kBqKZsEa(G&q@eF!V5u(fHiO1=r!A(XrJL+KEyjN?4!`vs zA)nj+3idH~)`C=-FIgN^G+1>>7Io=8h~p9}!^f05V5lS8`K$rCQ4Y-n zkV#NUP^W6kys!a!;4kS!WX+!Pfn7WYY6wF{m)qGB*+=vf{_f!ReeVU})GsbdrFyJ? z%Yi%SlFyHNtr3P{Y3;zycoV9*3_`P19#wTY@cP~P>y%lAYdt{KLg!QYa*Z6MbY0_i zD)?9B)PhYBkB9K|B+9|tM>B%P*JtX-YWNd&!wq`38vMew;eU!PCq6gg9K5e8KgQxxJ<8I!d_@m z#&cq74lbKPYxLHXbb5=yQYa%4k0zRqi_$a~Sy3ezM_N51I3i|i35S9F;4sh_upHxU zF@$a+X8qPYhQRA2fVJ5a6!wX+PO6xPU}QWZyB`F*HnVylo3+jfttSnT&H2HCu46Ai z5zX$8;Ieg&idAwmje6i*u}Bo%2@+AL~APaofaLOUjC6{>+r!} z?x8!)HIE?ppQm<*f9_C-hJTfNB3;U zY&2$>AIHZHWWfsge9soOM@cb?Ylr6s1yfe@lpEO&7eQdxql{x*%xl>pWt&qJK(qp1z!WE9ikOTrt`-LxFzV;0gAf=gZXfM}#e?MfcmrI2QbRPt z8f9~Z>CwYDnSM)wslPeLOs(rANNNhl+Ob|C!t{CWS@xkN-l~i-y@mC|KB1{YyWhbZ z=Q)Dxq1D(t{F>Z|W9p@xC1F|67Z6iYDkYvkR!!gfkp{nAfeYiLbm7O2EYNtkVyaug z>GF;zBYstx$g{wV`eXanx;y|+y|!;knqp;I5dPqd;VYoZW66`1(7;Hju2Wom9}C7S zHk$nG%-BhIebT|D)q1#$g;=GXtS;)<5sA|2LZ`a$2_fQPi7c{g)8J_VB~Gf+G(ukk z>Vxi7juRfko@DF4v;`F8woh+ZL-Mqup*RFF9(hc6#`HJ?%8Ie9W}gR`GZT&};vFGn zFfoY&>B2ZzGiLcBE%9$=UW_JM07h~;q(-D~%oDX6dK0^I%DcunXVlo&x@ak7$2Ps{ z+F%;?X(dB*PlQA7NyRkIu{Qwdu<_x%FKS+t4p@i1P|$#ksoZF=Rl(TJLSj=6Ae!{& z)LWi+u1*UexJC(*rcYhVOUge295dIqB1k%I^lmx3^1qmyT6cv`b^h_qW= zF=`qxy~5LomWn=(x+MBZ`VAVUT+1$b*2BHZxOW-E?4KNy-nLyl!!q^kglB;9xW%xhtK?vn5xyxPmQvqF&Ko!5o}V z8TIiBswJ$<6sE%_V7TnM+Pc%Qf;K6t1p_!5Phg1dW^j)ve-nx||^KbW` zAyG2n@U~Ay&b%5^J~5FCtlT2ZZy)UvcH@cLigK6%5a$De)(D)mmii~E79VD^dTM@>#M^$R8gyJt!$t*OG@ zc85fZAzTJ5)#0J)#69e0llDUC<~yKoh(ktOK_vNj@boI$W3AR7tm}@j^`<&{-9VCL z_2N6mDAl5P07$w_ijzqYT^T3bJxxH}LLlXuPcwo);}A-~yzb+x8ok|=ueIqMpv~Y^ zaaG%(IcXtYp9QUCvMU9r^L9YCt+hKE2^q=%isk1SX;=ach>cRa2M$6E#9Z5;EFPIO zQ3fccG5Ppn><08@o;;eQo>&JgwM=U{`UknT8{!A$6@~3W^wSheiiQFlY_TiZMq&x? zQ=A1-Cys0+k~+afEDv^>Sw=|Xv;N}jf*-k4(kkH19|5wdd!t?3&)(3ar-?S)J5gGb-L%pxC2*)u z;4h~GRmlXlOUEwg;F_Ho=aRL;?yL9%Yx_b4BHq$WT!La~B@&MOr5Yv)I4iWG2Ht-6 zHE_j0FO|a%);|&-Fog`7L4q8P()gp;vlC7+qmp&j~Kc!?#C_EHjsv zvWsV47ik`ReWr9Spr;mF+6Q04mYt9MsH?cxs4xpuh-Hc-aO0sbG?MTINa!WQ9Q65A zpLtS%VERk1(>Fo}bH#N^GvbcYnWRyt-JF`H%^#NC(D;pw=IEfoZcd<&ZdygM(3}|& z7b9i$>hJ9Cjt;>R4+yb%IWooS$B9dbX_u#<1Wt#aT?n!`vD~?CA~hZjBh1ast&|~< zG#~5DHaui&6U<;(mgNM{wcqTJJ91~ThimQV*=x9PLXa@e)pD>wYOGCcp(A3e7-pM@#v+z)!i20s+Yn)odIZ181UAm>nC1=<~B0dyuEvMNxuqW|$Vv3a5P(>dXBT|_m> z?G{r$jg+zPnDK$r(h__FTCf0sPe@-yW?rCbE3Cpt-VAQumQCWhQLGy z(YmZTicRGqrPu)9o~r?UoJ1zdwlVLZWY0+%lhI&g{2yRks-OM=(fE>$QuQJ7v!gbu zMOC?H$ktk;Zq&B1A@9Df9$%y|&d9eBZ*NW98bkQV*aTffKx`|F#f+{Q;%KSYI7wwd z=i;E)zDf;CuUtIP(u%j4f6C5P_Eh3L5XPf1`iKSYe2i*35RvLO`;gy0G`Q(`;7u;? zV`uFUZTfN1G{xlA@#@oH2q{)DB?78=?XPi*LjJ6=P?-R<`{g7EDD@XL(*_~qu4y8s zAd%IXzm8W3gkVV?x25xY%XX&27=FA5%mnT@20?zMRmqzYs$X zKTTSEp0z-YmiaPS?F8O5~t!NRs@ zR7Aajco3$%lt1#I#q!I@r{#}@vi=an>;^NZei5^quOeJW#|iU|25oieE-#ysYE-*x6ziBx5PcE z7sn=z12tC!x_8g#&+4T_@aWZ3c?zi&Qrdjp|E^&*3O6%A^~!Wv^DL8ABA2KH7a=Hj z{ZdMfqDMa-#!Smp7R#nv^;9p)_q{6G^<(o5G=DYpBw8GXh#=5BVxMQpAYo2(gYJ!= z8p7oh=jb|SR<|*~WXd+Fx|0M^TAt09ewR$;YLr!n0|0ju$}N| z6|IlT;Z4&RaWaUNteEhr z%m``rhIGW&=e5EL;^bLHoCXBj{0R(s z7D+%}I&jEG3G1l2=d1zk0{&oW;BFxu=Paq;K)XCCQI7x5Ft0{N(-XgK>ecxdiNrsc zdwo7IY;e*wljFj6x9po8 SC5o|Df~Wy~-+JsXFvGA! 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 Lk)@Vo@cZsRs#&%h literal 0 HcmV?d00001 diff --git a/analysis-master/dist/analysis-1.0.0.11.tar.gz b/analysis-master/dist/analysis-1.0.0.11.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..2e9aa30eeabf42fb316d8dbb5b93d9b1f72dd957 GIT binary patch literal 19444 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

3a7Qq& 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 LZ?kZD0Js4F(KkD> literal 0 HcmV?d00001 diff --git a/analysis-master/dist/analysis-1.0.0.12-py3-none-any.whl b/analysis-master/dist/analysis-1.0.0.12-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..60e0b51c7e0824323d9fea32c844cadcaeb7528a GIT binary patch literal 32026 zcmZ6xQ;;S~w5?mV`Il{W*>-i=wr$(CZQHhO+cvv!)_%D6>^SowBO@c`Tjm@iV|?<` zpkQb~KtNDHnav^c|80Ok{%85G{^!)d*1+1s$-;?2PtU^E!dXv`-rfTgNdEutkt)xX z*UAin3nc&o+Kc&rdj7xW|9WnCt>TVG6ZYWW`R_;j;Z3a2C9htL=(&b<`Td<-jn?@n z`VD28$5V&#B8xYUr_B*R?$lJi$+HqoU7H#btU;ozUDec7)Yh6NJ_tXl>@={xe1H~)~QbwGDxZ7iqIFDsjQ-ZeZTRA|7;%HOih{lg!h_n>a2$KF&75ythTZwp6OI^e}gXBWY z(6(?=TJeg!)HDTr`r`;@oq?ePq5p(}|4?48s4Akdd*57>DXh$j%wYFeO8wStU4*lG zY)u!j*pG(7EnqzpFkWf<#^@OS7pngf*L>`mfUpSdEqECKIBd)+6KgwYnp= zG6sKkvzxlEaOC>o2nxGBob7LO_dr2ln-09U=Wh>b$3cvLt|UrLVbq85Qyjzn z0i;5w(Mc-i%4)$o`B|HP)Un3Su?db9{!HR~r67cOR_)&eS@lJfbtOikcEF%VbMy8t$(qG-;F+1fWZia>N^AmW?lz#J)D|p9_-;*ZVNXVr!Y&e*Uwi#()h!i z`__J_2LKMOrxJ9d#zTRy7D_pPJ9h-%uLa+$s^ylYc?u8Qo% zHY+yjs+%&NL;InpP{;Wyvt-SBDhx=VvYtCi%9oo=O&BYEJfPEj2;j_*_J2K=OI3xx+ldRdUAPwqo^gS^e z2Fsm;$45?m-#6BuGglWV&AI~1=c2j=6q&VRFIHw=3>r$ENpyeWl&8kO^9~mLjGl_|Z?$0=3}lZTg(g zGC*D=NPNoA(wA;uPE~Z{zSdqFDXekh6mPQC*BAKY zpS<75K@z{-*s0=<9(LYpS&PRw6|hYyf`$+G6_Ta>c#G6?DiflKr5)5N)ogJS;DrLD z=K7B{svjxfn3zzL{W#s5aBX|Xy|?sc=H5XLLaH^5>oYUC8f*dQiGz|It8PI3teOmw z{HRBeWH40rfZR?*dN-*$CXcs8eh

x#v7H(S=Q=4L*Ouq%iyj9OET3NC4 zi1S*5#k_z@2OtVwJeA^=(k21dQ3SS7NY=KWnpS+?2-Z~?1kTnL^NuIi)r)h#q}Tg7 zg)ZR#0lPUenxXi3#Qdk6BsIuq!BN?7-@yM_+5*mw-Z<|WH|3-YZQ-r-j6HjR{;am1 z!SpGFAD!kBPs@pk{anwicqO?__qg|41MWKRLB+F&kGpEE%%Lu||A4%_r&`)S)N9s@Wr zp4-nHClseORL1|`F=T$jrk_#(WwYD@=r}tkrFZeRPqDS^%5!N3WT^*00vh-lu@59n zgua-0WBx5EX+bu#Cvn(c4D@jPV0AVI{NcmDZ>^ikL-1hlO|Fj+jL7z0Jh)p?o%clN z=lzKp`!zeD_9GF`-L4mDlq1x;hKg&NIzDl-B<#f@)te1u?~u3*_;v~kyzq!l^sdan zj|=2qC+*QhJr>#$JV8OB4M|i@ko%E3VF5^Eo480M4L}7ySBJmH=~z7ORs@!yn?N)<|aGq_S>t zVF}qlj0rd8qX|E7u)8B<|4|ADPQYVc$=&f^>LKi9=UB3~In;@C_eH0F6aO?T%P_{< zmamKIp`@A|zgYC0D~eh{#r?af?M3A0HJ0jw5a~pE0#A&DccFOi+ejrUwMCmKqBN)CISQ}5b|4|+sb%sup zP(IN6q9b-{I=H=SOBqwCY9u6`(=9t5gfAKK{sAUMG_eUjTeFye0oxX7j{)w@B8 z8{B)r*gJFydy?o}QpD*N*hsCgr~iC+3S)!?WwBY>O30Kl;29V>uf)+h{>Vk;z+O0Y z6IROH4{G?FtYqnD>Io0NIl8#$^&2DxPr|bO0GY$xbODy-Og4!TByn*GC9jWF5sd?CEqiEuhxw!J15T`Q zH^H|)03`Rt>NK*p=P0RSY{biqQ2$LEHof|pD6@j(I#UuS=0UOMwB?^!tvy_*aC zEAk`a%9X&E0XaCCAj@l~GufgCwDK5ZiIj@16dq8+6OFFII339n(6ed%=!(5_>o_mA zzKTxhOQ_n0&V>k)WTz~=%ImSD%p}cJ&ip(;Lb;r4NqbnGqRli-JS#rb+)pT6A;vp~ z-K$^j+EcQ7TtbV48ZWQAw*@r7saztGFOCUqe*q^tFT8sHK!D zJMCxEZ;bR%#?@yTk2f&-cy*LeKUUQcwoG<`A)Pxdsivi=;;R-Unexga51P;vs)z-p zAKXEW%?;53IYFjvkn&FC$&km92M_Dd)o_3u#k9cMe>^Iq9qKw;PfQ71%Z&s%-IB?S z@v|8G$(F1D_99kN9kIMbEy=H~P2dBkMGR-)xUA9WcRk92N^s^Yp~R}CnrKv138(Bj z8XXPeFB!Iu_Ng8!0d!iwR1DdAlWDW-nN5;ooU=Rr;!kn~BEAaw`f$sM3$T4|DPkBk z{);2D!4NrNTgwVA%)P5af&?>@oxF)=QX8aSq_74$=fhKh2IWTsWyQ!7HC%@$Jj6#2 zIwL_4^RCcz1ky-z2+CoZs10;hTY-C|0x>NJ93Y7lZSjmnq!pPJ#-zfuK2<2n7LrxC zRfVmlv?FCU?%ql{D=VC?K?IA66w`lxa(#PCe{3oO0>@G|7;@7Cct(h12}vUHkBT%g z7f^Cw_C9Yc8jF0}>uPV059?^|4`hubi-z^my^RB`?9a4*F1gM<8bVC}+(lJfp5vEB z{k&J^NAaI{4Vdy=mG6nn2=Pr&dlHH35+6eA`&0<%aJf(|K@3ne&UCQ*W>`FZn=Dzg zr&=gd2u=6Q6usv0yiCG>moZV;*j^=PSh0)RV)uFdY-?|2hFW|+oS9)*F@a2kUP?(? zTFR2(Ve5D_roYLatZR6l**pg!j&nA1&nc{e?=>IK8{?%F^r@ZHj0Wye_4R>j-kceVpEHTMQH0Jib8&19TW%X4wx3tpq++BnMi{D~HprI<1PQ}rqvVIUxE#w7;`}k; z9{|+GqoYdZ7X34vTzDeGfgHAoJ z!ljCqAwwRQ<}wF0FxNS8pNv))EF;r;XCSv&Kuw*5^^Cw)`xsB8TtemES9aBo%FV`$ zCU+4$g7+a`ATVaw7%NJFcyDY_Zv4{%4H>SuR65uQxCJA)IY|I7!;7PGuWUn6K2pbySRRh_eX5rzN8L$}j2+?Ix=C35W5kGW^P zXOZj;gI{|;9glpSkbd5oTX^mBKdqkxg_v>=md@D$I?Ho4?ak8rnHU5-4o`z*J^xui zSr(aom^yiezK$G{Nl3%0Z{agyPkZ2O<)WrxjA+Q|t>*$+aD84sNW+I?2I_(5^VLb! zqSq?zrfOMLA~wm8P#NrVKIf)``}~~Kv=n-#_I2Q<454Z9TqyhFk{Mii?sN4v!y+OW z>*``}fEzO|fZ2|sj~hKJG`n6{Wd(`XX-C3;&_CcIfoW&Kd2(bMEQBopQU6p8mNqAT>oJGmL~^OH4unsEe>^AaSe7!E{s_FgOVjne!q9!8x2MP$~G?PI+!`6{qQ-| z(BV6E?NY`uYq^eMRDHU@K%s6^=B`Bx>FirZ%RhVC$r0Uv<$ANj089FQn?|PS{WfLv zo-t#JQQV{G8(fs6J6@U=i@o+adsDKh>p2Xhsp)W03Zfoi3NjOk9b`I%7ZS=DXDnqu zb#(Hd{?;;h92bRpx{F|316RXu=6XAVBu0{$db!S^`e0U>3%xlSMQ`L?jE*ip7#kyO z;FUnNuPNW0IoTkWCRi+_>J#cZf5`wCk*1eH;HbX*LLV%G43hxRI9O3rp{ul5;N1IH@IAa^+RVc>?(0i9Sp?~ooh z`{*b$DUR_d2JMz(8n`m%^3ErJQJf` zDT%^k+Rg<_p&e^e0~3YwX&u0CMXZRe7$S2Lgk%y;e$se86z#s#Pk6k^4XBUXA#6Ew z@xG{l5+F?w`Q+pL5#C*p=1?zY0leXo2m0Un>R)d!g+K{Fhk`h;F4K!S{$;Xw1tlt8 z^&cd3={UE#=7V_sBuyFnz!*f^O!v5tozXzg0^r2b_%dL3sA{D2$ZGHL8+1rlBblq(%pX;nJK1fNeI?gcMn4ID>})6W)^$(X!695s#C zdCNwepZ+k?@lFSuI`rrgR&{oTx_Vg$N^UmNQlP8d()kgY=?d@FVG{F3QM z9;2N-A5KPIf>hdx&XwHR)L4n$m)HoS&`(FR14R0Gqs7iZg!T6?G3&ci9U%eE?I8eJ z+6V*srw3Go)QETxg#@vsw8-JKKO>8O(;_O%!dJ|cxcnPB+kHiN`99A<@|3m=`9|9A z5^+6i@#hW@ycf`Okagp&$L*Z&NvHm3!2@q!2D;dQBiXt))q?5GlwJBmnY_Nk=%~}) zu7(}Q&JRuK2B;{=sW*%it#|bV8dIf~$>gZZB{2TG#ZoY}7!;V;mUv`zrhSM`D~|RY zhmau6x;LBfKFl-CfUAE zWT`yE)5KdHl1raYbJa$rQgu)h`qr1$ctW<<+V=4Ax+)E`&d!4jdxPD|D1F>? z%NV)Oh0}!g+i9}}c^ET2d*DCqSjRTb2f-oLl$(`s{*w+wgt~vkXa8A|wAY=dvs`gk zozz((q?4lTc-E>91_uT`A+=dH#~%E-m*Ohv`i!*|x?rlbPP&8-auY!wCq?p8^ZrZd z^4b*?Hu~0PLzj&d&fAQsrAF+4SaX7iWb|i{KqbIGco;hge|SvOJ>IpnShzRw*AWJo z@jV}7djN@qpl3ddB{K6^I1e=Q3tyN*EG|%?Tr^TXijtxI0gjf9d^C~}P9)Ljt~8y; z`rP=Ds2qMw3A5Nvo0#~qctU<&`WB?*d^~}jOz<=&m|@<)Y|fOW3+v&^dpFx!;z`Sp zqsO1)RyY3p64}Z2vFA3*H)I!Un_~pv`i&o&V_1!44)4MBA#bYuAYs5tE^ExnbbL8nR>l>g{v^dX9hVM+GGY)(IV9Hs zd}e=aX{Ad@MRE-J#EDrb@}x?L5x=YPX;vqj1&H;0hLSf*3>#TALMx=eIlHwhiVJ0R z8MI?-Q`6U6Im=j5XZ5QF$Ps_c|4cTnn7AxyLon_BV$}MD+xzUhAwTQT9=iEiYj{S8Rs;G85-_QbuVv0U}_7kHWr!!4F3(K z?PZH4f!zh1vtG@Z$OVI%f2G^KspRH}oy4e<9n+>2c^4cRcDM#S|0MN>I8z?C@STT+ zX@5=(RU~l^&n1l40{^>GwjVXSkJaC)A2e1i>9{qTTzT+uvABOm0N_<2V?hzc9l)s# zWV!lxI|=;e5c?9tG7DrP@JDyAaGYuw&O+Bd@eajRRMXoELNH`gPfD%H|Gm}Q$mFGM z`x*?2@1;4d*b$o!t-)xNsoXbSVys}hz}gT1>ryZ?l_A5xp~_GVY@*19e)8ElP^$w< zYCiZ|zCPzgnvh_$sRMkL(m7LVv=9@E9K?FV}3T!bj_T5_W_3UY|)GkmlTOjU}pg6t}iu|BR z2ze80Y%pF^hX)*F>V#LGKtR_3iHlC-ou0(TF3y{4Kk+T0?b--OKwFQ6`Tm2vA#bqp zINmTg?hw*~`L*|HSzaegUFPQse#Y~CylVG@b$KC}DJ~tIsj}DW)54Nm?W-p`X(#N5 zr>0PFxteuR9=6i*N#J>3sa0KVs}7QNmx`C{^rNq7A?3}%ut_pI(?NvxqzDlV# zn!hG#h6Aq%g7Y5w>-I21^2xL}k`gLl*1&Kn_;h%(rxR?ot~J=+==L5uwqoJETu$Db zR2K|4Z-E~kD=_Y*gg0#5O7&B*mUH$V5zG`2|3?lHjfYKTrj^ht?JU36%-j&%+eWXr zcS;noy~iU1Pq<4zDnastR6dfkJgG5s=!3) zCLJTXM@7HGR+s2W<(})px2vor*r#CxECS0yD>;NDHn7@nYhL552xNWKm70?b7Lt#6l0(8+<{JUzZ6)4ZPXMdxlw){G`O*szbj&_fWIgf#8gp zklscVMm=)2c(HL<@<&pJ$~(tbvXbK_ULU4cO}3ql$1}Y&dO>+Ui|wzaZgzJq?QMuI z{8isv3?7Qobk%#NX>PUnJI97$d8n?t+|ShebpmZJ%5I4N(;!RwXJfU5pg=#WJH$-9gR(-M6dzDzL_#1ZqEOpNS`Rd3ms zUN2oxz}_X|N(Fe|0ig`haOowP1)BOtOQ1AYNZ6ioKf7&Jv#_5%Ulu=S7zC%%HY6Q` zkiQq5ol{Yy*7t-e4T;$btZVgb7By`>qL>&k-at^ko^gIi)+M12&hy?ef%S0TV3Mx; zVjg^>r<)@4Ay?`n{DM=f&}apQG31e4_$~5LV2R2!?_^nF-oD6hSS(nuP&b()6ve}N z=WDs*3lpuisch#r->_u315je8XWB8><)9xK41cjc?og)db`tyZr#VEW$taAch3?<( zG#Yj!+r5nrU(84orF@#5Zk-uNg5OxCr!^B7EkjHEU)QKVrOz4lOq(0q-KR6Xl}s-^ zHwAK0eyyM#O{bzRTWpb(@ zhkDu0*aUBeHpXn6;L4PbI~!icK*+M!@HkU?OkPpJG&h-)m&nW0_b#mAMzOdSouN zo*4)<54e0fY=T7u13)*bh#U2HoWpe-1b%#2ghp$7@H)MW+VKf7e00c&l0l2u^B0RQ zqpvPyaP8XbJTlR0CQD`Pgb^#okZ@4h!Ove~o51))zFy?9T_Oon zmuq>rqWn16T6Kn$f4t0lZeaz5jA0BF-}a}2x4w6Xbd|*eCr;0 zxaCTm3(S)P=2K);Ztv0gKK+WuIJj;MS~X6UUzh0J$WW}ygux!b`SNc)4jp0QZDef- zziG*uSWxIG(}q*V!}K58I=aafppD1c;^?Kv9WGyjK-m#8VJo8lRQxoe_S|}^1 z<3nN2fWKk2AZmG9mOH^Q*{=^AK8yR&3j{g(0bye%9?R-M3r>n|2 ztWo10LmDcOrTH8&@YOCd-APm$zS&GyI5X)b3Q*CXyd;-zETXT!+&;0I#NQ3_+$4eu z%@cO`m)h$;yL|%XWU%&RS|ZUDDJM6)@rH>?JL`xg?1`cM*d)h)Hu3=be;?QXfHY4| zh&cKXKtSAtKtLG(`*As%m^qp_Ia%1*{tp(Tv1Pl>hU9~|?*~{HAR%k)yn3Ao4+N9c z%y&s7cG!X(LTX1*o6;m!NqpS=_(YJ@p{!|AACp}`lLgW$KIJ=;Uwj9W%^=6+3lEv6 zRkD|o1Q%~ADl&3^`FE8T23u&3KwwT(q4?Jx+)i{i+4*h(_=_rIHF@X|TUV;bk~Ev; z9`8$tslgxBbD|yHi-JXE>=Z_zE{CTn+Lx6*- z4qeH?2k(FwvIRvZqlg^f(I_Bo9xkAYQld{K8lp?NOxi^VzT+IFrje8+tYD?uAa_2d z-cy``u}BZdeqzD z0kjc$ADCKrFVt)797B&i;tt$03>U;FxPi$jyQIr0BYZTWg`@ZH9P}x0_pCuH%P*|n z97es7rt(XsDFIP1=EZNlbPpQuLx|xCcSc1hQ&Cz`A*Kb$8n7Abue+koRf|PMQZDK- zBO0=X^GTqg0G*nIg8WL8lAVemiHt!*5>trRC=sJOPY4pMl^EOmtqn-qaJ^JO%~MOiPuHJ_okF-r~K4qNJF#?+14j zLRem27Wp4k!2D)2+I2wZ+xY8FKQL7j%Az5WeeSEz=0H=Ql-EO`O5`w$UGAND&9=ab zS$eq++M%cdvg&9?d2Ufyy^CV%>QKg#cQ+}UuOgqV4e#o4pk{+7ol4(S7B#D62~>pT zy4Ybcr&!8@@71ts+nrBeA9R$UC|XulUqRc<4!hb5eW{KhL_nTi9yZSlP91j0S<=>) zm$R+qP^G3s%zV)4Z}X>~mW|8i6a?2BkM^32Td*#ZD=fLPov|>pNC$H}ITlahYkt^7`V#I# z)elz+wIw{`<@`q^ViT2Cc09M)+%P`gEQ zUSaQT>QDWVkgD4hG};gMO~<~J2YodB@`nK^d-P=YB;UT2e?H5*x4c~FR+VoGD#Ho(T@e$(Om}-B%Qql~r~PL? zZ_NmNRPr>f!k&|;dOG$h3KgN`48n2?ip9rv13Uq+G`a@OM(-IIXB!%8o+pp9^1Np@0 zOyKa5I5P<7txN&Uiu{&MJV4VE<0`Safhm2?bt9UHm+CZ7EbtXyuZx*k)@!jZ0E$P_ zKc=9yRUm6m+e&$(gv=)7o&`>RC_#TatQHhPflsj&cN?ZYVqk{_HeKWTG zn=NI0@QJP@6L6bssJNEQeU@ae!IEuKum;YYCuAjQw(+f+X^a{02TL{&PtRajR=krsW6qR0xmd(8ly6#( zGjTmPiM(|=J)im`f{?ItaPz<}%*hGQh$R4afSZ1y@~>DZH;aCJ1r{6m=_F`N*G-`t z$gQU^*Z^)c2yP$vdc0k51dE>qROoY=dc)I8>yq-8nTS+JM#yQv$)`v!gZNj3l)*`m zy;5;1i`*uN3(t9#eGpIKwlOlGXS`}mrjTt5VK3bIZ!OFqPRuAQSe=XSkWE_XVlx68 zk>@JNw1*W9Hz(=OoM^A`g|-NuUC+RGaOdiH8nZjB9>M#npaDA?PyMx)$p-)b)ugeG zY{*f3>U6$= zC3=?|60`sh6_yv`avgGnX?j1$Wh;-bBt4<6MX7O>E}xoD>!uT>(b-EKNy4sbu7Xw{ zbj-GQ%KqW%l{9})De`Sb|MEooT(nw~yxV>~|#@M|e-n_`TCUsN1K6aUd>d97JQ_{*dbDF+|MP5Z&64?c>JpE^jp?Fj~ z3!YIWz$Jw_I&v~gm1(Tt5V9b62yTOHT^|b}hg#CyS-%U4`aD^=U2u06{S;s6gG`(P z&Tr)P%%7fWq^jcYh?X_iKzW@V&*at?&TwI_!v@SC7y+4zyyXr=g`n4^aC8!lE#L$8 z6DW@Wzt={8uA1^-%T5oX`iiF7&YXJnz#dEQi6x)xXxZ1$m#Rw-FV=gu>NZUVrKI!; zF7GGVw;_3|5R0lOhT!08^USp;f}8fGJ{CRiM))91jxX9^&25nKUWCmnaK5y=yWnp;+<33vpXFTAqWVlTo`SsG|vt^j=T8Udu9!ySJ8X5OsrmVYTO5Vo8O!fZ{0 z=VOz9 z5lVp>==Y40e)A(OKk_i+C}bcj{BMBDmkri>MdtBkG_wzigz5F7bAC0ilZlRcHv`+U z)<_i_1ILZJecZ%{U+1T4wBD9TJL=~Ew-&!IlgRgR3s3mX;yi9Srd=#nB!YtJf?GuvY&OH zW0{d)V~4(kHiJ7eW_A?9$>f6^ru(x%+HCDTXGl{G{7wj|;X@3`%N22!k(>AWz|5EZD!KbLFR>WM zi|GO$j=Y%%eW=%d4W;kvUU z-z>RVaqx82z#cxu!#A(t=M65qY`;g_}E4)@oTmM1v zIw!yW?oCAPgF>Vx7HXB%cgIaRjwv_o)?^jjo`@l2f+)yP^FZy#QYXK@-|6fSq-qN~ zjuhP8UJO?Y#I&W`JXe0D$v??k0)H{b6H=eXa*-) z3DOQsw}mD{2KK&%%~(#?y2a461JdXfY==!khNv66-~+e zwSjP)kstq*W@c@BOtJ3kaRUAJR#d@H=R@-1U(v+`Pn>ZDO{h~3TX3$O=T5Fc$}1v% z)*qt9Wa(Y8;aV9BV{F?}dyDUPD}m@ciAU}g8&dnrQ(#CNQXjIQfeJS1sJFWy zg1|jrSkMjX-|ss~`)bLw*S$RUJ_4|_?a)^Ky)v7eyCGt`m?=WBBh!cK|1NZMd7Veu6v@@&2EyKg&Ji=@7(eCx@ZaB^F2QxJHlAa^v*iu!69 z0O2t|J(g+E(gI!cguMltg>r#~G-|GfQ5*(pR(Xz{`O9un; z@Sm91YaTbK)lJEkEe4?f2D!rKVsL1iz}_0`(#r`kS5SN^&HC?I?<*~yGBzyy z!N=;YHJ@pPGmA?N<@IG0rPkUc*4&<0*87;OZb=SsxV<-1KkBwkqBLu>CKbQ#h`0js1TqM?><37GQ{@(Ca*ZC2zSo>#;HzQ8~8HokzbTXMjW`T^Q& zt8-=@r8sQ%FdCQ_gtoeER5Qe0vn;{938plx+Tf-RI0CSH-Fa-8=-_=Z0V`og-EI5y zlZKo2-xJENm9h-i^4I6Wfv^10{*Smyq1qhp%k3>&L^$924wp_uwR&w(KU*H2@Y*>0 zCeU!3u;kB%9HI1m4923iA0nw@+w~l_dZn>kcY+E)BPQ-%D zFoyNZzipoLw7?J%a3X}dgWf5t#>TVE&tG_GJK$NY3i2)a$%T|hdKKT(l8e>`J}8Yz zg9x*Xs=X0yXG5S-I0xv@?QZ47<>x>Utw-WW{$u(d-gNaH8_F`P73Z3O$NgjJ&%<;N z*Sx=T7s(Ag8k6&nL5>x6;B-r$u3TL=&dni2C%wU?W)e2iYw|3HkHCKsB!In=2~{N{ z3=)Z{eu-kkIk98y9R$@43J&iK)SQ^Rbr1JUZs@11_!8dyLRZ(YPK$Se?)+fse$Vh%NFhU&p6-awKbOk3F39C{EYf#z-s1~)Pt zM!@N&vBwSSOrX8ZC=(l8#(X_>!hw+MIfWPcUYrLq5`I<~M}e~R14TX)aq+|E4q^^I zi`9ER4Rwu<9%p;Nuk`gNup8{pKea@kX96${Co^D@?~W|}Lw&iTec4UcOOxWQ0Hy%8_VPiX9T5Fgv-ASzzUvL)P#M&{FUu;E4ebgw2}}B=tQ0yO+94(s`dYVvwUe#1i|(P?pdpLsN&c__z#-CKh!S6-^zJt; z=(i(v_?h+tLCA}9sFkr$D4TZVK0+jPBCb|b@1{u*?T`iE(8o+AWCc!-b6LH=-*wTr zFB<0=ag0>4*Gk>Lbl!H?lIGL(uJnSEq>{@`jTqr!Wp^6>V=)fh7liLa1c8EIZ`2G! z7yCTEt^Fy}v@|fL06xOG%AJ~fcmtJ$r`+fPI3w6&dactFuh!2#@H3fv*!Gu4ZeqxE zJ&`Dh5vnZw6BNMb?!>095|4Kuswo%fN}?3VTv-9O%N zC#l!``=&`(5m1lxVYoN}? zB6mkt&p-Ge*eruzOt>Qqda~pU=+oyQ6!q@fX)56rl6sD%37=xa+jvt@uJYmq$6=u@a)j||Kh!|5xXRogVZ>OS)09-C_ zUUY6x_o}kDug|yl*VpG{92o!n;)^kpZ*4?aX`R@bT2d7aj;FaS+KVVJl&YMezC_Gm zb65wrA!jAoo7vNkf$G%mnIWU3BLi?cdAi-QMjrF!jKgyBuEBEJI^)Js;IY43Mi6Y* z*{CuMe4=v*kqjdmh9C-5HkucwU}z*{Ri$O)F?~+YhJuVgFkW z7BFs1{T(ta=S?2cAepNC9mG6a5=8|u4azA-; zBZXf6UQi;%7bc4ej2|?8LVTG7)B7u77-|9|^iNvpiSekbQDLGK7E((B44V{T4)UWg z>s++8Na(IW1jGjoIe}p;12)FFNVXJMpidOyVBvt2CD90kXPDnlrY@*BJPfhno(kiL;=pD-io9tAO^bV+ z>D;F-ztX2Nl*iYC!Mo#9coN}|DG2K^->!@xqwMeoB%gtMBNeTPZ2t&BE@=Kk-p|-W z=u-hdlPW)g%200JGi?eYV10SGX!Dx)i8YPMXO3kRkaOqc-Ntll zf<4JHtyWTOAG2#rRTTt{7iRxUj;kS)Rl~_<%@ilt9xMk#ddtVZ+A)}E*crPSHqO%U zhtO8*&ANq(9L?r8m5?3QF`d3y+sP`<1Kj{PW2tZ*p#ibiVThQqQ@9_fD*1Q2w6>~! z?^v$3Y4dNlUGD%kun04`DD)HdVGzY6$Yi78jqUlO(jgg23kgOr{~pG`HFFE)iXx8v z@8s1rf5C~Wo;H=6$zI06@myZ<0iLZB0RcDvEC_#=w}!B3k3MI^jwZ4PgF&PJZV$RR zEsMdJ$f2>vd&6v%Ce#SKr7S)Q?4q~=qo2R-F*A2ru31n(lMzFi|G_G&cRJWP>1#vD zFy+7^|1K= zjH5)C(9J^HX~sa{ZJ#McYH>l~?ljzs(P#=vRa0^t$sUboBbA$Q$Q>Qc#F&aw0>#A#eC+{vK zH1(u9VjR#A5#hd{S88;q+i3&z8To6S?W?xK>Bx1V70_D(+-TNmBxB)mB08^XzH=n$ zp(6SNj{BzA4-Ae)lzrz;!Hj%o79-AW{`k%U7?4=l;_42<)apbE?QSN6&ZO5KVK1<3 zuWj%Rx#&I)pY&5wo$ReYp8s>=45G_;Ct!$lvri+$RS)lb^giJ}@4dkN)_I2xf74Ux zPU7}6B+7w;K9(@dwaom2%y_uuQv^Sp(flc3Z=W~A5ZeAUInSOkURj2sOE`gFvbl#;6^BUAkMr!h~yGya&>lSKuA1|02%X9!fvnKCU1U;~S1u2WRT z?Uy2u`HK_6?iCK8jWwwasBIAMVA%L8CV;X}sD)tZB_UYq%liIeZVUO~dky?qFvwkX z%0J+fJNc=v{d#Ki`}|>Dh9s2>GQ)`UnAJdWpKOOu-D;MdVjFUjbz5nLuhq>yYVZIn zXT<3dsR0M{eSN|c8xPApKvhI2Rd;g`g3jCN{*D0Q$BD6Vz%g6&KhrZjz6#=V>J4&X zQ~SLvUGmf5(_LK zC5@yYprn+N(!He8-3UuJNH?O--h1bF;W|9`H}m}W%&YAC-J+JTk z(@YXg(Y7_u>EJwUUal+Xg{{ivjG>Y$Fo?N$ej%3W5oqZ50xBgx%NzDV258-BET<$! zSR;F?mxRYb*l>_i)2)~ez;4!K++zZ}Ejm&aHFWf$l~X)Jqrf&4KW0MO<;BTf^vR8e zFPyHEIGfaApsN`hu?an}_mCR@jt=(9u+eDFC^}cv>6HDzv1MDYS^Sz)LEpyQ-kpGY zx1Z{`*8xvgR}@5ULRUfupf%q=a^@i26=&~7nM&)8(`0&tpY7G0e1KJpK?iq4onJx9 zqg}V=*9zYmI`4ZD4+!D@P%1iDVJrByAl7kCD)5^D;H0f&WjT;f867|>eBq}nh(EcU zHrKp4EtE+m^_&Yb60RTlUGbM3(#P60`o7NnEsB({91N`30RV90kSo3}$sLCfvw4`d z4dxorN{5U;%^48H;dvH}IpCq>4C%`=t^KI56BPq6JWg$&5;2{1OF`iyuyC2KhB5{7 za*cJ_f1;cv9yY;O@nU-$b2?%Ed%%P=dY>kPG+N7ZAT~Y0J$N=6uhxwwT!w?V&9ZsS zRbY;cBsMi~og6aj z_!2+RV9CKM9=V!Eudw6TZlv9P29Y0Pe2>AC?+xls{c9e7Wd+t{gu2$~KA)j@4&6-( zO~#vgNu{N!ym)yO%(A0NOP$qR( z6hG{s^_^~evJ$PJ+gVV| z!TnA_OYrTi*kK=R&|sdjoEvaZtLNHEk%;lqJ4(W*|LfC8Baa0GDry;DSTRo7aF_MY z^3$uBg`5|!S`3(+DjA2@1mx6 zS~q65lH(^!Bmps;k2uS{W~_b#9*DB6)xSrXo6-tn{pIs>2AyhD!Ye{Z3u4Um)d59M zyGHa!)vnl%O}xTn;OFQcaPdSw@omfLg(N$)@U%BEjO}k<*r{;fs8hx>tO1B+Le66p{JLl27IoM3J(D z?%>;M+V=3d;!rL(pTel0ch$c<$%sIGXq|D%<;O2oBQ4`7K6NtaQl^%AC?wJ`5r1D@1}xwB$g?J$t=G=xmT?oKzs2yM^iXbPsG&NcFg)@WJ+o1fG#?M zB{WVYH*6gKhp|YjTvhfIWgl5e0f&$D=>)hfD9TD3H-<0zxmb)g9ihk0 z)}nOe$ZL#C`{FcFVT>!@^~W4`XR^Ni9c1??1NHgGHC|(h#%Q!d;<}5P-qZlRGrTT+OF-k_QW|4S z(-$PQ>qB;`GVUAmnAxiqg^_6VrCt?C?0<`vzY`^|s>*#E z(||V6jMd$pSEriJ-utXUm@|Ln_*Y z`CAB$nL89dykv=Oj-2h$+I6~6XH*L4*}}Ty@>+{^NqDRr7c#u>LdvF}g?{J5J}V%i zwmXJKiwq|zi|AVsJ}~8n;rB;Edm`mJJB*YBxk#M*2Q?M#?8Gz1tOrRYc~&#geZkt_ zT4@XoB@4H_I7;~}I`aazs6gql_3?yCO~Qo61`RGn4yst~wUdkh0MU!sjUqN>c&hCQL#*bj_kyoGz<(chi-S(`K@* zRLn~R-Ksy8eFFH=;-5F8@wn&Kk z?B1)p>t~l&(>N59q-D{0vtt8rNfd}WW<42ciRX#{FUGWd8T!$x3gcGX*Bc-vGitx~ zkiJNKt41~Udw5}&0^4_pKmG=eC`r*Z3{J&IPmy9Icqp-*7RsLp18142ufI=5GWZ@n z?5F_!*fgeFyKK1){dkA#RY}zWH~M{Kfl(OnH5baE?HSa|iJo4TQRpbX4+u>VSbQX5 zraw2Nc8r`hhe;Id<~1emw3lBUX#9$A@v35r_&jPcum=;QIETA&hkYj^d4Iu1E4UCA zNfSpmSFfqa;10Np-zVitQeSiJWe7SBNTHQ;hT<1okj60iuOM9Ku=#) zPNZzZyE-2Nuk@Gfn9@+PdW*pn1J#SCXRNZtT6BSP+7NqO%k1GWqQe+A+7q&S)N`HpEk39_`M@>}SyRVfrmo6e!SYc8 zBnL*AjIH|>N|GOtzGl{N5!%e!Ms@Hl1+JS z4`2E<7UR~3+kMfPogM-OL8U%N8@67WnWu!hD{XPlv4(!F>1iU{5=iD`olh5pX!BmN z&>0(sH=$!qe#j>QnwOUqKW*p`Rbt{g-n|+u_5a$VJzyMj21{_P3i6HPovsEZYtzhy z1G-+I5=OBlMVY|xpl{HvO0n3;x5?G1G6oIX$V)#c^unCKpKg;^K&XdZnvNUSpg^kb zkc>zQcS_g9j!r(GH@&BELKmM}PSo?*NuF}Uh(-j4n>lp~eFMKbz4|_-{5`<5v}hyq zsbk@RmuO9{SzP@1!N>AT%4c93=;L^UvE)%8`5c>BpNxrX?UfCSa=FT^=+-MqF2_>& zY$-FM2zerhWY2Y;@4}l5mRM(RI}=nIqhmK32pl>Nx?Ln80`A2+LUj)ZALR5`ZfP(T zr{%ALToz$(3n=hF9Ug-FNBaput_>Du)F7UT)ztYM{5218 z-&_6K+C61lt8>e7IUi=6~gi?MV*2S1JHGF)ue8$>{(bh#fT zr$XJtDCUG-nALPR*QqBhAFL*mOwNP_dPfB0()aVz$hU-MW>2P_F=3glvGn6{Lu%eW zi^$6)zOq!>+|!eH;!oX#XND-Vtl)$95=(!o5v_)m=y}_pCq1-ZkXa@l7?dv)mLF4YcVQpFza-(z3()e7g~emx% ztY>vTsB*{d#L+d2W`S~2-5);-9`1H69KEDXdE8_0g*puxE*rrubBdd9!QE_JT+Qrl zJk7xW@?c%H)ZWZ+<3RCyeF-Sm8M$#cs1qG*zF15HpL_?h$|zM3-|N8p)%o&bi~ZY% zeL@Z%+LWiyuF?VWj;=K7oc)UcTZtKBJjdexHLA1XS8_$aOdpRo-vktM^YXKT)2P?|I zrpZ!I?fK|W5Q_}FcE#PL^U~Kl(A8z`0#0Yu##ALn1}P0OP$|wTd{XTk%1DDASQwdr zMqTN)lc9T7Q^$TQ-$rzuU_GALMGWz|&~+t|enT9$;m|j2r4!?q4UkmT)Z`%5l z2S_u|nKjO~J<6(U0!4jre#$CuE{14VWmfTpOwV~@883zFKH8FBvJ#arHlo$oSWcWD zZ^0*jZ-7B64?(I)V(f9Ov2Nlbz=;xG#&G|bl(hBiczU*Gr zB6(WxC`fNPq(HC`xI{8WGnB}jQdZN1r(E$ZJi=r6GLE!T{t`VC|N89p;Aekx(FE0P zXMk8dfml3&SUmB6Up(;yev{p_r)X}w$q*J5!lFW0R0xX-VNoG0DuhLau&59g6~dxI zSX2m$3Sm(pEGmRWg|Mg)78SyxLReG?iwa>;AuK9{MTM}a5Ed1}qC!|y2#X3~Q6Vg< z|5p~38N9#dl9@A?4cww~hBxM9yzw?1z{AN6-*|XA&23!30GpSVATBj|9T_4hv5!o+>w_F&ah_pCTe^~4dOxh}csRdMV+yA@(vxraN8t0zHZ}XB z(`;i%Vb^2rcn7w{&I>AVMVNt6^SEZUNS*V8vlJEUY?u?4W+novBT0gE(7x+V3ljBc zGljA612&&0WJO;n9rtcaTcR>Q17h`YTyyN5Ku z1DPCUujFH?#V%MVz8rV(b=w>^Rem)PUoa^zC0|iBIhT>V%1e;C&!oT54LS^N!kt>r zo4k4(Xm4hJx;GX{!eXL63b^_pqLu&4*81$oN!$0aetdAJ%z<9M$}XdJK^u`XhHUik zGA!lM?`deRi4zg-%PNUR)Zi6rRn#WzGy^su`R_ROpAft!@um&rJMS)pICFm8h<*7- zsUBJ3=b8PZMDU&NZ%U=FC@-&yJ)o%8H-xJKVC(N4DA(d1<(pq|*633KD06gim1!v| zcX4orabd7(4RR0i2@dfMFR$F~9^e`}<`~Ci0Vwx%sg`N6u(GMGtlU*nt=3}s%s<}O zGoUi2)?2W=vbcis$N0|B@kp@Y&dhYG(f z{P-1L%&qKoWmTmUj=;r^q@?$2&j7BCvEJ-RoWps8h*ilN6*n&Y7XGK;&GDdTG8TZ^ zwwn6G2bj{bgVa!xrbYN1C(IU`uEAvk-CL8aC+Rl&KI zBr>SB=MI%l!|g^P`OfV@7)VZ$YI8sGLVU>mVn;FV_!|4O8|20BOhGGv^jmeJbVzRP zW`Sn!J4#Yr7X51AErFzdv~x6Mgaavlt13PT(taEK(HVXJQ+q{1*6&E=ftnLScZ%-A z_k!)-%}S*nvy@oP_lEG**Q9f`TxfEF^^%&!OHY=i61Fzk*|~aiw=_@vL_R$DB?VfE znQ@y?F;sYbKoz3P%I;;F|HNZDgjEhbGe_*X84MGRtAFR|*Bbf6xu5Zg?~Tedo&y1IgD!nnFviAo9~?_a~<;fo(eBJ%Xp6waTI@U zV`Kx3UFscYzgt$~f_?#kx7-yboFCEY$WS;Q% z;l~0DUI}aQ=><1x&N7XnNa;8|5x_;XTaO=Kt#e`E7}mbRtmeDaa{AC}xO0k(Lh{dU z#kcn`hF_Kc{8ah>WiHyO9({arI)@SFeNgZPj1znhHPf~>9?id;7tH)5@B zB5t#QuMz6%HxPe1!8b9td8gMH2Dp>@@3XnZLcK}4%|g8!Ea+?Tx4WZM# zWjME2`Zn3^8WgN^3+Sf$c5_U(JtqR}S@=ZO3i-#c{{a=he?b5M literal 0 HcmV?d00001 diff --git a/analysis-master/dist/analysis-1.0.0.12.tar.gz b/analysis-master/dist/analysis-1.0.0.12.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..1ba274315415d3096304b963298c369f7d3b44c2 GIT binary patch literal 21001 zcmV(zK<2+6iwFn@J*!><|72-%bX;L>VQhJGX>%UY(<*`)35ZR_?)()PZukCzW6Q4(v4)RL4Xckh1pcV_S# z1SQ#V)Ap{^-IyeR!C){L38_doGYKlup1Wm!dq=RHaz^~U{4eo?LefB5FB_SctRe*d`re|C1( z)c?J1w{P|T34Hv->+bviH~)PXSJ61CqV`X5Q6_nI;q^PcCkL0&JihP*b38ease(p^OC;6>e7^(qGJHBQ3w*x-45%IN?#e2jW0vpVd0%JacoD-tS@q=LZTydA zQp9DOLAmfgADnc~3=G?^^Q?l*?e}*JXj~Pqt7GW8n{mF%o*aC#|NR^P>hfQFIet|6 zf4}+v6$QmVpaU^Dd*f54h=Ac5&lV1TQs;={8TFr_$!a6`@ zT#%N@i;tE?fl!BWHkzS+<>eDmJgT_%d~yQ%=R7XGNdy{Qfkn%>S}uT2PY%NHmg(7H z=ncHXUZ;bV-zM=2aA7oC6iHV3a@>ZYED?qQg4f=$g2O}k z0qVy#$SV0e{@UIoSwkIR7^Nu`ta7i2Cn=B=J|dMzd4UA>Cd+Ju?SwAPfIO(k#$_GO zYs{V!Mc&6{#d5!^;6n)<7^UnZ71uygt)%J#!O{uz@GW#Mrs*|AW9*rEQW8DpQ8nY7 zQ%B>Q%gYB=!pg(SslWmAFc`>s`4V_{5yL777e)ZIM84gLJZ5j57`-)I3TP`>L)`}+ zD?iU~p?OnS^xWiq%3T%9xV%Zy6dQ*%IhndhqGT01YwBv=!B+OurtEH%Od(j#BP0n8EE?le zSap}wb2-*mK$AUaA{qdgRl@*wVzn;?=?|4>5m1+=It9=wX^xE|X0(O*Y%~*+24}Mt zu`o+~tB@N)(@cCppR;P{x#S0T%n8qF|TFEd;lj;s3YD}0fE6}}&uq8;N#R4e{I%x@Yqd8Lt zw=7X5h!&ioqxoQ8ADOJ$1lk4Z$QjOf?KMHQp?0}TVXpK+sma3T4a z=E!Hhqtg39=KL~_V3fx?v%?~>XI2%Zi&->`X}UrEdQ4J{YwKxZ&Og1{{3CT0E7!}N za-Hv#>&&7}S&@pEF?kuS-MW(n#2n&6&6F^(bB0lwj6$4~Z46%Qgy+dlxy%7Nf?mwi zWK6?(u20Mk&E103b2JI5b6gb>4%h_@0vsoAp^f?c%N$stQr2l|xt_%5oV>8A={l-; z7)S;I=AZZi6cW~vT4mja%4j5YeqoI%a1(%LE~(ro5TDiPdlMH~oYL~|hu5zNL0C7K zC32EmWBKLW&6&3+v4!dD#G8;lio`>a!IJ ztd6I&dfyKFyaD!2mia;bGcf98NunDTWd&##&=+HvhwxKX#IY!YpwH@TPRrCW2=6

r^@|te4C77s|_wban4AlqUs0#kAv}EGys%3iB3V6{>*eItx~qEK}o00Ucj2;z5bZ0_ywVuN=u_0}Q z63ih9oXUDpVGxZ*%OVJ+XkjSL|z8~aQjm|YEpBO9~?(gfDCx{HBB zx(mYV79CN_q=`_QjDGImD!;6Cyi4EJ@-&%`=6vIv%z~R>I81EM+Od3i%YZQsk0<@72rCA0R*$eD4)kxu@^2mq*mN9L+Cv|39u?fqDwhAT82@pr;@ zrpyUu(~-?Sb1>Q@!fhlmVR8K!y9?(#m{egj&~{LrIcZgB5TA8(Z4uHXrQMWou+D@s z#$u3Vd*K`iFvr9z7)oUK5S~J##4hYqEJHHmNwmxoeYb??x-B@%Hx%^?@&>9{H9I0o3Jm4jJpP0ps>kmx36 zIvUxXbj@u7Vsa5xGgm_#%paKqKd%wIW)WbSdb?zDD$G$f3$;Pu!&*x0CaBNB7U*XU z#u0rW%K=EHS@9L=RmRm0@Lyc)km+QXO#NLlS=u_|YjXos@HdJ<=xQ_}I)?ID1Lc9j zqY%bwF-fYHx0)p&jquwt1@;5BTIHxblxTdTJ!FwHE{dF4NoxBHHh2Vu(vz1(oQ04J z>sG{W<1)=rNVZglus-YE71DYyJxfW(+I-k+82yWE-$i^m@^->@oJ(UE-2ti)tRTN#|4Q z)p)&tDV5Eqjy(`otIL#u02+wPS7VzXTafgIbF4yhiEh~wyPf(5pfGG0jYXbV7C_`e zH(a_#PJKs^0UR!Y9njV)eJsqbapf(@q6p%Rwz2{yr@4{7-nl0FxNPxo36r4AV)=c2 zO%s?n+e@0fm_`{XHhh0t%y`HWC zdrAfNln!j-Z7CeM+_0si$;LF97KF07DOR6NVWMr$E)aO(981!q)Sa((&e1*aTWQBDMM1TMRwLcxQXSOVH~XCDBbU@*K3!W;gv8!$Fy;w za`$Svoh;3K9^HV`JR0K!Ix27Li8?tfQam|0JUnF1T!LX?Hu4#aL**~`7hKig%QRO< z5I#R_@r=4No%fetQhNAnGB2Y}JYG`1fY(Ag$-ui}C65sC5U@VtppLYCDftZ+r${#K zUFv1>o2f6$&uU=FPuwF!zAHPbo$}h)Zm?6COg%1ag1&c;*iM&D<)FG$uhr&SVvA*%<6#W%rO0$HzACT7je z7V;bUaq)u8r;8^Djjkm|s3;)ZyADO7H;O` zXoyUhii`{k^KqO^XG2)P!Xq+jI7Chbgl^|8GM}X(nmxH%jR%e9>CmH(>W&YYJLEW9_`F;YXev7Y))}RFDGkMZPeegw3=Ik?P^tte zEOtl!3cTTy^%Ew;0g@tM&C_I`PgW;lZiJ0*VWp!<>7A&o?iR5>0m4*)$Q+WgFd&`5 zXC(ufg7#fX!v`ysOo5O{f2}lO3Wj9yXv0o2LJlw>WGQR71t+G5faHAZVtg$4*ibS`hN91BkT>qNkQxmvgG zu36*EiQUK7&>S4e#7|-5%ap6`b>MyO^;Hi1$z+`l3Yy9YgFd;9P(?Mwf?h)a-P{A= ziGvR^iQy+8@PRr`CX?+oR9C%g;Fb!oRym+FOy`xaat3-^IAslap>hJGR%6=9wEz^S zWqjd)dYNaj5V+d*HXB+k;mp?Z7>9x8V5P_oy==eXJt}JX-#SHEF-{hPJ2@atNT_{1 zP#v#T$AbcyWJi*B0U0zjftqmv{OCRRhI;#|;?8I<>xv2KF8&%C1XK%ZIW)>d-ZQTT zmF6gzv|-jA+`b?@LI~F<^jf zB`5Sb)a4JKHP!V;Ca+$_W>UkDXd-p&{e26mRTYm#azN)#O7hKQUZi(TWQI|@{(BD_ zy#9M1TfF}J3H<4FItrwE;(CN8ldjmOYfX#`d8g;%->!|u09rzDiBBnz5~m5AR(Khl zw)9dsF()1~2~K0b-(rR8{Yx5o<3wF|k%jpH`UdBoB-jFpuOmA1=q3)uo6lDhBA33# z=zL2rZ#B25hB{bw)`sdK(+}b zhc%SNZey&;KD8XsMtM95p=%_ptKP-MwG*OZ?S}ezHaAvQ8DJR`IZFYkjV>$^=!2n5 z8pS(qrhRmwgO&dI1%0ys;;l6{EX3lL+m6(F4ycGOW_ad~7WxJ5f3dX&C{hbtk!$b6 zGKR*F0p*tWP2f`6zDVBw)!G-b5XgXJ=wDzP1|T z=m(!y#;|XRx)DqMsAGo&SDv7Zl4dSk=q8+>JEZq04fKN6ur&p91gw8gp&T(ITONa8qNa=yP)ohiKGe;DfE(gvkz- zp`AyxDrDBnt<@sI?pZCGn>*z{ipqZ|0vcmEcQhW2xkmG?95X6*WEg<;f&C*7afIv; z$M)U<;eO+ zJHRkZ#x5|BVFxhExa@)v$;53yxE`Hotq+Jp-w z`NEoqOUDd-yjaU92m2t}hbuGwNX^747PUlID{*Dy_$*tETMq2WY(0F}Uj-fDGkXxU zAoTD-qX$~5#dDxjgjS@Qy;d8tP=@E>AN72rIOD|Pc{s&Fo)B8B#y=Y}VI#*aMv-DS z+_OUuDXdTN0M~`c(+xx347@L+6scC;jzjWU$9@q!#d-zU5Bjv?XMh*^%E)7pn^sKC zEM#mZc7AyM%C}I}UnR=;M?;xCSU9T}gPUr2n;$l^i@gPyMdN7;bCz#=JUnrx4G?w)it(A#f52;ti6t?z47wJCr$Otw1cBnm3S7mUI$cjkZ|{ zY1Mhd3HKge)Tvrur;&U%$Rr+3D#>T7PGx4&D5F!uInG%reV7v+1Z=*uJ!sIU4D~^y zwas$ouDsIHzPY?KG_sp4)0{xKj!d3x9UQ@&d6TbTnQ|n) zh0NZ>XAomL$wKKGFgOL#HR!{@#V=JkI9g^2j+vwFyy}6BsM_TyO6dTCwlVexWL_5o zODc4}xfG8Y58EYe_VXP4cOM?CuMrp{J&+p(i%B;kgTv&0pGGK+4*=0q$pk3GI2#lH)#>qQEF>cc_$Gn1 zH=We{sX?nTX)T`_$rl>Q*+ZS$#(Pbd+REbw(I1h?>$VYt!S&A77QV{i&XBCrC5{+a z2JIwM7cdtUiVf2pY6nue>{Pv+`KwpMN6W|<==eSVD?aNvhn^W z6nhvUF=4x7yH2Z%Sv2UO(u|rS(SJ4q%2@%LHQSRc@?pfH#1bmP_I^bux+avI*HqT!(kFV6ccqW z^GFOE>~IEI@CvV?j_upOeYqV?V!Q{UR}3dd77IJjc$ZA)c{1LP$_J6EWVIYM(uLf` z5}^W#@yB!vrckhF;pm4>F1GQorCAO!90|+nn18h$oaPz~7p&VT4b44U8`GG(@AF5A zr{Q3xvOIMvvsS)$Deo|Acm!Bhr^E8xLH zZ5L%A_E4nlpU*XO=x!F_p=7!%+Nt%AXbl_m*f%DE!$}b_u}Nt(2O`)B_nDPDvG|dU zX&EScrB-1wUo0`|6<{(d;;7_nKO>1D!^#Zvyuw?-7JP=y^C5Fy5mTgLd3WskYJ0*! z8A>ZEQMfh(+h@uCSZjpZR-!mm*l`D6^>xl5o1}U*_t~^PB`db!s++k!P!kd>H9aohj@CBS6m@cAy7icPq;B+bD#=w~Fq#diYG7+7wDQ zxsKC`Y0gllvR5us+G}KoG3YpHXCgo{U^U(FpNC(zDKg*Tg@8c5*oTYS=ic?dbc7c$ zwo0kWuJMG&#ddsnsls2gBOx_(iU*=oBILQ;9YkZc-2CImox2z!Aq!#2n2hdd@mS=G zXbQY`vvS>g6$8N$1vK)mDNWlG|YG)^4Q7vZCnYcfd`YjiWTx z_@O1@TY)56;}L1)7SPZQw6Q(Q@z4nKgxRHCyy7Za`c1W3UmCkgtDil%2m}>9lsH_p zOV4_SFCH&Y?tqwsEJ>VqDXtuyJ||DM9S9;SQ54}d;2*sP{$x}l9v`da^XbTFtnE4~ z8(PE*Y)G$*MoGL`hk0m%CY69BUF9h9l$Yd2XUAsJ&>k{6GsWQ)CaM{RVDuXivp-2B z@sExqf3i?jFWW48HA>&?J_zA6&R5#E{`J4Sr`|HdFpqe;@Vl>GllmmXa75mXxK&AR zXIQa@jJc^|CW0(x(~c6ci+sVNY&?#HW%cy17T*E=-cq)DpeSQ_ByM=f0Muud?)2mKu2;p9-X(N%72j#l_o$2lX^S_YIgIjiYZ$JdKM%wRzKuTU^|X zCoD7w9qVg(m+0WvZLy%lnFxAv1VXG`CS%%mqR{U+J1>9$>)qz(5*zQ=YQ#UR&P%&W z?M+sRf1IMSd>~CmvxFVU;v@l88J8rJ5Y%lsD~-qbq^3vi(rN|Wf=hoTVEkjSgR6-W z*7(6{<0>x3K+R$rUd}xvKamoF6we7juG6^6GoxV$ zta9NUKNRozDnu35KzUilA;!#3vL)N>Wz(`r)t%MDD9i9nOBUY=)wu@W{IH?_Tuom- zyyaCA^MK)M0|}|Y0_&GM%|a4{ua|U599dJFg_T#R8F(QW)IQaOsV(5}D%t67^P_|l z?XU#nAap!dNjl2cc#0E`YA@&71kTRl({0{yJQvpk(WQ|ix)Nk~=Y0qL?)}U<-us!u z@_zK*Q|#AWkcT=;n%f_<*JZ29WSYfei}$6J#+yV#MR!(;ws}P-s&!N2)V|ZglH=p^ z>hJ8jwKuDJ^>WV<^I(l<70yWS&}?ZRrmf!;%km~leHW@PqaE;rm5kv$Txk?d?htt({bH&k6)? z+?I>Qd$;sR$u@*lhjSS186&#Tl9>!F_6Sw(jS+Nt$ zr@OR))#Tft*@FwP_2n@KYPk|2TNRJ&v|lib7DVY47v_;D45T0x!v&4F(+|}8 zs0P~0^f~lQ9!$KKDpzA}Q`x!s7=mSzqAFcHu4K87en*!1n=D^tXqv~nTjXR)VZt(R zrflT|b%wSf}E)Qwc`D@0Ud+AsY z(M{p=+%b6IbA>lfY9CLmwKfu)lmgl)GS%68SO5`@Zxm~?@BP{)|A_lf1~;*;aYvi? zVe;K~x&_?m;g;%$w&`YBRC$?{zeT$Y*uO*Dm>Th0v`mBik=pgiwx5Us-)48=^!mr* z%P|k4as0`L{<`oxKR>6x@U#EYbMNHrw10MT_M!{lNV%Y(aqr~W@V z?TP+B?eu!@$2@J+sW9&8vr=()+!W~5+{Nq4%Y@<15DC!%ldO%^Ok{QH8F?)(`nFQ?Q zv@626!@xc>mnVdeB6%SQQA;2D#n}GNfWp77+ZG7BMG-T|Z{J8-x{0AeG1Jo`UrDwB z0`!qp%mfOI-w&KrF~ia8qzUnYf|mF84S&d&)hM6G^kyyGRDKM??ynvEr6SpDxwV@} zcr{pl?JUMK7!ls-egs{}{c$de9!#XTE%` zbsY8_CEo^4pcvu(-4f%9bQ|wy!JAyPHU&W~-aUiyT+m_a^HyIa*8vRD|E{0E7C&Dn z3uH&_gJ682R|yG{k_aw*EQd)>3n>wAvQ;n zEq}JHZn~{ml@F}CPwYO%{-ECQXGoA)KWK{iPY^Lr-#x3cVe;T1_)%oq2MaDvklSX- zM6|fwK!@L^*0hAe<(Ozd$1PfNbs-qvfim$|DT-T`v3I2yI=o*j2~Sv z9)^=89#IcNakY3fEb|l()vO_)F#I?l!5xg8}C&op1Uq2uI5|1h|w>`bU_+KoB zSc`lJlI#|6i|JZ1comKm{JzYEro!uGy=eRkUVJg;cV%PIg-oQgl8ZE9ZbX=dxj0B} zxiRk|GE4{aC66URSCaAPMS>wEpzxrpPt*xU_eJ*y5c1@^Vol+f6EF7m2`T$zg2wL5C&tX4%*7wR;zD&pHP(Cf<2wh34 zS(JHQyAtXFR>`wxUb}Cp8bnOU1C!*^n$xJ{BC)=*60{m(DSs6v9z9<2MspJYrn}Y! zxMT5o14wE?6I6Z1m%sw*J6<2&VhyZ1F}Vi#OfpRlY*y&7Q7Ol zW2?7;y9K^x&&vdjpBVJC+6_7k-oJ1da~njwJBUF8jOp%ZeBK0NcQih4LIbbrdH=lVoJ{^DgdTefjyibDLd3j2I&@7VnL+8UMxzd@0yoFj^?K+tnt6}@8;9B` zO8@y!@6!9%zkE;B%KrYn?`^Bn#{EA(E&ub#`;^t8U4_anV-qX021#EQqn0<*1BkAY zF%OtzNqImzMei#g%GfJ41_{R(!u#jH%v2tw^J>PUa8ec5wP^w;5SGOu$hj#!WEp(+ zC%AAglCZ+7?lsiO^3`*x915rtA;NV7K9ug$zZGxqJBK8DH+ z@WOx;*VPmM83Jp>q!?Xcfor-_z%tcyZAebTyG+!tBv(-X&zCY%0eVBy4bhZ%w0$vq zw3;QOnKz9yx>^b&9ndYS9v;{ObrM&%yMP(xc`;5hjMadWlH8x{DcxX1oQ#*`Zj6+x zF#*dfv=%F7N=?R4;qo|>H{-qO;;4X1xjM% zp+hVzMwTfo4dqS1d}(2G7@jsBC!oEeIv%AV%TMxAy9PUT^b3Zf3NAJXN71Y%$+SYT zXWHF#iGkxEMTJ;9xy1RdLRpR{7PZWu!Ez1vaf6NEnh@6;fY4TmsT*EgpX0bi;D|_3JVo?3+s}b zpAYR~N zklO9&e;)N9wi@A-J@=G5yUH9~LLiDnrv{niM$?v7l7E9u47^#0uscPWx)f#AhYw(- zD*ng7IkD6^=KCzY^Vs1SkKLUOqB2unmLN(s6m{uYQCzZHeyeL|9LEcMV6A9*z0PJa zg6=CVJh#y9**&#LZu1JKaW)70(XjNPHcoFy2yBLAb9CSUgPOG{>Qrbb*F|GI{BFl$ zOaj)TzqE#74=tYH7!lAFBNu$6T)VinI_TDWHefhe93G7-+F9>-$If(%ATI7FLovd6 z) zUf+VwV|wx#nhw5*=blAmRIo+Xo|d&&&svu#S65>gGD9eH)doP(wJw0%6Zlray{q)Z zbEV9?14!YcmOTn!Lg_QZY|lO8i?u#8B+(>I8eT`2e7M<+(05b@T5=LooW!>yoWqF!AHuBbT=3QD_P1zUBiF|6 z)OzLjAutbn#D)4ZPUN+Fme?|DD8dE72lY^~t&4CD*X$RRMOuiqtr_3XVh>kgw4Wih z=7?KVcJ8{}7gN7U&rzGXoOy&nv1Om)pa1gzsqIN9$gp$BCz*eB^l9g0f-9L(oTiLm_<%IaSJzxOgjGet_GGS|TOh-Dnq>cE zv;M!lPfPE=L9G|>2psbKH?I+~*k#j$`8LH_7#EWf%tt={ZPCW&0RPeVKtz^1y}5^n zhwruBcyYZK+W0Vk2ht7Rzr)R@zIy^|_qw|7O6$ryTvB%3`OWMUiHjnBW1KEnfc9#G zPGzwG;^MIn>iwOzRxmv3+kN5Ah5oyD==Rvr#RPUyyW2VMp7(kV2T{M@Iq9CCp1?eS zs%*E@KkuIP0&;2V@Q;4C^Vw(p{%0~z_r;5sutGrZx}eb+uy2pFxS(LMKzn~3m`!4c zJ|9pXs=C*Id2;?)@9ez$+39Joe|oO_o3{NmZr%3@1$e|_b)H%yaW&eLV%1(7mk4mq zF&J*Km^3jP&yJhIZq^L6IG+G!O|BPRu?5+4?bPEoHTOo)x|JLm1$^vc5xIsJ1Ly*2 zPEii}SM(5^qgK${5wR{nIHvpA+4;*CJ((MLu=nz;|MF$`tPX$y>7T!RdG@k~UAd18R*4!(7x&3DP;jVdpsjPV7tuTGqdH| zQ1UgDRDpm77&%chlz`y`+lv7r@B10e^1Q@rX-61a-{*e?stLx?qAzlfjr=I0G{x_= z5kYZ@7xWJ@xfHkp$N;0yEU*Pf+Hk6GsS2mF1@l+4wnghsVy0rFrTa%;qecYN;voZe zh=D7YkcmQBa=eb}5{TvQWYi+@LM@YYF}CVspEhQ=JM(AqatSDISRo z1btU3V7(n80X;3$ljz>M!vATZ^9;_Az-Jil4s`^m-#r>yb-y7 zA*84*KcVv>`gma8mUMawE*hN$YX=(Vaal%F+5*-UaHf?C__ZCMz&bL?7ag}zs#jo~ zUt;GnZjDg#++V7td)h$``hMT3a56?<|umOMQ+HI*{d8cJUon=J3&NUK>UCu(hH z(4QGanaQe|08}Qhec>u}nU@rANVtTUDP(M9n%Gh4m~)Q)0;^E?-zuqQ-lt=fxfu(8_G$S! z&LN0A)3lhN{E|pOVse9UY%y%1ILGq~Ojqjip$;kAnXQM%bS(`7f0K#?c^f%r1VmS7(nUd9kp*`8t zRz~4I_1ZimD(Fa0_&%(b4DhtXt_xPlpArPQw7R`nMgMdhLY>KPB^3qjzfEpH?}atR zc=ry#;}D_fg=H)r+0l!7SJ+k5`@;dS)<2ksgeJ>c?>#jUInx<-LTJFF5tBMfM`5J+ z%Q2v}b-fAk85Ur=%NE9X%4b`KrKY#c%c8@#~ci9^hiLp7$9`6m*=!kw?H9^DJlwE=?o=uT)>B|35$*j^Jc!q6G%j+2~n=@WhIdBmsSLI1xG={@hU7qXsB^P5b}FMgAtar6Xxg zF6Ab~ZYS8#^;Z|yW-6z$$W-cwvmb*ySgouQlTDl)A`7Ys-Y#ISB$;hkbJU$L>j&mZ zO#mPq2BQCKvhX(pC!~^FHl3i&ubf&Iy(QYu8N_FpwWA+jQ>#}((Y1DMcGq$<=~EU? zu0y9K&t7=5C>w)f%T7-w*|g2A?#L&2XmOlOCUJqs|5njm#|7_8$QZ9FrZ)`Biu_0L zOe9_|oOy4TfZII&8J_XzK%RNoaTlX0fjT{Rfx~UgI2yBam_@$AQZ)|lc;365$VE%T zS?q!|jxnxxhSyL-GsU$vkvCi>Y1PJK8rWt>n>f8y$1s~JJ7CHxefUU|{6?qvjMI(W zu_>gjjV&h|MWhI&qnQ&MUosmL+52LdjUelN732_i;ac8`{~Z_6Dx8Dron-Yn&8%Zb zg_!{3AfX2ZFwfr0!J7sMyJ~C6f2Rwa;MXPKm>ZYH=;X`s*{-vX$)+GnOh3k=dz8@Fa!{C28j~R0GM$b@c0mQ$3 z@g4y(z{hxmRENn|Ud$i^x!=F~QOn%xcFpY2%_IS%VS+beh$H7ySVu$QH*a749RBe3 z`@g;V+t=TI{r>+2NSz*o@X8xTWkQl{G>b^hV~W87SQ5BBww|A*K(gb)e}U0!cRt~Xe|)x0o#-h zNj>nPr6!d-n>YKIY(07xS7J-9GhcMZi<0)FW^|MGk=Q{qlwV%*b(GT@;V;ZNL?eQaaC(@8)-g+K)21))k7Qj&KYc z0afSuc$tz#b|kH{cxGU?bL^j%cnBZ;%LHTNbKtVJ;>{@UF!+!aT*W4YtFkumwbelZavRq_{0S^x4j`akDJq zU3YI8q&m08*<7%@h0SdUx*o?Jm%NRuoHgmluqbSsiw#@H7G!nZUFHi)qemTAq$$b^ zD=a25A-?HXw~`%AhI*ky zk##`@>tyj+nFfkP0rM`S&)7og)%Cn*^yTWY`chkOA;dZ?bLoXAe0+>gx;C8;x_EdI z{YTwy2P-|mF?!Uvl`Z4sENkYUjwiU=ER}HjEp2SNqg#jq3RidE2==;VTVojfI1)!v z76RX){$&_w3tWA-HBH7!)Ny6pjKygx_RJ8))@n?Z=ZduzIl(Lpywcx#xZ*O#pkpk+ zSS+H9GXO`f!?aPF`i(fctN0?qNFanZ3zoq`fY`Mf^_i_jrA2EkeGKWN7McRzZTbZ@ z5@}^wT#0Q58(yU;r-yc~fsXJXkQ$9N_?<<*@B^G_*qpJgCYB2gpGasHq(bWtlRW$) z%wJ=(#ZB|Sk%ip%<_|$R~s7^LQB)tP+=Rsd_o;lF}*f_=Uz?(($*JtGG+k6Bi@9H8*u_@|E9f z;T%t+otroUYF?jrpO@% zzpH9D@;Fd}I=VRkqBw5&~|@hM*^xtz^-8SagCB^`i++NnacGHPA6h>OVsijk3T$Fiz{H3+D7 z-3tO5b!$+B<+IsNsuPiJ5b*>f>3ZmdeHD`eyK2N4t3^^ z1@-lF4=*LYdfvlGD%b8N; z>Z~u;L>D&{VL0YCF$EN6K>J&tn~oclWryw4Nr2jJ^bTY4DZANwSK91~iaYeDrWH`I zM04dO=;_ktO&^4vcPbl*iV<^A55fop7)pvgdCT9}=4>u7^Zw=E_B97_P z%e{J{3F?Zriy6?BZaXsvz2$jw-;wV?p~=|ulnr>MC6sj|P+dc4)#l-rdy;b?>Xe_Y zy38>QcknqZN3$4rX}BJ|6IKm$a^u>7+GZFE;T8syV@H|>c#V#I*}TCtg>yjjq89oQ7LH zht7ag3?3I17&5_bl|+vrcID{zZKGjVw%E)cM))3s?Q|Zp3Q;&(SDTT#f-1?<2Ax|I|ZK}#&)@88OX zaDRWC#&)&FrtzeytxrJ+E97D zL!8jC8!XZ+ZBVy~juD3x!kHuQ6mXH!;;8n*st|gv7+7vgyuB{xRm;N9J*`15J)K}1iy9jwr!8|$ zZc;oAQ!oQg`<=Q~*hLOq@M9ow49W(1oO_$t6=YOvc|3>+4hOt}#Bi0pX!ovlgltKz z_ATr3exlz!P1BFE;yDDqvCqg&FU--99l)JqoC*B{_Zze?I;geW++M70Ey5U{vCw9^ z80l&aT4psVg2eLIVvvTRHadfr1BYO<4$fr>;$cc>v6bZ#&TMwOn#v72L_*?vtur0) z8}NI~?&ko-XoUCZvBTs^wpdoQQHW8gi#xveY1e`osMUP8465UcNmtEks{O|@BAb_U zw$*3YKlFt9`)s19ZW51} zM_*-zEC!!jt$0TqQ0JkvDEkjA+?&GR@7%GJ8GZG1E|4AYMo^0-l9Mf`_T zZPM*l%S=&{S?6|6er8OAe(Bu>O^1UJrcl~Z5vjU?MPLT=1DH5}cU8VW6Q7F6QM_M@ z#vo6nM4}J#Ez^>V5Yw%a!daGub1BHe93}~}?*{GJ7M6HmG*&*X<@r`Ef*(*3$TX$u zUj3o^77z29Bs=({)yU7@6~$LooV5+#Cu!v=?r}zYcQ?F|4sLK)yIyRR?A(pA2x1GI zwXm%aaT}kobP}0(2k3$N##XQv|Msm&L_~BO1ec(+ep8}tP4se1^~zGsa6_awV&#s%-h#cR6pO z+UQxl+6aG&sLTDNl%=!yslRu*hi5uUtM3_DIB`;jLrtxwlE}-V;5h!1h!mgWIHgSh zku4)074zO;{giDLBmTs^F>}%cMHk7|qWa1bt5EBELOmiLKbV}^@xHZ=vEYqD{o|ql zhJ}lrffhdn!6uhJS@6O50pznsvmKnnZDs?s{^{&}q4e3Yp~56a9T@X>+c!K=)LUM- zz$8O%+Qa+jQmiDcUKfgvHd$_IbkjQ#Tt9BIHAeESc$ov?IA*|UJqoYGG;`owk(}9$LDr2pmcf}tBvrq8 zZG>X4s-derVynJc+(e^VDI~4CPL3ruVBej;nAwkl*j2Tc-w&9ti(=P$n%k^M)ZPJ-Cl{Wmq$5g1uIlDj2aF*xCtB< zcA4z-1C0gjnx-~8LtCz^Pd&}M4M)-?|7h8J;JJM){ZDIaAKh3N+iq=hippm{{BF7p z0_J$9Ea+UL!Oxdu;0@m9j^*ds*7Xk(>`fk_sSAeK4@vlu$ZKzLYV2G-{w859Wwi~R^f3#v;6z!TMAP;Og59WM!LGp%ds6LaaN{HqT zt9C6TN{Gh8j_PS{@kTOjt}DKWJ2EGi>*1KpP$BDJgGTcwVF*8K3lq6Ib29BXg*o$J zrxmlM_N@FQe}zzrk7Jta9GiII4STSSCb*nSym}5>)dgoT!HyZica4`Nv*?~KOD9u| z;{gqh?k|+H>m4WtRSGpEe$4RbVkLASoE7O`LMaDTvf}d?Wp=(b_G8jL=(i~IsBHSZ z{>0wbqb4Gw7{E+VmkoQE5lIiCq^K3be%QsQ-aK5n?J1jbIZIU$@>*t3uODDQiFzD@ zB1$T8sF?u6Qkl0k!p&@sQ99>BViSl^Nj4|sneRvLM@VW6 zc?hZ}S81oY?J{+=>up*9ix1}D@JOxVkfS8`oXJ6`MeC^TlMduZroIw^-I25TM5<%s>e44xm3D#$uX7GxgptF`g_e-8D zm4{vuJC=rCS+`7+gLq>G_b0yL`*jbyoS?jivKP3OkM|`nF=ROuvvb+(68VEROlK)N40}tC$B#N3`5#i{8lr5RcJ42XCi!8s4 z)vryMx&eD4x#MjI=#H!pD+8gw!oRhI5FxFmGU~?x&|B-saq0bb$E+8Nrt{ORk3wHd zd$ROy!t6NSgaLP&&QJ&w*81eCCR{*O@feJ($$qNqe0=W%RN=%rs15!Pw$4c9oqqiWD!N~3tj^ZlkpZZsdz0q#<%QG!~)O|9Gl_caY zTVviaNsk?IdDhCpoL(;_FiR7ONm6{?76Hn9I5o_$JfA!1m3~x2b)F8lj~#)A6)|DTvrHjuogQ=DDz@(9ZC0<&o8zKf*>Nu}EA z$HLNDiafqS3M2}~6tG`2Pi7Gc1c8CxK+#rxC7=Lo@g7bcTsbQEv3<4l6Kr9`hA%-~ zl2s)p^tfpT@?@v8O85hv5mo%2&q%Rnb}friP4mk74&ob>&7SPLcD~rTl^)if^r57Q zi%}!pyoae;iUlIVkm^V7ZGO}FF;y%jinL$9!}Zg}<^^^kICSZXPo8SGfNNh^%47R) zdZ$n`T1A+;N{Da1lVd|bj34P8ZT?f2_-EM1-`5Z$5aQsj?VU>;_R{9c^fQaJFZ(067VtZL=lE*$@$shEVrZdo;Yg%5L| zC#KOB&Go6u_VQkE;xI>huf321hCb&$DQVRrg^JWun`NSGP{Eqnc7!6bJz^RG3Wr3hWg3@Uo9tdhS7=(w$GyGY%L>D|I3CX1GGW~^ z$uHekD8>6;oxZNfM|EXnn2O}(eBq#BSXa2BdcV=7l0m6GBvd->Q??iTh`DrkmZkiX z@Qx>xXp>ppdfqWA$Z3NPcG*W6O(wF_OMan`v*)l2T89yuu0n;qX}B{m(kFz? zEWhEv4T9G!HnUk~Gb@jvOE~U96V~xK!r9*3?V}T`H`0UnNSCj9ZM2AO(Y+FutO9Et z+27o2&v!~+Ov*bFWh9KQLd_$l5BY&hxFCZO_!`|q{3N?m9T5WndPrfAs3L?#rGnH# z6QG&rrf}-dd0e@DR|%;ArR8#6Y5yUP{V_6#Ax2A@{;23!9Yw-x_Jz$N=3IsXB^en& zG(Q#YK-s{37B>96M!k!;C}#ak41s?-!823}VmU;6*}=QeAS{`{?+W5aJki;r6;QNM zEahv1qyu;G*~m+qJtV_0llK+fhQ|st&EAd!S~k<=Z?RQoxUjm=g^aISw!Iz|wX_yh z5YNdMiKj}SB&!wW+z#lK)T+;mxSW8}SX54NVqa1Y+DR2If~PfiIzYor2t)exNsq=&!zxT3bK@SbkcHnCk`LWP~COOVAC@n zutzWV%5VFxzOa?~OQoa7!k#D%Iz3E1DlkTO6p_|(-cIW;^Je0Y{qD^D@caqrYOym7 zAPvc3%dgpb9$diS=ARRjb3W2|D6|h!td<1Q6MF&Fr0#SYZv*IodS`|M%L=wcO>W|G zU&#BVgvKm|E8fQVvl!P=CxOb#J4CzbirDb!BsBmhv>m(Go$wr~(XVT?FC1J+9u5#; z=VN;V>p{Xag&vVF$lhxfI+<_N*2d*~tf{Eq3EO)BG2eQT^0<2p!cAQn(>r@Z8zmDL zd>0dBkSi4eg&b+cmj*0=Nq`$C?jxkvQ$_wcij*WCta8C7GuBelZ&vbdR*ffXvBkIZ ze%)upD-Bn@T|OasH#)jwpzrXQZOFe=b68OP$%P>(LO+-8vRdFk@11ErN7m?F4lYQG zf6D|FM0B=z!&>7D@2K4L)#GmFUx7SZy*ZnZ`QNj&N`I}u&IWWMRpHZIj@udiG-3{bdCiZ%tbHHtqUfk{ELv79-r*^W;Jh zyky~jMORkwFfSmOJL!$`e_(B&8KxRTJ{3C?KcaP@(rWRiELE0^jay5{OZ?LoId1%Z zkoW9rIGD46Ne|cg&1eGNETfbqAhAh+sE@|zKl>0bz|Ki^1>c2X znIx0OFB6@S(A5h+^wf-udMSBid;rqId5&f<5`VV%!|R>pbV#OsPNk7cvo7N-@ZS;} z8_mV_ie($cY$XAVB={{5PH`tpSh)$rx!6i5zRZ4@u-EX8`;ygdMbSk zU$DN!2jWhZmA7|q3h*7m)d)H%6ns4s>kfh`nR3jnht6FGc_Ok2%73tcAHgvO*XIMO z_q1m+EYR&XZvJ_y-Z&ACGTd|&I)TZ;-xGDq>h^1f zkO02W#W@WB-GB!u$S__C!(pDv31R!Fjgx->NAH>0!8-uh&49(m$`0P8{XB0|R|kJQjE)LguewKr_^mVMhZ#7>WOs$>3?k?4;Sfoh4RhFFy3ly^hk1L z)fm%*Qc?s~0xr)gX4>WFYYGLnfCE>Rp6>ZFYwpoQwQ9Qt;a$5y_B>6E3ULA4#cS*+ j9acoaP9`V5?aGZXN5K8}i}D7RK&kn|s+FjbnCO219Kkg) literal 0 HcmV?d00001 diff --git a/analysis-master/dist/analysis-1.0.0.8-py3-none-any.whl b/analysis-master/dist/analysis-1.0.0.8-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..83d5cb968fdb50f333025e6373172553d91df843 GIT binary patch literal 20459 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 Z{&)Yo|K0!Ye;@Gg{{uiF_T2zz0RRUFw=Vzy literal 0 HcmV?d00001 diff --git a/analysis-master/dist/analysis-1.0.0.9-py3-none-any.whl b/analysis-master/dist/analysis-1.0.0.9-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..24f78782f4be9579653b2260cea98482394d1c8f GIT binary patch literal 20332 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