diff --git a/analysis/analysis.ipynb b/analysis/analysis.ipynb new file mode 100644 index 0000000..131dea5 --- /dev/null +++ b/analysis/analysis.ipynb @@ -0,0 +1,442 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import json\n", + "\n", + "import matplotlib.pyplot as plt\n", + "from dataclasses import dataclass\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [], + "source": [ + "this_dir = os.path.dirname(os.path.abspath(''))\n", + "# results is in \"../results\"\n", + "results_dir = os.path.join(this_dir, \"results\")" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [], + "source": [ + "experiment_folder = \"casestudy_example\"\n", + "experiment_name = \"cs_example_edf\"\n", + "\n", + "experiment_file = os.path.join(results_dir, experiment_folder, experiment_name + \".json\")\n", + "if not os.path.exists(experiment_file):\n", + " print(\"Experiment file not found: \", experiment_file)" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [], + "source": [ + "with open(experiment_file) as f:\n", + " experiment_data_raw = json.load(f)" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7146948, 'on_time': 1, 'time_diff': -73, 'periods_late': 0, 'thread_id': 1}, 'time': 0.000127}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7146948, 'on_time': 1, 'time_diff': 0, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0002}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7147048, 'on_time': 1, 'time_diff': -71, 'periods_late': 0, 'thread_id': 1}, 'time': 0.000229}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7147148, 'on_time': 1, 'time_diff': -157, 'periods_late': 0, 'thread_id': 0}, 'time': 0.000243}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7147048, 'on_time': 1, 'time_diff': 0, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0003}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7147148, 'on_time': 1, 'time_diff': -57, 'periods_late': 0, 'thread_id': 1}, 'time': 0.000343}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7147248, 'on_time': 1, 'time_diff': -100, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0004}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7147248, 'on_time': 1, 'time_diff': -57, 'periods_late': 0, 'thread_id': 0}, 'time': 0.000443}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7147348, 'on_time': 1, 'time_diff': -100, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0005}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7147348, 'on_time': 1, 'time_diff': -57, 'periods_late': 0, 'thread_id': 1}, 'time': 0.000543}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7147448, 'on_time': 1, 'time_diff': -100, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0006}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7147448, 'on_time': 1, 'time_diff': -57, 'periods_late': 0, 'thread_id': 0}, 'time': 0.000643}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7147548, 'on_time': 1, 'time_diff': -100, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0007}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7147648, 'on_time': 1, 'time_diff': -157, 'periods_late': 0, 'thread_id': 1}, 'time': 0.000743}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7147548, 'on_time': 1, 'time_diff': 0, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0008}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7147648, 'on_time': 1, 'time_diff': -57, 'periods_late': 0, 'thread_id': 0}, 'time': 0.000843}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7147748, 'on_time': 1, 'time_diff': -100, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0009}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7147848, 'on_time': 1, 'time_diff': -157, 'periods_late': 0, 'thread_id': 0}, 'time': 0.000943}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7147748, 'on_time': 1, 'time_diff': 0, 'periods_late': 0, 'thread_id': 1}, 'time': 0.001}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7147948, 'on_time': 1, 'time_diff': -157, 'periods_late': 0, 'thread_id': 0}, 'time': 0.001043}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7147848, 'on_time': 1, 'time_diff': 0, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0011}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7147948, 'on_time': 1, 'time_diff': -70, 'periods_late': 0, 'thread_id': 1}, 'time': 0.00113}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7148048, 'on_time': 1, 'time_diff': -157, 'periods_late': 0, 'thread_id': 0}, 'time': 0.001143}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7148048, 'on_time': 1, 'time_diff': -100, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0012}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7148148, 'on_time': 1, 'time_diff': -157, 'periods_late': 0, 'thread_id': 1}, 'time': 0.001243}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7148148, 'on_time': 1, 'time_diff': -100, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0013}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7148248, 'on_time': 1, 'time_diff': -157, 'periods_late': 0, 'thread_id': 1}, 'time': 0.001343}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7148248, 'on_time': 1, 'time_diff': -100, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0014}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7148348, 'on_time': 1, 'time_diff': -157, 'periods_late': 0, 'thread_id': 0}, 'time': 0.001443}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7148348, 'on_time': 1, 'time_diff': -100, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0015}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7148448, 'on_time': 1, 'time_diff': -157, 'periods_late': 0, 'thread_id': 0}, 'time': 0.001543}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7148448, 'on_time': 1, 'time_diff': -100, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0016}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7148548, 'on_time': 1, 'time_diff': -170, 'periods_late': 0, 'thread_id': 0}, 'time': 0.00163}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7148648, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 1}, 'time': 0.001643}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7148548, 'on_time': 1, 'time_diff': -100, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0017}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7148648, 'on_time': 1, 'time_diff': -157, 'periods_late': 0, 'thread_id': 0}, 'time': 0.001743}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7148748, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0018}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7148848, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 1}, 'time': 0.001843}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7148748, 'on_time': 1, 'time_diff': -100, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0019}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7148948, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 1}, 'time': 0.001943}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7148848, 'on_time': 1, 'time_diff': -100, 'periods_late': 0, 'thread_id': 0}, 'time': 0.002}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7148948, 'on_time': 1, 'time_diff': -157, 'periods_late': 0, 'thread_id': 1}, 'time': 0.002043}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7149048, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0021}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7149048, 'on_time': 1, 'time_diff': -157, 'periods_late': 0, 'thread_id': 0}, 'time': 0.002143}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7149148, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0022}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7149148, 'on_time': 1, 'time_diff': -157, 'periods_late': 0, 'thread_id': 1}, 'time': 0.002243}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7149248, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0023}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7149248, 'on_time': 1, 'time_diff': -157, 'periods_late': 0, 'thread_id': 0}, 'time': 0.002343}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7149348, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0024}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7149348, 'on_time': 1, 'time_diff': -170, 'periods_late': 0, 'thread_id': 1}, 'time': 0.00243}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7149448, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 0}, 'time': 0.002443}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7149448, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0025}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7149548, 'on_time': 1, 'time_diff': -256, 'periods_late': 0, 'thread_id': 1}, 'time': 0.002544}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7149548, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0026}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7149648, 'on_time': 1, 'time_diff': -259, 'periods_late': 0, 'thread_id': 1}, 'time': 0.002641}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7149648, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0027}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7149748, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 1}, 'time': 0.002743}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7149748, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0028}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7149848, 'on_time': 1, 'time_diff': -256, 'periods_late': 0, 'thread_id': 1}, 'time': 0.002844}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7149848, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0029}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7149948, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 0}, 'time': 0.002943}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7149948, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 1}, 'time': 0.003}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7150048, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 1}, 'time': 0.003043}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7150048, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0031}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7150148, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 0}, 'time': 0.003143}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7150148, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0032}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7150248, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 0}, 'time': 0.003243}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7150248, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0033}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7150348, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 0}, 'time': 0.003343}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7150348, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0034}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7150448, 'on_time': 1, 'time_diff': -270, 'periods_late': 0, 'thread_id': 0}, 'time': 0.00343}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7150548, 'on_time': 1, 'time_diff': -357, 'periods_late': 0, 'thread_id': 1}, 'time': 0.003443}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7150448, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0035}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7150548, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 0}, 'time': 0.003543}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7150648, 'on_time': 1, 'time_diff': -300, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0036}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7150748, 'on_time': 1, 'time_diff': -357, 'periods_late': 0, 'thread_id': 0}, 'time': 0.003643}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7150648, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0037}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7150748, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 1}, 'time': 0.003743}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7150848, 'on_time': 1, 'time_diff': -300, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0038}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7150948, 'on_time': 1, 'time_diff': -358, 'periods_late': 0, 'thread_id': 1}, 'time': 0.003842}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7150848, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0039}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7150948, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 0}, 'time': 0.003943}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7151048, 'on_time': 1, 'time_diff': -300, 'periods_late': 0, 'thread_id': 1}, 'time': 0.004}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7151148, 'on_time': 1, 'time_diff': -356, 'periods_late': 0, 'thread_id': 1}, 'time': 0.004044}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7151048, 'on_time': 1, 'time_diff': -200, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0041}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7151148, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 0}, 'time': 0.004143}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7151248, 'on_time': 1, 'time_diff': -300, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0042}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7151248, 'on_time': 1, 'time_diff': -257, 'periods_late': 0, 'thread_id': 0}, 'time': 0.004243}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7151348, 'on_time': 1, 'time_diff': -300, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0043}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7151348, 'on_time': 1, 'time_diff': -270, 'periods_late': 0, 'thread_id': 1}, 'time': 0.00433}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7151448, 'on_time': 1, 'time_diff': -357, 'periods_late': 0, 'thread_id': 0}, 'time': 0.004343}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7151448, 'on_time': 1, 'time_diff': -300, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0044}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7151548, 'on_time': 1, 'time_diff': -370, 'periods_late': 0, 'thread_id': 0}, 'time': 0.00443}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7151648, 'on_time': 1, 'time_diff': -457, 'periods_late': 0, 'thread_id': 1}, 'time': 0.004443}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7151548, 'on_time': 1, 'time_diff': -300, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0045}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7151648, 'on_time': 1, 'time_diff': -357, 'periods_late': 0, 'thread_id': 0}, 'time': 0.004543}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7151748, 'on_time': 1, 'time_diff': -400, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0046}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7151748, 'on_time': 1, 'time_diff': -357, 'periods_late': 0, 'thread_id': 1}, 'time': 0.004643}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7151848, 'on_time': 1, 'time_diff': -400, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0047}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7151848, 'on_time': 1, 'time_diff': -370, 'periods_late': 0, 'thread_id': 1}, 'time': 0.00473}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7151948, 'on_time': 1, 'time_diff': -457, 'periods_late': 0, 'thread_id': 0}, 'time': 0.004743}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7151948, 'on_time': 1, 'time_diff': -400, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0048}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7152048, 'on_time': 1, 'time_diff': -457, 'periods_late': 0, 'thread_id': 0}, 'time': 0.004843}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7152048, 'on_time': 1, 'time_diff': -400, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0049}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7152148, 'on_time': 1, 'time_diff': -457, 'periods_late': 0, 'thread_id': 0}, 'time': 0.004943}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7152148, 'on_time': 1, 'time_diff': -400, 'periods_late': 0, 'thread_id': 1}, 'time': 0.005}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7152248, 'on_time': 1, 'time_diff': -457, 'periods_late': 0, 'thread_id': 1}, 'time': 0.005043}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7152248, 'on_time': 1, 'time_diff': -400, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0051}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7152348, 'on_time': 1, 'time_diff': -457, 'periods_late': 0, 'thread_id': 0}, 'time': 0.005143}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7152348, 'on_time': 1, 'time_diff': -400, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0052}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7152448, 'on_time': 1, 'time_diff': -473, 'periods_late': 0, 'thread_id': 1}, 'time': 0.005227}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7152448, 'on_time': 1, 'time_diff': -400, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0053}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7152548, 'on_time': 1, 'time_diff': -456, 'periods_late': 0, 'thread_id': 0}, 'time': 0.005344}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7152548, 'on_time': 1, 'time_diff': -456, 'periods_late': 0, 'thread_id': 1}, 'time': 0.005344}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7152648, 'on_time': 1, 'time_diff': -457, 'periods_late': 0, 'thread_id': 1}, 'time': 0.005443}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7152648, 'on_time': 1, 'time_diff': -400, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0055}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7152748, 'on_time': 1, 'time_diff': -457, 'periods_late': 0, 'thread_id': 0}, 'time': 0.005543}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7152748, 'on_time': 1, 'time_diff': -400, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0056}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7152848, 'on_time': 1, 'time_diff': -457, 'periods_late': 0, 'thread_id': 1}, 'time': 0.005643}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7152848, 'on_time': 1, 'time_diff': -400, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0057}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7152948, 'on_time': 1, 'time_diff': -457, 'periods_late': 0, 'thread_id': 0}, 'time': 0.005743}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7152948, 'on_time': 1, 'time_diff': -400, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0058}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7153048, 'on_time': 1, 'time_diff': -457, 'periods_late': 0, 'thread_id': 0}, 'time': 0.005843}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7153048, 'on_time': 1, 'time_diff': -400, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0059}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7153148, 'on_time': 1, 'time_diff': -470, 'periods_late': 0, 'thread_id': 0}, 'time': 0.00593}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7153248, 'on_time': 1, 'time_diff': -557, 'periods_late': 0, 'thread_id': 1}, 'time': 0.005943}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7153148, 'on_time': 1, 'time_diff': -400, 'periods_late': 0, 'thread_id': 0}, 'time': 0.006}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7153248, 'on_time': 1, 'time_diff': -470, 'periods_late': 0, 'thread_id': 0}, 'time': 0.00603}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7153348, 'on_time': 1, 'time_diff': -557, 'periods_late': 0, 'thread_id': 1}, 'time': 0.006043}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7153348, 'on_time': 1, 'time_diff': -500, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0061}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7153448, 'on_time': 1, 'time_diff': -557, 'periods_late': 0, 'thread_id': 0}, 'time': 0.006143}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7153448, 'on_time': 1, 'time_diff': -500, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0062}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7153548, 'on_time': 1, 'time_diff': -563, 'periods_late': 0, 'thread_id': 1}, 'time': 0.006237}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7153548, 'on_time': 1, 'time_diff': -500, 'periods_late': 0, 'thread_id': 0}, 'time': 0.0063}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7153648, 'on_time': 1, 'time_diff': -560, 'periods_late': 0, 'thread_id': 0}, 'time': 0.00634}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7153648, 'on_time': 1, 'time_diff': -500, 'periods_late': 0, 'thread_id': 1}, 'time': 0.0064}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7153748, 'on_time': 1, 'time_diff': -557, 'periods_late': 0, 'thread_id': 1}, 'time': 0.006443}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7153748, 'on_time': 1, 'time_diff': -504, 'periods_late': 0, 'thread_id': 0}, 'time': 0.006496}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 0, 'deadline': 7146848}, 'time': 0.0}\n", + "Record: {'entry': {'operation': 'next_deadline', 'chain_id': 1, 'deadline': 7146848}, 'time': 0.0}\n", + "Number of records: 1542\n", + "First record: {'entry': {'operation': 'start_work', 'chain': 0, 'node': 'node_0', 'count': 500, 'next_release_us': 99910}, 'time': 0.0001}\n", + "Operation types: ['end_work', 'next_deadline', 'get_next_executable', 'wait_for_work', 'start_work']\n" + ] + } + ], + "source": [ + "def pre_process_data(data):\n", + " for record in data:\n", + " record[\"time\"] = int(record[\"time\"])\n", + "\n", + " min_time = min([record[\"time\"] for record in data])\n", + " for record in data:\n", + " record[\"time\"] -= min_time\n", + " record[\"time\"] /= (1000 * 1000)\n", + "\n", + " if record[\"entry\"][\"operation\"] == \"next_deadline\":\n", + " print(\"Record: \", record)\n", + " record[\"entry\"][\"deadline\"] = int(record[\"entry\"][\"deadline\"])\n", + " record[\"entry\"][\"deadline\"] -= min_time\n", + " record[\"entry\"][\"deadline\"] /= (1000 * 1000)\n", + "\n", + " # data = sorted(data, key=lambda x: x[\"time\"])\n", + " return data\n", + "\n", + "experiment_data = pre_process_data(experiment_data_raw)\n", + "\n", + "print(\"Number of records: \", len(experiment_data))\n", + "print(\"First record: \", experiment_data[0])\n", + "operation_types = list(set([record[\"entry\"][\"operation\"] for record in experiment_data]))\n", + "print(\"Operation types: \", operation_types)" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [], + "source": [ + "@dataclass\n", + "class Record:\n", + " start_time: float\n", + " end_time: float\n", + " node_name: str\n", + "\n", + "@dataclass\n", + "class RecordLine:\n", + " node_name: str\n", + " count: int\n", + "\n", + " def __eq__(self, other):\n", + " return self.node_name == other.node_name and self.count == other.count\n", + "\n", + " def __hash__(self):\n", + " return hash((self.node_name, self.count))\n", + "\n", + "def get_records(data) -> list[Record]:\n", + " # used to match start_work and end_work records\n", + " current_records: dict[RecordLine, Record] = {}\n", + " records = []\n", + " for record in data:\n", + " if record[\"entry\"][\"operation\"] == \"start_work\":\n", + " current_record = Record(start_time=record[\"time\"], node_name=record[\"entry\"][\"node\"], end_time=None)\n", + " current_record_line = RecordLine(node_name=record[\"entry\"][\"node\"], count=record[\"entry\"][\"count\"])\n", + " if current_record_line in current_records:\n", + " raise Exception(\"Overlapping records\")\n", + " current_records[current_record_line] = current_record\n", + " elif record[\"entry\"][\"operation\"] == \"end_work\":\n", + " current_record_line = RecordLine(node_name=record[\"entry\"][\"node\"], count=record[\"entry\"][\"count\"])\n", + " if current_record_line not in current_records:\n", + " raise Exception(\"No start record\")\n", + " current_record = current_records[current_record_line]\n", + " current_record.end_time = record[\"time\"]\n", + " records.append(current_record)\n", + " del current_records[current_record_line]\n", + " return records\n", + "\n", + "records = get_records(experiment_data)" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of nodes: 4\n" + ] + } + ], + "source": [ + "num_nodes = len(set([record.node_name for record in records]))\n", + "print(\"Number of nodes: \", num_nodes)" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "ea1129c959df4732a9cb712543ecf881", + "version_major": 2, + "version_minor": 0 + }, + "image/png": "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xYwZMw45Nnjw4F6eDQBAcTkhA7C8vDzKy8sLPQ0AgKJ0Qr4EDABA9wQgAEBiBCAAQGIEIABAYgQgAEBiBCAAQGIEIABAYgQgAEBiBCAAQGIEIABAYgQgAEBiBCAAQGIEIABAYgQgAEBiBCAAQGIEIABAYgQgAEBiBCAAQGIEIABAYgQgAEBiBCAAQGIEIABAYgQgAEBiBCAAQGIEIABAYgRgH5dlfX/scIpprtbfu2PFNh/r792xwymWuebrY3g4xbL+fI2RXwIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAwo9AbqXy0VkWfdjEYce72tjxTYf6y+esWKbj/X37lixzae7sXx9nc7HXPvSWHfj9AxnAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQAS02cCsL6+Pi666KJCTwMAoM/rMwHY095///24/vrro6ysLMrKyuL666+PX/ziF4WeFgBA3iUbgL/7u78bW7dujWeeeSaeeeaZ2Lp1a1x//fWFnhYAQN7lJQCnTJkSCxYsiMWLF0d5eXmMGDEi6uvrO8dbWlri6quvjmHDhkVpaWnMmDEj3nnnnS6PsXLlyqioqIjhw4fHnDlzYt++fQc9z5o1a6K6ujoGDRoUY8aMifvvv/+I5tfU1BTPPPNMPPTQQ1FXVxd1dXWxevXq+Md//Md47bXXjmvtAADFLm9nANeuXRtDhw6NTZs2xb333ht33313NDY2RpZlcc0118SePXtiw4YN0djYGM3NzTFz5szO+z722GOxdOnSWL58eWzZsiUqKysPirvVq1fHHXfcEcuXL4+mpqZoaGiIO++8M9auXXvYuf34xz+OsrKymDBhQudtl156aZSVlcWLL77Yc5sAAFCEBuTrgWtqamLp0qUREXHuuefGt771rfjBD34QERGvvPJKvPnmm1FVVRUREY888kicf/758ZOf/CQuueSSWLVqVdx4440xd+7ciIhYtmxZPPfcc13OAt5zzz1x3333xbXXXhsRESNHjozt27fHgw8+GLNnz/7Eub399ttx2mmnHXT7aaedFm+//Xa392tvb4/29vbO621tbUeyFQAARSVvZwBramq6XK+srIzdu3dHU1NTVFVVdcZfRMTYsWPj5JNPjqampoj4+CXaurq6Lvc/8Pq7774bO3fujDlz5sSwYcM6L8uWLYvm5uYjml8ulzvotizLDnn7fitWrOh800hZWVmXNQAA9BV5OwM4cODALtdzuVx0dHR0G1mHi68DdXR0RMTHLwMf+DJuRET//v0Pe/8RI0Yc9DOHER+HZUVFRbf3u/3222PRokWd19va2kQgANDn9Pq7gMeOHRstLS2xc+fOztu2b98era2tUV1dHRER1dXVsXHjxi73O/B6RUVFnHHGGbFjx44YPXp0l8vIkSMPO4e6urpobW2NzZs3d962adOmaG1tjYkTJ3Z7v5KSkigtLe1yAQDoa/J2BrA7U6dOjZqampg1a1asWrUqPvzww7jpppti8uTJUVtbGxERCxcujNmzZ0dtbW1MmjQp1q1bF9u2bYtRo0Z1Pk59fX0sWLAgSktLY/r06dHe3h5btmyJ999/v8tZukOprq6OadOmxZe//OV48MEHIyLiD/7gD+Lzn/98nHfeeflbPABAEej1M4C5XC6eeuqpOOWUU+Kyyy6LqVOnxqhRo+J73/te5zEzZ86Mu+66K5YsWRLjx4+Pt956K+bPn9/lcebOnRsPPfRQPPzwwzFu3LiYPHlyPPzww0d0BjAiYt26dTFu3Li48sor48orr4yampp45JFHenStAADFKJdlWVboSfRVbW1tUVZWFq2trXl5OTiXi+juo7P/xyUPNd7XxoptPtZfPGPFNh/r792xYptPd2P5+jqdj7n2pbHuxntCvr9/9wXJ/ksgAACpOiEDsKGhocuvhznwMn369EJPDwCgoHr9TSC9Yd68eTFjxoxDjg0ePLiXZwMAUFxOyAAsLy+P8vLyQk8DAKAonZAvAQMA0D0BCACQGAEIAJAYAQgAkBgBCACQGAEIAJAYAQgAkBgBCACQGAEIAJAYAQgAkBgBCACQGAEIAJAYAQgAkBgBCACQGAEIAJAYAQgAkBgBCACQGAEIAJAYAQgAkBgBCACQGAEIAJAYAQgAkBgBCACQGAEIAJAYAQgAkJgBhZ4A3cuydMeKbT7WXzxjxTYf6+/dsWKbj/X37hg9xxlAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIwD4ul+v7Y4dTTHO1/t4dK7b5WH/vjh1Oscw1Xx/DwymW9edrjPwSgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJ6TMBWF9fHxdddFGhpwEA0Of1mQDsaV/4whfirLPOikGDBkVlZWVcf/31sWvXrkJPCwAg75INwMsvvzwee+yxeO211+Lxxx+P5ubm+O3f/u1CTwsAIO/yEoBTpkyJBQsWxOLFi6O8vDxGjBgR9fX1neMtLS1x9dVXx7Bhw6K0tDRmzJgR77zzTpfHWLlyZVRUVMTw4cNjzpw5sW/fvoOeZ82aNVFdXR2DBg2KMWPGxP3333/Ec7z11lvj0ksvjbPPPjsmTpwYt912W2zcuDF+9atfHfO6AQD6grydAVy7dm0MHTo0Nm3aFPfee2/cfffd0djYGFmWxTXXXBN79uyJDRs2RGNjYzQ3N8fMmTM77/vYY4/F0qVLY/ny5bFly5aorKw8KO5Wr14dd9xxRyxfvjyampqioaEh7rzzzli7du1Rz3XPnj2xbt26mDhxYgwcOLDb49rb26Otra3LBQCgz8nyYPLkydmkSZO63HbJJZdkS5YsydavX5/1798/a2lp6Rzbtm1bFhHZ5s2bsyzLsrq6umzevHld7j9hwoTswgsv7LxeVVWV/e3f/m2XY+65556srq7uiOe5ePHibMiQIVlEZJdeemn23nvvfeLxS5cuzSLioEtra+sRP2dP+6SPYF8ZO5ximqv19+5Ysc3H+nt37HCKZa75+hgeTrGsP19j+dTa2lrw79+FlrczgDU1NV2uV1ZWxu7du6OpqSmqqqqiqqqqc2zs2LFx8sknR1NTU0RENDU1RV1dXZf7H3j93XffjZ07d8acOXNi2LBhnZdly5ZFc3PzEc/xT//0T+Pll1+O9evXR//+/eOGG26ILMu6Pf7222+P1tbWzsvOnTuP+LkAAIrFgHw98P99KTWXy0VHR0dkWRa5XO6g47u7/VA6Ojoi4uOXgSdMmNBlrH///kc8x1NPPTVOPfXU+PVf//Worq6Oqqqq2Lhx40HxuV9JSUmUlJQc8eMDABSjXn8X8NixY6OlpaXL2bPt27dHa2trVFdXR0REdXV1bNy4scv9DrxeUVERZ5xxRuzYsSNGjx7d5TJy5Mhjmtf+M3/t7e3HdH8AgL4ib2cAuzN16tSoqamJWbNmxapVq+LDDz+Mm266KSZPnhy1tbUREbFw4cKYPXt21NbWxqRJk2LdunWxbdu2GDVqVOfj1NfXx4IFC6K0tDSmT58e7e3tsWXLlnj//fdj0aJFnziHzZs3x+bNm2PSpElxyimnxI4dO+Kuu+6Kc845p9uzfwAAJ4pePwOYy+XiqaeeilNOOSUuu+yymDp1aowaNSq+973vdR4zc+bMuOuuu2LJkiUxfvz4eOutt2L+/PldHmfu3Lnx0EMPxcMPPxzjxo2LyZMnx8MPP3xEZwAHDx4cTzzxRFxxxRVx3nnnxY033hgXXHBBbNiwwUu8AMAJL5d90rse+ERtbW1RVlYWra2tUVpaWpA55HIR3X0E+8rY4RTTXK2/9/emmOZj/f5sHGosXx/DwymW9edrLJ+K4ft3oSX7L4EAAKTqhAzAhoaGLr8e5sDL9OnTCz09AICC6vU3gfSGefPmxYwZMw45Nnjw4F6eDQBAcTkhA7C8vDzKy8sLPQ0AgKJ0Qr4EDABA9wQgAEBiBCAAQGIEIABAYgQgAEBiBCAAQGIEIABAYgQgAEBiBCAAQGIEIABAYgQgAEBiBCAAQGIEIABAYgQgAEBiBCAAQGIEIABAYgQgAEBiBCAAQGIEIABAYgQgAEBiBCAAQGIEIABAYgQgAEBiBCAAQGIEYB+XZX1/7HCKaa7W37tjxTYf6+/dscMplrnm62N4OMWy/nyNkV8CEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDEDCj2BvizLsoiIaGtrK/BMAIAjtf/79v7v4ykSgMdh7969ERFRVVVV4JkAAEdr7969UVZWVuhpFEQuSzl/j1NHR0fs2rUrhg8fHrlc7qju29bWFlVVVbFz584oLS3N0wz7LvvTPXvTPXvTPXvTPXvTvRN1b7Isi71798bpp58e/fql+dNwzgAeh379+sWZZ555XI9RWlp6Qv2h6mn2p3v2pnv2pnv2pnv2pnsn4t6keuZvvzSzFwAgYQIQACAxArBASkpKYunSpVFSUlLoqRQl+9M9e9M9e9M9e9M9e9M9e3Pi8iYQAIDEOAMIAJAYAQgAkBgBCACQGAEIAJAYAXiM7r///hg5cmQMGjQoxo8fHz/60Y8+8fgNGzbE+PHjY9CgQTFq1Kj467/+64OOefzxx2Ps2LFRUlISY8eOjSeffPK4n7cQCrE3P/zhD+O3fuu34vTTT49cLhdPPfVUTy6pRxVif1asWBGXXHJJDB8+PE477bS45ppr4rXXXuvRdfWEQuzNAw88EDU1NZ2/6Lauri7++Z//uUfX1RMK9TVnvxUrVkQul4tbbrnleJfS4wqxN/X19ZHL5bpcRowY0aPr6gmF+rz5+c9/Hr/3e78Xn/rUp2LIkCFx0UUXxUsvvdRj66IHZBy1Rx99NBs4cGC2evXqbPv27dnChQuzoUOHZm+99dYhj9+xY0c2ZMiQbOHChdn27duz1atXZwMHDsz+/u//vvOYF198Mevfv3/W0NCQNTU1ZQ0NDdmAAQOyjRs3HvPzFkKh9ub73/9+dscdd2SPP/54FhHZk08+me+lHpNC7c9VV12VrVmzJnv11VezrVu3Zp/73Oeys846K/uf//mfvK/5SBVqb55++unsn/7pn7LXXnste+2117KvfvWr2cCBA7NXX30172s+UoXam/02b96cffrTn85qamqyhQsX5muZx6RQe7N06dLs/PPPz/7rv/6r87J79+68r/doFGpv9uzZk5199tnZ7//+72ebNm3K3nzzzey5557L3njjjbyvmSMnAI/BZz/72WzevHldbhszZkx22223HfL4xYsXZ2PGjOly2x/+4R9ml156aef1GTNmZNOmTetyzFVXXZV96UtfOubnLYRC7c2BijkAi2F/sizLdu/enUVEtmHDhqNdQt4Uy95kWZadcsop2UMPPXQ008+rQu7N3r17s3PPPTdrbGzMJk+eXHQBWKi9Wbp0aXbhhRce5+zzq1B7s2TJkmzSpEnHO33yzEvAR+mDDz6Il156Ka688sout1955ZXx4osvHvI+P/7xjw86/qqrrootW7bEr371q088Zv9jHsvz9rZC7U1fUUz709raGhER5eXlR72OfCiWvfnoo4/i0UcfjV/+8pdRV1d3rMvpUYXemz/6oz+Kz33uczF16tTjXUqPK/TevP7663H66afHyJEj40tf+lLs2LHjeJfUYwq5N08//XTU1tbGddddF6eddlpcfPHFsXr16p5YFj1IAB6l9957Lz766KOoqKjocntFRUW8/fbbh7zP22+/fcjjP/zww3jvvfc+8Zj9j3ksz9vbCrU3fUWx7E+WZbFo0aKYNGlSXHDBBce6nB5V6L356U9/GsOGDYuSkpKYN29ePPnkkzF27NjjXVaPKOTePProo/Hv//7vsWLFip5YSo8r5N5MmDAhvvvd78azzz4bq1evjrfffjsmTpwY//3f/90TSztuhdybHTt2xAMPPBDnnntuPPvsszFv3rxYsGBBfPe73+2JpdFDBhR6An1VLpfrcj3LsoNuO9zx//f2I3nMo33eQijU3vQVhd6fr3zlK/HKK6/Ev/7rvx7VvHtDofbmvPPOi61bt8YvfvGLePzxx2P27NmxYcOGoonAiN7fm507d8bChQtj/fr1MWjQoOOae74V4vNm+vTpnf8/bty4qKuri3POOSfWrl0bixYtOvpF5Ekh9qajoyNqa2ujoaEhIiIuvvji2LZtWzzwwANxww03HNtC6HHOAB6lU089Nfr373/Q36B279590N+K9hsxYsQhjx8wYEB86lOf+sRj9j/msTxvbyvU3vQVxbA/N998czz99NPx/PPPx5lnnnk8y+lRhd6bk046KUaPHh21tbWxYsWKuPDCC+Mv/uIvjndZPaJQe/PSSy/F7t27Y/z48TFgwIAYMGBAbNiwIf7yL/8yBgwYEB999FFPLfGYFfrz5kBDhw6NcePGxeuvv34sS+lxhdybysrKg/7yVF1dHS0tLce8HnqeADxKJ510UowfPz4aGxu73N7Y2BgTJ0485H3q6uoOOn79+vVRW1sbAwcO/MRj9j/msTxvbyvU3vQVhdyfLMviK1/5SjzxxBPxL//yLzFy5MieWFKPKbbPnSzLor29/WiXkReF2psrrrgifvrTn8bWrVs7L7W1tTFr1qzYunVr9O/fv6eWeMyK6fOmvb09mpqaorKy8liW0uMKuTe/8Ru/cdCvmfrP//zPOPvss495PeRBr73d5ASy/6313/nOd7Lt27dnt9xySzZ06NDsZz/7WZZlWXbbbbdl119/fefx+99af+utt2bbt2/PvvOd7xz01vp/+7d/y/r375+tXLkya2pqylauXNntr4Hp7nmLQaH2Zu/evdnLL7+cvfzyy1lEZH/+53+evfzyy0X1K3KyrHD7M3/+/KysrCx74YUXuvzaiv/93//tvcUfRqH25vbbb89++MMfZm+++Wb2yiuvZF/96lezfv36ZevXr++9xR9Gofbm/yrGdwEXam/++I//OHvhhReyHTt2ZBs3bsw+//nPZ8OHD/f1OPv41wYNGDAgW758efb6669n69aty4YMGZL9zd/8Te8tnsMSgMfor/7qr7Kzzz47O+mkk7LPfOYzXX6dxuzZs7PJkyd3Of6FF17ILr744uykk07KPv3pT2cPPPDAQY/5d3/3d9l5552XDRw4MBszZkz2+OOPH9XzFotC7M3zzz+fRcRBl9mzZ+djicelEPtzqL2JiGzNmjX5WOIxK8Te3HjjjZ3P+Wu/9mvZFVdcUVTxt1+hvuYcqBgDMMsKszczZ87MKisrs4EDB2ann356du2112bbtm3Ly/qOR6E+b/7hH/4hu+CCC7KSkpJszJgx2be//e0eXxvHJ5dl//8nPAEASIKfAQQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASMz/A2FKvAESEvRzAAAAAElFTkSuQmCC", + "text/html": [ + "\n", + "