Created
July 17, 2025 08:17
-
-
Save betatim/b090bf44e68e86b4e5d14bd5664f8088 to your computer and use it in GitHub Desktop.
Associate log output with the (top level) line of a script. Makes it easier to know which log messages where output while a particular line was running. Try it with `python -m log_tracer -o traced_output.txt log-test.py`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import logging | |
import time | |
# Configure logging | |
logging.basicConfig( | |
level=logging.INFO, | |
format='%(asctime)s - %(levelname)s - %(message)s', | |
handlers=[ | |
logging.FileHandler('calculations.log'), | |
logging.StreamHandler() | |
] | |
) | |
logger = logging.getLogger(__name__) | |
def calculate_statistics(data): | |
""" | |
Calculate basic statistics of a numpy array and log the results. | |
""" | |
logger.info(f"Starting statistics calculation for data with shape {data.shape}") | |
try: | |
mean_val = np.mean(data) | |
std_val = np.std(data) | |
min_val = np.min(data) | |
max_val = np.max(data) | |
logger.info(f"Statistics calculated successfully:") | |
logger.info(f" Mean: {mean_val:.4f}") | |
logger.info(f" Standard deviation: {std_val:.4f}") | |
logger.info(f" Min: {min_val:.4f}") | |
logger.info(f" Max: {max_val:.4f}") | |
return { | |
'mean': mean_val, | |
'std': std_val, | |
'min': min_val, | |
'max': max_val | |
} | |
except Exception as e: | |
logger.error(f"Error calculating statistics: {e}") | |
raise | |
def matrix_operations(matrix_a, matrix_b): | |
""" | |
Perform matrix operations and log the process. | |
""" | |
logger.info(f"Starting matrix operations with shapes: A={matrix_a.shape}, B={matrix_b.shape}") | |
try: | |
# Matrix multiplication | |
logger.debug("Performing matrix multiplication...") | |
result_mult = np.dot(matrix_a, matrix_b) | |
logger.info(f"Matrix multiplication completed. Result shape: {result_mult.shape}") | |
# Matrix addition | |
logger.debug("Performing matrix addition...") | |
result_add = matrix_a + matrix_b | |
logger.info(f"Matrix addition completed. Result shape: {result_add.shape}") | |
# Calculate determinant | |
logger.debug("Calculating determinant...") | |
det_a = np.linalg.det(matrix_a) | |
det_b = np.linalg.det(matrix_b) | |
logger.info(f"Determinants calculated: A={det_a:.4f}, B={det_b:.4f}") | |
return { | |
'multiplication': result_mult, | |
'addition': result_add, | |
'det_a': det_a, | |
'det_b': det_b | |
} | |
except np.linalg.LinAlgError as e: | |
logger.error(f"Linear algebra error: {e}") | |
raise | |
except Exception as e: | |
logger.error(f"Error in matrix operations: {e}") | |
raise | |
def polynomial_fitting(x_data, y_data, degree=2): | |
""" | |
Fit a polynomial to data points and log the fitting process. | |
""" | |
logger.info(f"Starting polynomial fitting with degree {degree}") | |
logger.info(f"Data points: {len(x_data)}") | |
try: | |
# Fit polynomial | |
logger.debug("Fitting polynomial coefficients...") | |
coefficients = np.polyfit(x_data, y_data, degree) | |
logger.info(f"Polynomial coefficients: {coefficients}") | |
# Calculate R-squared | |
y_pred = np.polyval(coefficients, x_data) | |
ss_res = np.sum((y_data - y_pred) ** 2) | |
ss_tot = np.sum((y_data - np.mean(y_data)) ** 2) | |
r_squared = 1 - (ss_res / ss_tot) | |
logger.info(f"R-squared value: {r_squared:.4f}") | |
return { | |
'coefficients': coefficients, | |
'r_squared': r_squared, | |
'y_predicted': y_pred | |
} | |
except Exception as e: | |
logger.error(f"Error in polynomial fitting: {e}") | |
raise | |
def random_simulation(samples=1000, seed=42): | |
""" | |
Perform a random simulation and log the results. | |
""" | |
logger.info(f"Starting random simulation with {samples} samples") | |
try: | |
# Set random seed | |
np.random.seed(seed) | |
logger.debug(f"Random seed set to {seed}") | |
# Generate random data | |
logger.debug("Generating random normal data...") | |
data = np.random.normal(0, 1, samples) | |
# Generate random matrix | |
logger.debug("Generating random matrix...") | |
matrix = np.random.rand(5, 5) | |
# Calculate some statistics | |
logger.debug("Calculating simulation statistics...") | |
stats = calculate_statistics(data) | |
logger.info("Random simulation completed successfully") | |
logger.info(f"Generated {samples} random samples and 5x5 matrix") | |
return { | |
'data': data, | |
'matrix': matrix, | |
'statistics': stats | |
} | |
except Exception as e: | |
logger.error(f"Error in random simulation: {e}") | |
raise | |
def performance_benchmark(func, *args, iterations=100): | |
""" | |
Benchmark a function's performance and log the results. | |
""" | |
logger.info(f"Starting performance benchmark for {func.__name__}") | |
logger.info(f"Running {iterations} iterations...") | |
try: | |
start_time = time.time() | |
for i in range(iterations): | |
if i % 20 == 0: # Log progress every 20 iterations | |
logger.debug(f"Progress: {i}/{iterations} iterations completed") | |
result = func(*args) | |
end_time = time.time() | |
total_time = end_time - start_time | |
avg_time = total_time / iterations | |
logger.info(f"Benchmark completed:") | |
logger.info(f" Total time: {total_time:.4f} seconds") | |
logger.info(f" Average time per iteration: {avg_time:.6f} seconds") | |
logger.info(f" Iterations per second: {iterations/total_time:.2f}") | |
return { | |
'total_time': total_time, | |
'avg_time': avg_time, | |
'iterations_per_second': iterations/total_time, | |
'result': result | |
} | |
except Exception as e: | |
logger.error(f"Error in performance benchmark: {e}") | |
raise | |
if __name__ == "__main__": | |
logger.info("Starting calculation test script") | |
# Test the functions | |
# Generate some test data | |
x = np.linspace(0, 10, 100) | |
y = 2 * x**2 + 3 * x + 1 + np.random.normal(0, 0.5, 100) | |
# Test statistics calculation | |
stats_result = calculate_statistics(y) | |
# Test matrix operations | |
matrix_a = np.random.rand(3, 3) | |
matrix_b = np.random.rand(3, 3) | |
matrix_result = matrix_operations(matrix_a, matrix_b) | |
# Test polynomial fitting | |
poly_result = polynomial_fitting(x, y, degree=2) | |
# Test random simulation | |
sim_result = random_simulation(samples=500) | |
# Test performance benchmark | |
benchmark_result = performance_benchmark(calculate_statistics, sim_result['data'], iterations=50) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import logging | |
import sys | |
from collections import defaultdict | |
from contextlib import contextmanager | |
import runpy | |
import traceback | |
class LineTracer: | |
""" | |
A tool to trace log messages to specific lines of code execution. | |
""" | |
def __init__(self, script_path, output_path): | |
self.script_path = script_path | |
self.output_path = output_path | |
self.current_line = None | |
self.line_logs = defaultdict(list) | |
self.original_trace = None | |
self.original_excepthook = None | |
with open(script_path, 'r') as f: | |
self.script_lines = f.readlines() | |
def setup_tracing(self): | |
"""Setup line-by-line tracing using sys.settrace.""" | |
self.original_trace = sys.gettrace() | |
sys.settrace(self.trace_function) | |
def setup_logging_patch(self): | |
"""Patch Logger.handle to always call our handler for every log record.""" | |
class TracerHandler(logging.Handler): | |
def __init__(handler_self, tracer): | |
super().__init__() | |
handler_self.tracer = tracer | |
def emit(handler_self, record): | |
msg = handler_self.format(record) | |
if handler_self.tracer.current_line is not None: | |
handler_self.tracer.line_logs[handler_self.tracer.current_line].append(msg) | |
self._tracer_handler = TracerHandler(self) | |
fmt = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') | |
self._tracer_handler.setFormatter(fmt) | |
self._original_logger_handle = logging.Logger.handle | |
tracer_handler = self._tracer_handler | |
def handle_patch(logger, record): | |
tracer_handler.handle(record) | |
return self._original_logger_handle(logger, record) | |
logging.Logger.handle = handle_patch | |
def restore_logging_patch(self): | |
"""Restore the original Logger.handle method.""" | |
if hasattr(self, '_original_logger_handle'): | |
logging.Logger.handle = self._original_logger_handle | |
def restore_tracing(self): | |
"""Restore original tracing.""" | |
if self.original_trace: | |
sys.settrace(self.original_trace) | |
def clean_traceback(self, exc_type, exc_value, exc_traceback): | |
"""Clean up traceback to remove tracer infrastructure.""" | |
if exc_traceback: | |
# Remove traceback lines added due to us using runpy | |
tb = exc_traceback | |
while tb and (tb.tb_frame.f_code.co_filename.endswith('log_tracer.py') or | |
'runpy' in tb.tb_frame.f_code.co_filename): | |
tb = tb.tb_next | |
if tb: | |
# Use the internal colorised function, could be fragile :-/ | |
new_exc = exc_type(exc_value) | |
new_exc.__traceback__ = tb | |
traceback._print_exception_bltin(new_exc) | |
return | |
# Fallback to original | |
traceback.print_exception(exc_type, exc_value, exc_traceback) | |
def trace_function(self, frame, event, arg): | |
"""Trace function for sys.settrace.""" | |
if event == 'line': | |
# Only track lines from our script at top-level | |
if (frame.f_code.co_filename.endswith(self.script_path) and | |
frame.f_code.co_name == '<module>'): | |
self.current_line = frame.f_lineno | |
return self.trace_function | |
@contextmanager | |
def trace_execution(self): | |
"""Context manager to trace execution and capture logs.""" | |
self.setup_tracing() | |
self.setup_logging_patch() | |
try: | |
yield | |
finally: | |
self.restore_logging_patch() | |
self.restore_tracing() | |
self.write_output() | |
def write_output(self): | |
"""Write the traced output to file.""" | |
with open(self.output_path, 'w') as f: | |
for line_num in range(1, len(self.script_lines) + 1): | |
if line_num in self.line_logs: | |
line_content = self.script_lines[line_num - 1].rstrip() | |
f.write(f"{line_content}\n") | |
for log_record in self.line_logs[line_num]: | |
f.write(f"LOG:{log_record}\n") | |
else: | |
line_content = self.script_lines[line_num - 1].rstrip() | |
f.write(f"{line_content}\n") | |
def trace_script_execution(script_path, output_path): | |
""" | |
Trace the execution of a script and capture log messages for each line. | |
Args: | |
script_path: Path to the script to trace | |
output_path: Path to write the output file | |
""" | |
script_path = os.path.abspath(script_path) | |
tracer = LineTracer(script_path, output_path) | |
with tracer.trace_execution(): | |
try: | |
runpy.run_path(script_path, run_name='__main__') | |
except Exception as e: | |
tracer.clean_traceback(type(e), e, e.__traceback__) | |
sys.exit(1) | |
def main(): | |
"""Main function for command line usage.""" | |
import argparse | |
parser = argparse.ArgumentParser(description='Trace script execution and capture logs per line') | |
parser.add_argument('script', help='Path to the script to trace') | |
parser.add_argument('-o', '--output', default='traced_output.txt', | |
help='Path to write the output file (default: traced_output.txt)') | |
args = parser.parse_args() | |
trace_script_execution(args.script, args.output) | |
if __name__ == "__main__": | |
main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import logging | |
import time | |
# Configure logging | |
logging.basicConfig( | |
level=logging.INFO, | |
format='%(asctime)s - %(levelname)s - %(message)s', | |
handlers=[ | |
logging.FileHandler('calculations.log'), | |
logging.StreamHandler() | |
] | |
) | |
logger = logging.getLogger(__name__) | |
def calculate_statistics(data): | |
""" | |
Calculate basic statistics of a numpy array and log the results. | |
""" | |
logger.info(f"Starting statistics calculation for data with shape {data.shape}") | |
try: | |
mean_val = np.mean(data) | |
std_val = np.std(data) | |
min_val = np.min(data) | |
max_val = np.max(data) | |
logger.info(f"Statistics calculated successfully:") | |
logger.info(f" Mean: {mean_val:.4f}") | |
logger.info(f" Standard deviation: {std_val:.4f}") | |
logger.info(f" Min: {min_val:.4f}") | |
logger.info(f" Max: {max_val:.4f}") | |
return { | |
'mean': mean_val, | |
'std': std_val, | |
'min': min_val, | |
'max': max_val | |
} | |
except Exception as e: | |
logger.error(f"Error calculating statistics: {e}") | |
raise | |
def matrix_operations(matrix_a, matrix_b): | |
""" | |
Perform matrix operations and log the process. | |
""" | |
logger.info(f"Starting matrix operations with shapes: A={matrix_a.shape}, B={matrix_b.shape}") | |
try: | |
# Matrix multiplication | |
logger.debug("Performing matrix multiplication...") | |
result_mult = np.dot(matrix_a, matrix_b) | |
logger.info(f"Matrix multiplication completed. Result shape: {result_mult.shape}") | |
# Matrix addition | |
logger.debug("Performing matrix addition...") | |
result_add = matrix_a + matrix_b | |
logger.info(f"Matrix addition completed. Result shape: {result_add.shape}") | |
# Calculate determinant | |
logger.debug("Calculating determinant...") | |
det_a = np.linalg.det(matrix_a) | |
det_b = np.linalg.det(matrix_b) | |
logger.info(f"Determinants calculated: A={det_a:.4f}, B={det_b:.4f}") | |
return { | |
'multiplication': result_mult, | |
'addition': result_add, | |
'det_a': det_a, | |
'det_b': det_b | |
} | |
except np.linalg.LinAlgError as e: | |
logger.error(f"Linear algebra error: {e}") | |
raise | |
except Exception as e: | |
logger.error(f"Error in matrix operations: {e}") | |
raise | |
def polynomial_fitting(x_data, y_data, degree=2): | |
""" | |
Fit a polynomial to data points and log the fitting process. | |
""" | |
logger.info(f"Starting polynomial fitting with degree {degree}") | |
logger.info(f"Data points: {len(x_data)}") | |
try: | |
# Fit polynomial | |
logger.debug("Fitting polynomial coefficients...") | |
coefficients = np.polyfit(x_data, y_data, degree) | |
logger.info(f"Polynomial coefficients: {coefficients}") | |
# Calculate R-squared | |
y_pred = np.polyval(coefficients, x_data) | |
ss_res = np.sum((y_data - y_pred) ** 2) | |
ss_tot = np.sum((y_data - np.mean(y_data)) ** 2) | |
r_squared = 1 - (ss_res / ss_tot) | |
logger.info(f"R-squared value: {r_squared:.4f}") | |
return { | |
'coefficients': coefficients, | |
'r_squared': r_squared, | |
'y_predicted': y_pred | |
} | |
except Exception as e: | |
logger.error(f"Error in polynomial fitting: {e}") | |
raise | |
def random_simulation(samples=1000, seed=42): | |
""" | |
Perform a random simulation and log the results. | |
""" | |
logger.info(f"Starting random simulation with {samples} samples") | |
try: | |
# Set random seed | |
np.random.seed(seed) | |
logger.debug(f"Random seed set to {seed}") | |
# Generate random data | |
logger.debug("Generating random normal data...") | |
data = np.random.normal(0, 1, samples) | |
# Generate random matrix | |
logger.debug("Generating random matrix...") | |
matrix = np.random.rand(5, 5) | |
# Calculate some statistics | |
logger.debug("Calculating simulation statistics...") | |
stats = calculate_statistics(data) | |
logger.info("Random simulation completed successfully") | |
logger.info(f"Generated {samples} random samples and 5x5 matrix") | |
return { | |
'data': data, | |
'matrix': matrix, | |
'statistics': stats | |
} | |
except Exception as e: | |
logger.error(f"Error in random simulation: {e}") | |
raise | |
def performance_benchmark(func, *args, iterations=100): | |
""" | |
Benchmark a function's performance and log the results. | |
""" | |
logger.info(f"Starting performance benchmark for {func.__name__}") | |
logger.info(f"Running {iterations} iterations...") | |
try: | |
start_time = time.time() | |
for i in range(iterations): | |
if i % 20 == 0: # Log progress every 20 iterations | |
logger.debug(f"Progress: {i}/{iterations} iterations completed") | |
result = func(*args) | |
end_time = time.time() | |
total_time = end_time - start_time | |
avg_time = total_time / iterations | |
logger.info(f"Benchmark completed:") | |
logger.info(f" Total time: {total_time:.4f} seconds") | |
logger.info(f" Average time per iteration: {avg_time:.6f} seconds") | |
logger.info(f" Iterations per second: {iterations/total_time:.2f}") | |
return { | |
'total_time': total_time, | |
'avg_time': avg_time, | |
'iterations_per_second': iterations/total_time, | |
'result': result | |
} | |
except Exception as e: | |
logger.error(f"Error in performance benchmark: {e}") | |
raise | |
if __name__ == "__main__": | |
logger.info("Starting calculation test script") | |
LOG:2025-07-16 18:15:36,631 - INFO - Starting calculation test script | |
# Test the functions | |
# Generate some test data | |
x = np.linspace(0, 10, 100) | |
y = 2 * x**2 + 3 * x + 1 + np.random.normal(0, 0.5, 100) | |
# Test statistics calculation | |
stats_result = calculate_statistics(y) | |
LOG:2025-07-16 18:15:36,661 - INFO - Starting statistics calculation for data with shape (100,) | |
LOG:2025-07-16 18:15:36,661 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,661 - INFO - Mean: 83.0020 | |
LOG:2025-07-16 18:15:36,661 - INFO - Standard deviation: 68.7736 | |
LOG:2025-07-16 18:15:36,661 - INFO - Min: 0.0573 | |
LOG:2025-07-16 18:15:36,662 - INFO - Max: 231.1586 | |
# Test matrix operations | |
matrix_a = np.random.rand(3, 3) | |
matrix_b = np.random.rand(3, 3) | |
matrix_result = matrix_operations(matrix_a, matrix_b) | |
LOG:2025-07-16 18:15:36,662 - INFO - Starting matrix operations with shapes: A=(3, 3), B=(3, 3) | |
LOG:2025-07-16 18:15:36,662 - INFO - Matrix multiplication completed. Result shape: (3, 3) | |
LOG:2025-07-16 18:15:36,662 - INFO - Matrix addition completed. Result shape: (3, 3) | |
LOG:2025-07-16 18:15:36,662 - INFO - Determinants calculated: A=0.0595, B=0.0822 | |
# Test polynomial fitting | |
poly_result = polynomial_fitting(x, y, degree=2) | |
LOG:2025-07-16 18:15:36,662 - INFO - Starting polynomial fitting with degree 2 | |
LOG:2025-07-16 18:15:36,662 - INFO - Data points: 100 | |
LOG:2025-07-16 18:15:36,663 - INFO - Polynomial coefficients: [1.99126391 3.09489698 0.81678548] | |
LOG:2025-07-16 18:15:36,663 - INFO - R-squared value: 0.9999 | |
# Test random simulation | |
sim_result = random_simulation(samples=500) | |
LOG:2025-07-16 18:15:36,663 - INFO - Starting random simulation with 500 samples | |
LOG:2025-07-16 18:15:36,663 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,663 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,663 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,663 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,664 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,664 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,664 - INFO - Random simulation completed successfully | |
LOG:2025-07-16 18:15:36,664 - INFO - Generated 500 random samples and 5x5 matrix | |
# Test performance benchmark | |
benchmark_result = performance_benchmark(calculate_statistics, sim_result['data'], iterations=50) | |
LOG:2025-07-16 18:15:36,664 - INFO - Starting performance benchmark for calculate_statistics | |
LOG:2025-07-16 18:15:36,664 - INFO - Running 50 iterations... | |
LOG:2025-07-16 18:15:36,664 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,664 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,664 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,664 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,664 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,665 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,665 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,665 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,665 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,665 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,665 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,665 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,665 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,665 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,665 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,665 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,665 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,666 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,666 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,666 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,666 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,666 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,666 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,666 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,666 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,666 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,667 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,667 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,667 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,667 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,667 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,667 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,667 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,667 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,667 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,667 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,668 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,668 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,668 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,668 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,668 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,668 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,668 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,668 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,668 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,668 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,669 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,669 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,669 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,669 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,669 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,669 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,669 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,669 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,669 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,669 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,669 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,670 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,670 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,670 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,670 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,670 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,670 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,670 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,670 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,670 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,670 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,670 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,670 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,671 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,671 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,671 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,671 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,671 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,671 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,671 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,671 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,671 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,671 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,671 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,671 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,672 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,672 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,672 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,672 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,672 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,672 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,672 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,672 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,672 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,672 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,672 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,672 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,673 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,673 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,673 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,673 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,673 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,673 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,673 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,673 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,673 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,673 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,673 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,673 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,674 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,674 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,674 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,674 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,674 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,674 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,674 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,674 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,674 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,674 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,674 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,674 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,675 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,675 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,675 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,675 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,675 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,675 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,675 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,675 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,675 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,675 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,675 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,675 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,676 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,676 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,676 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,676 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,676 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,676 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,676 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,676 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,676 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,676 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,676 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,677 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,677 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,677 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,677 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,677 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,677 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,677 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,677 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,677 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,677 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,677 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,677 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,678 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,678 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,678 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,678 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,678 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,678 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,678 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,678 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,678 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,678 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,678 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,678 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,679 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,679 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,679 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,679 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,679 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,679 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,679 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,679 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,679 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,679 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,679 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,679 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,680 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,680 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,680 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,680 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,680 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,680 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,680 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,680 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,680 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,680 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,680 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,680 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,681 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,681 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,681 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,681 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,681 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,681 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,681 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,681 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,681 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,681 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,681 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,681 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,682 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,682 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,682 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,682 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,682 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,682 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,682 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,682 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,682 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,682 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,682 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,682 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,683 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,683 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,683 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,683 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,683 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,683 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,683 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,683 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,683 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,683 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,683 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,683 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,684 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,684 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,684 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,684 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,684 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,684 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,684 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,684 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,684 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,684 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,684 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,684 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,685 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,685 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,685 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,685 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,685 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,685 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,685 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,685 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,685 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,685 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,685 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,685 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,686 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,686 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,686 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,686 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,686 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,686 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,686 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,686 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,686 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,686 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,686 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,687 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,687 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,687 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,687 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,687 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,687 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,687 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,687 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,687 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,687 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,688 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,688 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,688 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,688 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,688 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,688 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,688 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,688 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,688 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,688 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,688 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,689 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,689 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,689 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,689 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,689 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,689 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,689 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,689 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,689 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,689 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,689 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,690 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,690 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,690 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,690 - INFO - Starting statistics calculation for data with shape (500,) | |
LOG:2025-07-16 18:15:36,690 - INFO - Statistics calculated successfully: | |
LOG:2025-07-16 18:15:36,690 - INFO - Mean: 0.0068 | |
LOG:2025-07-16 18:15:36,690 - INFO - Standard deviation: 0.9803 | |
LOG:2025-07-16 18:15:36,690 - INFO - Min: -3.2413 | |
LOG:2025-07-16 18:15:36,690 - INFO - Max: 3.8527 | |
LOG:2025-07-16 18:15:36,690 - INFO - Benchmark completed: | |
LOG:2025-07-16 18:15:36,690 - INFO - Total time: 0.0262 seconds | |
LOG:2025-07-16 18:15:36,690 - INFO - Average time per iteration: 0.000524 seconds | |
LOG:2025-07-16 18:15:36,691 - INFO - Iterations per second: 1907.82 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment