From 024eb52a6989f494785514240407bda2f2428db1 Mon Sep 17 00:00:00 2001 From: fencl Date: Tue, 4 Nov 2025 13:50:38 +0100 Subject: [PATCH] init --- .gitignore | 13 + .gitlab-ci.yml | 30 ++ Dockerfile | 16 + Makefile | 44 ++ README.md | 30 ++ app.py | 440 +++++++++++++++++ docker-compose.yml | 9 + help.md | 148 ++++++ requirements.txt | 10 + scripts/create_mulog.py | 56 +++ scripts/utils.py | 139 ++++++ static/index.css | 399 ++++++++++++++++ static/pic/SWMU-logos_transparent.png | Bin 0 -> 47897 bytes static/pic/SWMU-logos_transparent2.png | Bin 0 -> 16453 bytes static/pic/SWMU-logos_transparent3.png | Bin 0 -> 28537 bytes static/pic/favicon.ico | Bin 0 -> 34494 bytes templates/helpswmu.html | 143 ++++++ templates/index.html | 24 + templates/index_v2.html | 636 +++++++++++++++++++++++++ templates/info.html | 51 ++ templates/mulog_read.html | 202 ++++++++ templates/test.html | 17 + uploads/.a | 0 23 files changed, 2407 insertions(+) create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 README.md create mode 100644 app.py create mode 100644 docker-compose.yml create mode 100644 help.md create mode 100644 requirements.txt create mode 100644 scripts/create_mulog.py create mode 100644 scripts/utils.py create mode 100644 static/index.css create mode 100644 static/pic/SWMU-logos_transparent.png create mode 100644 static/pic/SWMU-logos_transparent2.png create mode 100644 static/pic/SWMU-logos_transparent3.png create mode 100644 static/pic/favicon.ico create mode 100644 templates/helpswmu.html create mode 100644 templates/index.html create mode 100644 templates/index_v2.html create mode 100644 templates/info.html create mode 100644 templates/mulog_read.html create mode 100644 templates/test.html create mode 100644 uploads/.a diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8ffb5bd --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# Python +__pycache__ +*.pyc +*.pyo + +# .idea +*.iws +**/.idea/workspace.xml **/.idea/tasks.xml + +# virtual environment +/venv/ + + diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..770abb1 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,30 @@ +stages: + - buildimage + - checks + - tests + - deploytest + + +variables: + APP_IMAGE: gitlab.princip.cz:4567/$CI_PROJECT_PATH/app-$CI_COMMIT_REF_NAME + + +Build Application (docker) Image: + stage: buildimage + image: docker:git + before_script: + - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN gitlab.princip.cz:4567 + script: + - docker build -t $APP_IMAGE . + - docker push $APP_IMAGE + except: + - tags + + +Static Checks: + stage: checks + image: $APP_IMAGE + before_script: + - pip install flake8 + script: + - make pep8 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7748579 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM python:3.9 + +LABEL maintainer="Martin Fencl " + +RUN apt-get update -y && \ + apt-get dist-upgrade -y + +WORKDIR /app +COPY requirements.txt ./ + +RUN pip3 install --upgrade pip && \ + pip3 install -Ur requirements.txt -i https://pypi.princip.cz + +COPY . . + +CMD [ "python", "./app.py" ] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..20b58e0 --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ +# Makefile +help: + @echo "Please use 'make ' where is one of" + @echo " clean clean up __pycache__" + @echo " clean-build clean build files and directories" + @echo " mrproper all cleaning jobs" + @echo " pep8 to check PEP 8" + @echo " static-check to check PEP 8 and merge markers" + +clean: + @echo "-------------------" + @echo "Purifying 'pycache'" + @echo "-------------------" + rm -fv **/*.pyc + rm -fv **/*.pyo + +clean-build: + @echo "--------------" + @echo "Cleaning build" + @echo "--------------" + rm -rfv *.egg-info/ + rm -rfv dist/ + +mrproper: clean clean-build + +# pep8: +# @echo "--------------" +# @echo "Checking PEP" +# @echo "--------------" +# @echo "**pycodestyle**" +# pycodestyle . +# +# @echo "--------------" +# @echo "**flake8**" +# flake8 +pep8: + @echo "--------------" + @echo "**flake8**" + @echo "--------------" + flake8 app.py --exclude=migrations + flake8 scripts --exclude=migrations + +# static-check: pep8 merge-markers + diff --git a/README.md b/README.md new file mode 100644 index 0000000..0f30bd7 --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ + +# SWMU web +### Swmu project support web tool + +See: https://gitlab.princip.cz/lab/sw/uhura/swmu/-/wikis/home + +
+                                 _____  _    ____  ____   _              _     
+                                /  ___|| |  | |  \/  | | | |            | |    
+                                \ `--. | |  | | .  . | | | |_      _____| |__  
+                                 `--. \| |/\| | |\/| | | | \ \ /\ / / _ \ '_ \ 
+                                /\__/ /\  /\  / |  | | |_| |\ V  V /  __/ |_) |
+                                \____/  \/  \/\_|  |_/\___/  \_/\_/ \___|_.__/
+                                               O         O
+                                                \\     // 
+                                                 \\   //
+                                                  \\ // 
+                                                 /~~~~~\
+                                          ,-------------------,
+                                          | ,---------------, |
+                                          | |               | |
+                                          | |               | |
+                                          | |               | |
+                                          | |               | |
+                                          | |_______________| |
+                                          |___________________|
+                                          |___________________|
+
+ + diff --git a/app.py b/app.py new file mode 100644 index 0000000..9fb267e --- /dev/null +++ b/app.py @@ -0,0 +1,440 @@ +import os +import shutil + +import folium +import pandas as pd +from flask import Flask +from flask import request, render_template +from flask import send_from_directory, url_for, redirect +from werkzeug.utils import secure_filename + +from scripts import create_mulog + +print("version: 1.5") +ASSETS_DIR = os.path.dirname(os.path.abspath(__file__)) +app = Flask(__name__) + +# app.config['SECRET_KEY'] = '^%huYtFd90;90jjj' +# app.config['MULOGS'] = 'static' +app.config['MAX_CONTENT_LENGTH'] = 1024 * 1024 * 10 # 10mb +app.config['MAX_RECOMMENDED_POS'] = 10000 +app.config['UPLOAD_EXTENSIONS'] = ['.log'] +app.config['UPLOAD_PATH'] = 'uploads' +app.config['FILE_NAME'] = app.config['IGN1A'] = None + +questions = [] +counter_files = 0 + + +@app.route('/', methods=['GET', 'POST']) +@app.route("/home", methods=['GET', 'POST']) +def index(): + environment = request.host + clear = False + if request.method == 'POST': + if len(questions) > 20: + del questions[:1] + if request.form['submit_button'] == "Clear": + del questions[:] + return render_template('index_v2.html', questions=questions, + environment=environment, clear=True, + lenquestions=len(questions)) + elif request.form['submit_button'] == "Generate": + if request.form['modes'] == "None": + questions.append({ + 'loglevel': request.form['loglevels'], + 'id32': request.form['start-id32'], + 'number_swmu': request.form['number_of_swmu'], + 'mode': "None", # set default run mode + 'server_host': request.form['server_hosts'], + 'server_port': request.form['server_ports'], + 'start_port': request.form['start_ports'], + 'bt_spontaneous_timeout': request.form[ + 'bt_spontaneous_timeouts'], + 'sigma': request.form['sigmas'], + 'sta': request.form['stas'], + 'sta_pause': request.form['sta_pauses'], + 'ft_delay': request.form['ft_delays'], + 'ft_mode': request.form['ft_modes'], + }) + elif request.form['modes'] == "run": + questions.append({ + 'loglevel': request.form['loglevels'], + 'id32': request.form['start-id32'], + 'number_swmu': request.form[ + 'number_of_swmu'], + 'mode': request.form['modes'], + 'server_host': request.form['server_hosts'], + 'server_port': request.form['server_ports'], + 'start_port': request.form['start_ports'], + 'bt_spontaneous_timeout': request.form[ + 'bt_spontaneous_timeouts'], + 'sigma': request.form['sigmas'], + 'sta': request.form['stas'], + 'sta_pause': request.form['sta_pauses'], + 'ft_delay': request.form['ft_delays'], + 'ft_mode': request.form['ft_modes'], + 'latitude': request.form['latitudes'], + 'longitude': request.form['longitudes'], + 'domain': request.form['domains'], + 'near_by_domain': request.form['near_by_domains'], + 'x01': request.form['x01s'], + 'x01_pause': request.form['x01_pauses'], + 'units_wo_x1a': request.form['units_wo_x1as'], + 'x1a_pause': request.form['x1a_pauses'], + 'x1a_mask': request.form['x1a_masks'], + 'x1a_type': request.form['x1a_types'], + 'x1d': request.form['x1ds'], + 'x1d_pause': request.form['x1d_pauses'], + 'x1d_weight_axles': request.form['x1d_weight_axles'], + + }) + elif request.form['modes'] == "sim": + questions.append({ + 'loglevel': request.form['loglevels'], + 'id32': request.form['start-id32'], + 'number_swmu': request.form[ + 'number_of_swmu'], + 'mode': request.form['modes'], + 'server_host': request.form['server_hosts'], + 'server_port': request.form['server_ports'], + 'start_port': request.form['start_ports'], + 'bt_spontaneous_timeout': request.form[ + 'bt_spontaneous_timeouts'], + 'sigma': request.form['sigmas'], + 'sta': request.form['stas'], + 'sta_pause': request.form['sta_pauses'], + 'ft_delay': request.form['ft_delays'], + 'ft_mode': request.form['ft_modes'], + 'log': request.form['logs'], + 'sim_time_check': request.form['sim_time_checks'], + 'sim_stop': request.form['sim_stops'], + }) + elif request.form['modes'] == "simfast": + questions.append({ + 'loglevel': request.form['loglevels'], + 'id32': request.form['start-id32'], + 'number_swmu': request.form[ + 'number_of_swmu'], + 'mode': request.form['modes'], + 'server_host': request.form['server_hosts'], + 'server_port': request.form['server_ports'], + 'start_port': request.form['start_ports'], + 'bt_spontaneous_timeout': request.form[ + 'bt_spontaneous_timeouts'], + 'sigma': request.form['sigmas'], + 'sta': request.form['stas'], + 'sta_pause': request.form['sta_pauses'], + 'ft_delay': request.form['ft_delays'], + 'ft_mode': request.form['ft_modes'], + 'log': request.form['logs_simfast'], + 'sim_time_check': request.form['sim_time_checks_simfast'], + 'sim_stop': request.form['sim_stops'], + 'simulate_pause': request.form['simulate_pauses'], + }) + return render_template('index_v2.html', questions=questions, + environment=environment, clear=clear, + lenquestions=len(questions)) + + +@app.route('/info') +def info(): + environment = request.host + return render_template('info.html', environment=environment) + + +@app.route('/helpswmu') +def helpswmu(): + environment = request.host + return render_template('helpswmu.html', environment=environment) + + +""" +@app.route('/mulog_read') +def mulog_read(): + environment = request.host + return render_template('mulog_read.html', environment=environment) +""" + + +@app.route('/mulog_read') +def upload_file(): + environment = request.host + # environment_road = f"http://{environment}/uploader" # on local + environment_road = f"https://{environment}/uploader" + max_pos = app.config['MAX_RECOMMENDED_POS'] + files = listdir_nopos(app.config['UPLOAD_PATH']) + max_size = (app.config['MAX_CONTENT_LENGTH']) / (1024 * 1024) # in mb + ign1a = app.config['IGN1A'] + text = warn = "" + mulogt = [] + other_type_ttt = [] + pos_file = {'latitude': [], 'longitude': [], "msg_type": []} + x01 = x04 = x05 = x08 = x09 = x13 = x14 = x25 = x26 = x0b = 0 + x0d = x1a = x1c = x1d = x02 = x10 = x0e = ts_c = pos_c = 0 + if files: + try: + mulog_path = f"{app.config['UPLOAD_PATH']}/{files[0]}" + mulog_data = create_mulog.dir_mulog( + import_dir=mulog_path, sim_time_check=False) + + # (pos, log, ts_, type, pos) + for (count, message, old_ts, message_type, message_type_parse, + message_type_full_parse, list_ts_warning) in mulog_data: + warn = list_ts_warning + if message_type["type"] == b'\x01': + x01 += 1 + elif message_type["type"] == b'\x04': + x04 += 1 + elif message_type["type"] == b'\x05': + x05 += 1 + elif message_type["type"] == b'\x08': + x08 += 1 + elif message_type["type"] == b'\x09': + x09 += 1 + elif message_type["type"] == b'\x13': + x13 += 1 + elif message_type["type"] == b'\x14': + x14 += 1 + elif message_type["type"] == b'\x25': + x25 += 1 + elif message_type["type"] == b'\x26': + x26 += 1 + elif message_type["type"] == b'\x0b': + x0b += 1 + elif message_type["type"] == b'\x0d': + x0d += 1 + elif message_type["type"] == b'\x1a': + x1a += 1 + if ign1a == "False": + keys = [] + key_fast = message_type_full_parse["fastlog"] + for key in key_fast.keys(): + if key == "latitude": + keys.append(key) + elif key == "longitude": + keys.append(key) + if "latitude" and "longitude" in keys: + key_lat = key_fast["latitude"] + key_lon = key_fast["longitude"] + for lat in key_lat: + pos_file["latitude"].append(lat) + for lon in key_lon: + pos_file["longitude"].append(lon) + msg_type = message_type_parse["type"] + pos_file["msg_type"].append(msg_type) + pos_c += 1 + elif message_type["type"] == b'\x1c': + x1c += 1 + elif message_type["type"] == b'\x1d': + x1d += 1 + elif message_type["type"] == b'\x02': + x02 += 1 + elif message_type["type"] == b'\x10': + x10 += 1 + elif message_type["type"] == b'\n': + continue + elif message_type["type"] == b'"': + continue + elif message_type["type"] == b'#': + continue + elif message_type["type"] == b'\x0e': + x0e += 1 + else: + other_type_ttt.append(message_type["type"]) + + if old_ts is not None: + ts_c += 1 + if message_type["type"] != b'\x1a': + if "latitude" in message_type_parse and \ + "longitude" in message_type_parse: + lat = message_type_parse["latitude"] + lon = message_type_parse["longitude"] + msg_type = message_type_parse["type"] + pos_file["latitude"].append(lat) + pos_file["longitude"].append(lon) + pos_file["msg_type"].append(msg_type) + pos_c += 1 + + if not other_type_ttt: + other_type_ttt.append("None") + if pos_file is not []: + header_key = ["latitude", "longitude", "msg_type"] + df = pd.DataFrame(pos_file) + df.to_csv(f"{app.config['UPLOAD_PATH']}" + f"/{files[0]}_pos_file.csv", columns=header_key) + + mulogt.extend([x01, x04, x05, x08, x09, x13, x14, x25, + x26, x0b, x0d, x1a, x1c, x1d, x10, + x0e, other_type_ttt]) + except IOError: + print("Error: File does not appear to exist.") + # remove() + return "Error: File does not appear to exist.", 400 + except ValueError: + remove() + text = f"ValueError: {ValueError}, file deleted" + print(text) + pass + return render_template('mulog_read.html', files=files, + max_size=max_size, environment=environment, + environment_road=environment_road, mulog=mulogt, + ts_c=ts_c, pos_c=pos_c, text=text, warn=warn, + ign1a=ign1a, max_pos=max_pos, + _scheme="https", _external=True) +# don't use use_scheme and _external with local testing + + +@app.route('/uploader', methods=['GET', 'POST']) +def uploader_file(): + if request.method == 'POST': + app.config['IGN1A'] = request.form['ign1a'] + uploaded_file = request.files['file'] + filename = secure_filename(uploaded_file.filename) + app.config['FILE_NAME'] = filename + if filename != '': + file_ext = os.path.splitext(filename)[1] + if file_ext not in app.config['UPLOAD_EXTENSIONS']: + return "Invalid file, supports only .log format", 400 + remove() + uploaded_file.save( + os.path.join(app.config['UPLOAD_PATH'], filename)) + + return redirect( + url_for('upload_file', _scheme="https", _external=True)) +# don't use use_scheme and _external with local testing + + +@app.route('/uploads/') +def upload(filename): + return send_from_directory(app.config['UPLOAD_PATH'], filename) + + +@app.route('/call_remove') +def call_remove(): + remove() + environment = request.host + # environment_road = f"http://{environment}/uploader" # on local + environment_road = f"https://{environment}/uploader" + files = os.listdir(app.config['UPLOAD_PATH']) + max_size = (app.config['MAX_CONTENT_LENGTH']) / (1024 * 1024) # in mb + return render_template('mulog_read.html', files=files, + max_size=max_size, environment=environment, + environment_road=environment_road, mulog=[], + _scheme="https", _external=True) +# don't use use_scheme and _external with local testing + + +@app.route('/call_render') +def call_render(): + file_path = f"{app.config['UPLOAD_PATH']}/" \ + f"{app.config['FILE_NAME']}_pos_file.csv" + file_ = pd.read_csv(file_path) + file_use = file_[["latitude", "longitude"]] + if file_use.empty: + return f"Failed to render {file_path}, file positions empty.", 400 + else: + map_ = folium.Map(location=[file_use.latitude.mean(), + file_use.longitude.mean()], + zoom_start=14, control_scale=True) + i_count = 0 + for _, row in file_use.iterrows(): + + if row['latitude'] == "latitude": + continue + else: + i_count += 1 + lat_lon = f"{i_count}\n{row['latitude']}\n{row['longitude']}" + if i_count == 1: + folium.Marker([row['latitude'], row['longitude']], + popup=f"First position: \n{lat_lon}", + icon=folium.Icon(color="green", + icon="fas fa-truck"), + ).add_to(map_) + elif i_count == len(file_use): + folium.Marker([row['latitude'], row['longitude']], + popup=f"Last position \n{lat_lon}", + icon=folium.Icon(color="red", + icon="fas fa-truck"), + ).add_to(map_) + else: + folium.Marker([row['latitude'], row['longitude']], + popup=f"{lat_lon}\n", + ).add_to(map_) + """ + points = [] + points.append(tuple([row['latitude'], row['longitude']])) + folium.PolyLine(points, color="red",weight=2.5, opacity=1).add_to(map_) + """ + return map_._repr_html_() # https://fontawesome.com/ + + +@app.errorhandler(413) +def too_large(e): + return f"File is too large {e}, maximum is " \ + f"{(app.config['MAX_CONTENT_LENGTH']) / (1024 * 1024)}mb", 413 + + +@app.errorhandler(404) +def not_found(e): + return f"Error: File does not appear to exist, {e}.", 404 + + +@app.errorhandler(500) +def some_error(e): + return f"{e}. Try Clear button", 500 + + +def remove(): + print("deleted") + folder = app.config['UPLOAD_PATH'] + for filename in os.listdir(folder): + file_path = os.path.join(folder, filename) + try: + if os.path.isfile(file_path) or os.path.islink(file_path): + os.unlink(file_path) + elif os.path.isdir(file_path): + shutil.rmtree(file_path) + except Exception as e: + return f"Failed to delete %s. Reason: {(file_path, e)}", 400 + + +def listdir_nopos(path): + r = [] + for _ in os.listdir(path): + if not _.endswith('_pos_file.csv'): + r.append(_) + return r + + +""" +@app.route('/SomeFunction') +def SomeFunction(): + print('In SomeFunction') + return "Nothing" + + +@app.route('/clear') +def SomeFunction2(): + print('In SomeFunction2') + return "Nothing" + + +@app.route('/swmu_run') +def swmu_run(): + os.system( + return "Nothing" +""" + +if __name__ == '__main__': + app.run(debug=True, host="0.0.0.0", port=50002) + """ + app.run(debug=True, host="0.0.0.0", port=5000 2, ssl_context=( + "server.crt", "server.key" + )) + """ + """ + app.run(debug=True, host="0.0.0.0", port=50002, + ssl_context=('cert/cert.pem', 'cert/key.pem') + ) + """ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..fadb3f1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +version: "3.9" + +services: + + swmu: + image: registry.martinfencl.eu/swmu_web:ver1.3 + + ports: + - 8046:50002 \ No newline at end of file diff --git a/help.md b/help.md new file mode 100644 index 0000000..eda940b --- /dev/null +++ b/help.md @@ -0,0 +1,148 @@ + + + +****SWMU arguments (when entering the command runswmu -h):**** + +**mandatory arguments:** + -- UNITS unit amount + --mode MODE mode run | sim | simfast + +**optional arguments for "run" mode:** +*--latitude LATITUDE* +latitude (default 47.687622035085916) + +*--longitude LONGITUDE* +longitude (default 17.744894027593666) + +*--domain DOMAIN* +current domain (default HU00) + +*--near_by_domain NEAR_BY_DOMAIN* +near by domain (default HU00) + + *--x01 GENERATE_X01* + generate x01 (default True) + + *--x01-pause X01_PAUSE* +x01 pause in seconds (default 5sec) + + *--units-wo-x1a UNITS_WO_X1A* +amount of units that will not generate x1a (default 0) + + *--x1a-pause X1A_PAUSE* +x1a pause in seconds (default 10sec) + + *--x1a-mask X1A_MASK* + x1a mask-type of log: + - 01 - without Regain signal flag; + - 17 - with Regain signal flag (default); + + *--x1a-type X1A_TYPE* + x1a type of log (number of positions): + - 0 - (default); + - 1 - 17pos; + - 2 - 33pos; + + *--x1d GENERATE_X1D* + generate x1d (default True) + + *--x1d-pause X1D_PAUSE* +x1d pause in seconds (default 60sec) + + *--x1d-weight_axles X1D_WEIGHT_AXLES* +x1d weight + number of axles: +- 'auto' - generate 2-10 (default); +- '42' - set weight 4, axle 2; +- '76' - set weight 7, axle 6; +- '22' - set weight 2, axle 2; +- .. + +**optional arguments for "sim" and "simfast" mode:** + --log IMPORT_DIR + path to simulated log (obligatory with "sim" mode) + + --simulate_pause SIMULATE_PAUSE + used for mode "simfast" to set delay between each message in seconds (default 2) + +**shared arguments:** + *-h, --help* + show this help message and exit + +*--server-host SERVER_HOST* +server host (default localhost) + +*--server-port SERVER_PORT* +server port (default 31001) + +*--start-id32 START_ID32* +start id32 (default 3567779840) + +*--start-port START_PORT* +start port (default 1024) + +*--bt-spontaneous-timeout BT_SPONTANEOUS_TIMEOUT* +BT spontaneous timeout in seconds (default 20) + +*--sigma SIGMA* +sigma in seconds (default 0.2) + +*--sta SEND_STA* +send sta (default True) + +*--sta-pause STA_PAUSE* +STA pause in seconds (default 30sec) + +****SWMU examples:**** + +Example for 5 Software Mobile Units and server host `localhost`: +```bash +$ runswmu 5 --mode run +``` +```bash +$ runswmu 5 --mode sim --log ./test_log.log +``` +```bash +$ runswmu 5 --mode simfast --log ./test_log.log --simulate_pause 0.25 + ``` +**Other examples**: +```bash +$ runswmu 1 --mode run --server-host localhost --start-id32 3567779841 +``` +```bash +$ runswmu 1 --mode sim --server-host localhost --start-id32 3567779841 --log ./test_log.log +``` +```bash +$ runswmu 1 --mode run --server-host 10.48.172.135 --start-id32 3567779841 --bt-spontaneous-timeout 5 --simulate_pause 0.25 +``` +```bash +$ LOG_LEVEL="INFO" runswmu 5 --mode sim --server-host localhost --start-id32 3567779871 --bt-spontaneous-timeout 5 --simulate_pause 0.25 --log ./test_log.log +``` +```bash +$ LOG_LEVEL="INFO" runswmu 2500 --mode run --server-host 10.48.172.135 --bt-spontaneous-timeout 20 --sigma 3 --sta True --sta-pause 60 --x01-pause 11 --x1d-pause 250 --x1a-pause 18 --x1a-type 1 --domain DE00 --near_by_domain CZ00 --start-id32 3567779841 +``` +```bash +$ runswmu 1 --mode run --server-host 10.48.172.135 --start-id32 3567779841 --bt-spontaneous-timeout 5 --simulate_pause 0.25 +``` +```bash +$ runswmu 50 --mode simfast --server-host localhost --start-id32 3567779841 --log ./test_log.log --simulate_pause 0.25 +``` + +**how to create pod (k8s):** +```bash +$ kubectl [-n namespace] run [name_of_pod] --rm -i --tty --image [name_of_image] -- /bin/bash +``` +```bash +$ kubectl -n uhura-azure-wagexp run swmu --namespace=uhura-azure-wagexp --image=python --requests=cpu=100m,memory=512Mi --limits=cpu=200m,memory=2048Mi --rm -i --tty -- /bin/bash +``` + +```bash +$ kubectl -n uhura-azure-wagexp run swmu --rm -i --tty --image python -- /bin/bash + ``` + +**how to add mulog_file to k8s pod**: +```bash +$ kubectl [-n namespace] cp [path to mulog file] [pod_name]:/ +``` +```bash +$ kubectl -n uhura-azure-wagexp cp /home/directory/test_log.log swmu:/ +``` \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c7aba34 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,10 @@ +Flask +# colorlog +crc16 +folium +Werkzeug +pandas +# requests +# our packages +muidconv +directive diff --git a/scripts/create_mulog.py b/scripts/create_mulog.py new file mode 100644 index 0000000..4f5a533 --- /dev/null +++ b/scripts/create_mulog.py @@ -0,0 +1,56 @@ +import logging +import time + +from scripts import utils +from directive.munet.log_record import identify, parse, full_parse + +# from .settings import conf + +LOGGER = logging.LoggerAdapter( + logging.getLogger("swmu"), {"unitid": "unassigned"}) + + +def load_log(import_dir, sim_time_check): + with open(import_dir) as fin: + # take only message even when row is f"{log_address}: {message}" + fin_data = [row.split(":")[-1].strip() for row in fin] + index = 0 + list_ts = [] + list_ts_warning = [] + five_year = time.time() - 157784630 + + for message in fin_data: + message_ts = utils.get_timestamp_of_message( + bytes.fromhex(message)) + if sim_time_check == "max_y" and message_ts is not None: + if message_ts < five_year: + list_ts_warning.append( + (index, message, message_ts)) + continue + message_type = identify(bytes.fromhex(message)) + try: + message_type_parse = parse(bytes.fromhex(message)) + message_type_full_parse = full_parse(bytes.fromhex(message)) + except Exception: + # except Exception as e: + # logging.warning(e) + continue + if message_ts is not None and message_ts <= 423792000: + list_ts_warning.append( + (index, message, message_ts)) + list_ts.append( + (index, message, message_ts, message_type, message_type_parse, + message_type_full_parse, list_ts_warning)) + index += 1 + """ + if list_ts_warning: + LOGGER.warning( + f"timestamp in mulog is suspicious ([row in mulog]" + f", [message], [timestamp]): {list_ts_warning}") + """ + return list_ts + + +def dir_mulog(import_dir, sim_time_check): + mulog_data = load_log(import_dir, sim_time_check) + return mulog_data diff --git a/scripts/utils.py b/scripts/utils.py new file mode 100644 index 0000000..2a12a88 --- /dev/null +++ b/scripts/utils.py @@ -0,0 +1,139 @@ +CHARTOITA2 = { + "A": int("11000", 2), + "B": int("10011", 2), + "C": int("01110", 2), + "D": int("10010", 2), + "E": int("10000", 2), + "F": int("10110", 2), + "G": int("01011", 2), + "H": int("00101", 2), + "I": int("01100", 2), + "J": int("11010", 2), + "K": int("11110", 2), + "L": int("01001", 2), + "M": int("00111", 2), + "N": int("00110", 2), + "O": int("00011", 2), + "P": int("01101", 2), + "Q": int("11101", 2), + "R": int("01010", 2), + "S": int("10100", 2), + "T": int("00001", 2), + "U": int("11100", 2), + "V": int("01111", 2), + "W": int("11001", 2), + "X": int("10111", 2), + "Y": int("10101", 2), + "Z": int("10001", 2), + "": int("00010", 2), + "": int("01000", 2), + "": int("11111", 2), + "": int("11011", 2), + "": int("00100", 2), + "": int("00000", 2), +} + +# message type: offset (bytes) +MESSAGE_TYPE_TIMESTAMP_OFFSET = { + 0x01: 8, + 0x02: 4, + 0x04: 8, + 0x10: 4, + 0x14: 4, + 0x1a: 4, + 0x1d: 4, + 0x23: 4, + 0x0b85: 4, + 0x1c01: 4, + 0x1c02: 4, +} + + +def bytes2uint(input_bytes): + return int.from_bytes(input_bytes, byteorder="big") + + +def bytes2uintle(input_bytes): + return int.from_bytes(input_bytes, byteorder="little") + + +def bytes2hex(input_bytes): + return input_bytes.hex() + + +def bytes2str(input_bytes): + return input_bytes.decode() + + +def parse(input_bytes, item_iter): + item_dict = {} + for item in item_iter: + name, a_slice, function = item + result = input_bytes[a_slice] + if function: + result = function(result) + item_dict[name] = result + return item_dict + + +def mask_flag_dict(flag_bytes, flag_name_mask_iter): + flag_int = int.from_bytes(flag_bytes, byteorder="big") + flag_dict = {} + for flag_name, mask in flag_name_mask_iter: + flag_dict[flag_name] = mask & flag_int + return flag_dict + + +def get_domain(domain_str): + if len(domain_str) == 4: + country_code = domain_str[0:2] + subdomain_code = int(domain_str[2]) + status = int(domain_str[3]) + int(0x04) # 0x04 to activate + domain_int = 0 + domain_int |= CHARTOITA2[country_code[0]] << 11 + domain_int |= CHARTOITA2[country_code[1]] << 6 + domain_int |= subdomain_code << 3 + domain_int |= status + return domain_int.to_bytes(2, byteorder="big") + else: + raise ValueError(f"domain '{domain_str}' 4 characters expected") + + +def circular_increment(value, min_value, max_value): + value += 1 + # value must be between 'min_value' and 'max_value' inclusive + if value > max_value: + value = min_value + return value + + +def get_message_type(message: bytes): + try: + message_type = message[0] + except IndexError as ie: + print(f"IndexError occurs in get_message_type: \n\n{ie}") + return None + if message_type in (0x0b, 0x1c): + return int.from_bytes(message[:2], byteorder="big") + return message_type + + +def get_timestamp_of_message(message: bytes): + message_type = get_message_type(message) + if message_type in MESSAGE_TYPE_TIMESTAMP_OFFSET: + index = MESSAGE_TYPE_TIMESTAMP_OFFSET[message_type] + ts = int.from_bytes(message[index:index + 4], byteorder="big") + return ts + return None + + +def set_timestamp_of_message(message: bytes, ts): + message_type = get_message_type(message) + if message_type in MESSAGE_TYPE_TIMESTAMP_OFFSET: + index = MESSAGE_TYPE_TIMESTAMP_OFFSET[message_type] + message = ( + message[:index] + + int(ts).to_bytes(4, byteorder="big") + + message[index + 4:] + ) + return message diff --git a/static/index.css b/static/index.css new file mode 100644 index 0000000..27ed0fa --- /dev/null +++ b/static/index.css @@ -0,0 +1,399 @@ +/* ** CSS styles ** */ + +/* LOGO_TEXT */ +@import url('https://fonts.googleapis.com/css?family=Holtwood+One+SC'); +.logo{ + font-family: "Holtwood One SC", serif; + /*text-decoration: underline;*/ + text-transform: capitalize; + text-align: center; + font-size: 80px; + color: rgb(75, 86, 87); + background-color: rgba(84, 84, 84, 0); + text-shadow: rgb(245, 230, 230) 2px 2px 2px; +} + + +/* NUMBER_SIZE */ +#number { + width: 5em; +} + +/* just_text */ +.text { +font-family: "Times New Roman", Times, serif; + font-size: 20px; +color: #000; +} + +/* INFO_HELP_text */ +.info_number { +font-family: "Times New Roman", Times, serif; + font-size: 10px; +color: #000; +} + +/* INFO_arguments_text */ +.info_argument { +font-family: "Times New Roman", Times, serif; + font-size: 12px; +color: #000; +} + +/* SWMU_text */ +.swmu { +font-family: "Times New Roman", Times, serif; + font-size: 8px; +color: #000; +} + +/* ign1a_info_text */ +.ign1a_info { +font-family: "Times New Roman", Times, serif;/*font-family: "Audiowide", sans-serif;*/ +font-size: 16px; +} + +/* MODES_text */ +.mode_text { +font-family: "Times New Roman", Times, serif;/*font-family: "Audiowide", sans-serif;*/ +font-size: 18px; +color: #4E4545; +} + +/* mode_text_alert */ +.mode_text_alert { +font-family: "Times New Roman", Times, serif;/*font-family: "Audiowide", sans-serif;*/ +font-size: 12px; +color: #D12A2A; +} + +/* dropbox_text */ +.dropbox_text { +font-family: "Times New Roman", Times, serif;/*font-family: "Audiowide", sans-serif;*/ +font-size: 18px; +color: #4E4545; +/* vertical-align: top;*/ +text-align: left; +} + +/* Parameters_text */ +.parameters_text { +font-family: "Times New Roman", Times, serif;/*font-family: "Audiowide", sans-serif;*/ + font-size: 15px; +color: #4E4545; +} + +/** IMAGE_swmu **/ +.center { + display: block; + margin-left: auto; + margin-right: auto; + width: 50%; +} + +/** DOWN_BUTT **/ +.button_mode { + background-color: #ddd; + border: none; + color: black; + padding: 10px 20px; + text-align: center; + text-decoration: none; + display: inline-block; + margin: 4px 2px; + cursor: pointer; + border-radius: 16px; +} + +/* Place the navbar at the bottom of the page, and make it stick */ +.navbar { + background-color: #333; + overflow: hidden; + position: fixed; + bottom: 0; + width: 100%; +} + +/* Style the links inside the navigation bar */ +.navbar a { + float: left; + display: block; + color: #f2f2f2; + text-align: center; + padding: 14px 16px; + text-decoration: none; + font-size: 17px; +} + +/* Change the color of links on hover */ +.navbar a:hover { + background-color: #ddd; + color: black; +} + +/* Add a color to the active/current link */ +.navbar a.active { + background-color: #04AA6D; + color: white; +} + + +/* RADIO */ +.radio_text { +font-family: "Times New Roman", Times, serif; + font-size: 20px; + color: #4E4545; +} + +#content1, #content2, #content3 { display:none; } + + +#toggle1:checked ~ #content1 +{ + display: block; +} + +#toggle2:checked ~ #content2 +{ + display: block; +} + +#toggle3:checked ~ #content3 +{ + display: block; +} + +.text-center { + text-align: center; +} + +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +/* RUN_BUTTON */ +.run_butt { + align-items: center; + background-color: initial; + background-image: linear-gradient(#464d55, #25292e); + border-radius: 8px; + border-width: 0; + box-shadow: 0 10px 20px rgba(0, 0, 0, .1),0 3px 6px rgba(0, 0, 0, .05); + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-flex; + flex-direction: column; + /*font-family: expo-brand-demi,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";*/ + /*font-family: "Audiowide", sans-serif;*/ + font-family: "Times New Roman", Times, serif; + font-size: 24px; + height: 70px; + justify-content: center; + line-height: 1; + margin: 0; + outline: none; + overflow: hidden; + padding: 0 32px; + text-align: center; + text-decoration: none; + transform: translate3d(0, 0, 0); + transition: all 150ms; + vertical-align: baseline; + white-space: nowrap; +} + + + +.run_butt:hover { + box-shadow: rgba(0, 1, 0, .2) 0 2px 8px; + opacity: .85; +} + +.run_butt:active { + outline: 0; +} + +.run_butt:focus { + box-shadow: rgba(0, 0, 0, .5) 0 0 0 3px; +} + +@media (max-width: 420px) { + .run_butt { + height: 48px; + } + +/** SELECTOR_INFO **/ +body { + display: flex; + align-items: center; + justify-content: center; + margin: 0 auto; + height: 100vh; + background-color: #f1f1f1; + } + +input { + display: flex; + align-items: center; + justify-content: center; + margin: 0 auto; + } + +label { + display: flex; + align-items: center; + justify-content: center; + margin: 0 auto; + } + +select { + margin-bottom: 10px; + margin-top: 10px; + } + + + + +} + +.selectt { + /*color: #fff;*/ + padding: 30px; + display: none; + margin-top: 30px; + width: 60%; + /*background: grey*/ + } + + label { + margin-right: 20px; + } + +/** BOX_ITEMS **/ +.clearfix { + content: ""; + clear: both; + display: table; + border-style: groove; + + /*display: block;*/ + /*margin-left: 700px;*/ + margin-left: auto; + margin-right: auto; + width: 800px; + /*margin-right: auto;*/ +} + + +/** HELP **/ +helpswmu { + position: absolute; + right: 0; +} + +/* CLEAR_BUTT */ +.clear_butt { + align-items: center; + background-color: initial; + background-image: linear-gradient(#464d55, #8c2323); + border-radius: 8px; + border-width: 0; + box-shadow: 0 10px 20px rgba(0, 0, 0, .1),0 3px 6px rgba(0, 0, 0, .05); + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-flex; + flex-direction: column; + /*font-family: expo-brand-demi,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";*/ + /*font-family: "Audiowide", sans-serif;*/ + font-family: "Times New Roman", Times, serif; + font-size: 15px; + height: 20px; + justify-content: center; + line-height: 1; + margin: 0; + outline: none; + overflow: hidden; + padding: 0 10px; + text-align: center; + text-decoration: none; + transform: translate3d(0, 0, 0); + transition: all 150ms; + vertical-align: baseline; + white-space: nowrap; +} + +.clear_butt:hover { + box-shadow: rgba(0, 1, 0, .2) 0 2px 8px; + opacity: .85; +} + +.clear_butt:active { + outline: 0; +} + +.clear_butt:focus { + box-shadow: rgba(0, 0, 0, .5) 0 0 0 3px; +} + +@media (max-width: 420px) { + .clear_butt { + height: 48px; + } + +/* file_butt */ +.file_butt { + align-items: center; + background-color: initial; + background-image: linear-gradient(#464d55, #25292e); + border-radius: 8px; + border-width: 0; + box-shadow: 0 10px 20px rgba(0, 0, 0, .1),0 3px 6px rgba(0, 0, 0, .05); + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-flex; + flex-direction: column; + /*font-family: expo-brand-demi,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";*/ + /*font-family: "Audiowide", sans-serif;*/ + font-family: "Times New Roman", Times, serif; + font-size: 24px; + height: 70px; + justify-content: center; + line-height: 1; + margin: 0; + outline: none; + overflow: hidden; + padding: 0 32px; + text-align: center; + text-decoration: none; + transform: translate3d(0, 0, 0); + transition: all 150ms; + vertical-align: baseline; + white-space: nowrap; +} + + + +.file_butt:hover { + box-shadow: rgba(0, 1, 0, .2) 0 2px 8px; + opacity: .85; +} + +.file_butt:active { + outline: 0; +} + +.file_butt:focus { + box-shadow: rgba(0, 0, 0, .5) 0 0 0 3px; +} + +@media (max-width: 420px) { + .file_butt { + height: 48px; + } diff --git a/static/pic/SWMU-logos_transparent.png b/static/pic/SWMU-logos_transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..3264efb1f4f5abdd0f3a7eb7f3c37fffc0f53036 GIT binary patch literal 47897 zcmeFaS6EY9`!7ltkSc;AN>>y_iqflqBGPPxUK9bPL!{RT0v152N>x!15+DizLRV0F zQ3<_DmC!MS&Kb#M{lE3?{hYJ!&c%MbSS|x|jQNhY{@ya;<7)=m%#6nvDJUqIb*^aL zprD{Zlm4Tp13$qF6m@|AQNnL%Yfu!lAOB53!B3&1b@7(3)!dL_p^8!WktG7tv%Nbr zyxi#&w)(FRd_z#%%+f?jQ25f;^02*>e-uos{_FUa3oM9w#Ci1-2k$*=r%0cvZ#cV| zwlGk-Smm&oXK94YQ%xMKUEQ9&mA_-kQ?}DKytQpqM$g8t9!fz;Mf0D(9Oha_e!-lH z{_mfXo>Qks>rwstQSxHM4=O6ukNNAz|7#c0uR_uN58Q{mTBo{fZvl z`oHZ#@ppSjK7X0>S92gM{cBc#ox;A;{_7O}I)%SZVIREwMGAkB!akP$i!sS~{x4Ga zixmDMg?|#lFSv zg}+YWzc}#MDg1Q`|9?1z^oLB^|I7k_68GQo#ozM9-}1%3$4~xtKmR&~zunLO8@r!q zbZra!@(ryCYowK$c6}-P^4G~iBmAu+`}1KoQk0b4cZzxSpei01S<}}FJkDOoS+M-( zhw9^~Qg2w1C&NB!E25<_DPmCBFZlJoQI9ZoTR<!9 z69(=UlH){GiuEcgqV z*b<;1SnceaLxH4h65r>C2Mvu$!|(Sm_D|sg-XtsH^Ut_nGd(@JxmZJB|KY3Pw~4Q- zBKD^ZC9kT7%3S>c-w$+E;Ni6&XS@#W*DB9ZQJuYs*gsJ!IFa)SIV?Zg*AnA>Ji$ve_iMM1LXgS6e_UJ-99{=t;oY8b_SSbe6nI+5O;;oWvN; z*09mYq>%n&HucuNGAyA%1*UcX=$8)`ha30!xU%12Kxcbx!+gDh^4OeG3Jv!eYY14S z$GT7EJ9R@}j8W9d+Sx^4C*PCxv!w(E=vS{Vs)yo2C%E=M>DXNL#asdpIyz4Cxy>>c zhMNRcFPwsO=okG%0qWBJQeYfDDJVb*~su?A3>jd zZ`f%0V(dwqrgq*mwi*g4KmW16a_ADo4`l)VT4|MiDJf71)gdt&XDPeqV`3Q#3)~Lf z8Itum02u>#?!f+Yv@}Wdg-J{wKMflT2~wk`k11O{jw(F1z~k2f9EDvS^?A0<(}LAe zQJFjoi&(n{q%(i_k%0DDdL7DXa*7W6AbH8AY02?H6ydT~rT4~fZl_5K{DQn{Y}EEf zv4eZ;V8t!4_E_ifScvZqz~<7iTi*=G#Ah?0*sa=_KYBhgqBCC9(&|>4?AHzTIx)b? zzT9-OvAJfkDv1T~uDJhehAP&<1q1R(B48}S)w1@{*^_VByWKY7ev=U)R zCfg~ifP?6T7~-+J7*|BvF{??gZx=$cIR;*tq}#ZPkk>mL0i*=c9ffwjcjP69m0jbD zH<#$dxFrczr5dQf-GF4t_r$)~p_*w5yka&JTD8n0si$j6wDjzhgLS2{b(D-b-figd_ zG`(-TXMqzwtI7vyOAgynZmVd&e$t;MvsgO3$&J(ES94MM$|%v|WXWWrOkkM}$BR`(ThQ#3jRnXSqotx=dWaw>&{Id1nWPjm-G3_+gvRhLvyo z-G6-Kf$A!Zq#!h2N)RhL&+*qfmU@biKgq|}9vj0Y33L<8+0Ub!GnIYvRuXs0B1~^q z6WkVh&FaJix-IT!LT{ttJgYa0f)Fx5n>A4u_Y()GONRyJeYz(%jIeD>kFczc z>w#|IrH<-e2lrnp!e2YP>L~}kw7iyU4EI9-R#4Jx1mn9@UwXjFCPN|dVmHshXeURo z(CmW%FBAvbMfqzLou;Ex$)ekSUz;?BJ0t+3Gv+p%G$e>WgiqV9oeM*4``Itloy*MR zv10g0C-cR2-;(GllT7#3@tyjkCC6J)UfH9wyK^Tv??y8M)!p6Efb5isoy~^%_8&H~ zkkC$ut7Et{Hhk-6TqC~|$-eptHN1xn$};Cz!*MH2gvmz!LvD)`^X_Zki&iFe zpA&v?uv#esXA`}UH%<0*2o45%v_Y4%=1KA?d}!9#tSnpFIJJnZB74g#do6B99$*eu z`Z0XUs9Jq7=>O`QU+<2Yad5ydV-A+Ij@K)kV)NaO@kDZTLMVcup;&c|fh+_QT^qwO z98TD&y;CSey1sF#PR5eo_^ze+Px#aPWDV5somCw&H{2D0=KnTxttB1U-4me_VJza- z_a;)JUhzQya|~H7&p6m@qKp0rL+m?%kPs3y9{FQ|{d!hyJS~@3hFHR=2OP=P3_f4N zgAY;(v>VvBdMn4Dyr@&?xxg(t6P4tpSwpjp=wLtZTZ&et7p5|&_S8Z$%7de#wwv(f zb`qr*r%bJS_CgG;W4sr;*zi6NaasDb?6rtaj73t)$ zNf$rfNHH0mNQE@FY*!a6Z4C1G#CdsYCjZq~2N@{T>Hy>=;!=5=WT&-fXonw1u_|fr z!n6W^Y`jt#$}r!PF7_|F%`*xcZx)Z}3o~S`9+C`L@(@`8Nb35u!yx2z>F2HiWK)-Y z27)qrha1sTTMU^hW>LV(tfQlt{&?bW83luPUfzZkv?~6PtvfSjwwCJf?SBo)+6$o?(P$# zvmg1zScgYiydo6JlC3^K0W$%3@THPtjm+>CZMiE33N zp~)D#mx*fJC6m_Hv$L?RHdAwwT|P1@$ZExiX3Rncn*-cKdNz*kD%k^M9PWjqpTFsB zIEX55t`#l)Wf_u`rh%Q53h|umJs4)4KnbHWt-3uhDt)H|?p*u`vSmuDbYOo5lBJL% zr#?6*Wz)#1muU$*AAPUw2>XkH#T5r+tq3)i>C-2^ESSS&-p3xE62%zFz!~m{3 z-*b@VNCH?RL)oTHc5<}{+O@+MCXznK(*60>&>~x5k$Y>t^~0e3OO>WfhXcEyX~Ybe3ki|k7@Rhnj?J(8MuvdQW^>V->dHX)NP@$jr|IVlcLv51h_SnR zt_NBkUtkCpUy!`wM95s?NnWxE!)W&mlFZK@77w-3pZvsoeZ^$m)a(4re=`T69c|x_YiJ3Xh3eM~z?nf@C>c z3K38Q_|x9+Hx8kT9jcKBX=*Z}wJH8K07-Zx6czX@B|6v!^=`dsVJu)DG3YI#a=Pm- zd%IC}KYqptK}xqX z!n(`TJ#O{-O$GBnz(Bqdq!>%$vg-R*$KP?G+2+IKv5zO6n?>I)3JR7M+WG!^(#R%8 zoqI%4>N3g--{b?J3+kcg{3OH-z!$Q3uRSpUDx~8kCpBx7Xd)G=RZ0*Lc+i^6lVk_ zM&?ZC^V60ARF*Omtx&TEW5s?3+7cWOZ>CiD6|B}!k zHugn1<<*bo{tsgUzeUwLU&dDK+*>T=u;+hezBP6HS?21ms>@PH^szUCm&w-E4l-dy z^M>eTGCztBqOhBJ1k0XT?c>tJ=R8nK0jy1#6^W9@!FCjDdeq}b(#@~%@c!Pu_W1$ydgHYeskiDIWP3ZSfwSQ5ZPO_uS#O-E$ejtmz}db}Og# zO{YH!Wa+EF2H6i$6F0vO?u90{rRZ;n z_8r)l3?mab_4jWA*ng7rcu-?79J(P!wonu8*CMx4cw~#|>=ah`gak`#+7wO)pZFY9 zd2$OFrt*Nv!k|@Y!I$RU-I9-|{t<=<$@9MZ9-%|#j3QuYvR$X7%(dCR?3a^D#JsG> z(WPt0yE0?bel9Y#20Nl!WWQfN4Xs8L0T0psOUf{Ehi`TE!y~bo-ipWM$+Y^K04=iL*CHQUe^^tiDLbxcv$^}T-SoYVja%6M zbF8MB<+BA2UwhJURxMBb6v+$u(dFRGUY-)rE8ml00FUVQf+w$0T|VpZ4}abp!M)y} za+~Kf@qMz2KAfF*&5dBOQUDC*SOBi8Mm2kjq+A-<7F&+2Dws}vQ z`nNepvK>{ymDDARaoQD|?QPjFOcLe=SR~r4?h{kFrxJb!kBn-h@SYX@^qt_# z3sKj}53s+wCj`n*3qMC@nT18XZ{9sAC>@^Sk11Fw-`i%oAl=%$`XZe5CSh+0J7*mM z<342smKDzKt3b_2A{qj@z{^9zY9rtN|mizLx3y9ddj?cN>+Hb(;!0; z9p;~eV#ibUj{E|fpg}LuizbnoR8qc^F{k;FbmiMd$S7^Ds2%K0xLhh$xPtkEyHQ^4t{Ij8;#Us zU!-|G9s3~uQ2eI2agEA|=eQ8DIGAVbnem07Kln%0Y;S%~y6%_3`az|^#b5#YWPb1# z1A6NCaQbKCjB(7ASA=+kt_!>K@1OYd)o0viZ|{nG5e9{7XTN(w`F-yd;ON;ad!V>s zfDomG6_hnyyVs1FSo@shA5;9*JsMDv4KHC=J;LtydapZ~!U@mfyPrq@yLNGy?E{+) z$vbtRk1o%LowwR^;A;yTIe#s6OFV*Gc(SBQ`K}uED+^|?A;DJ{M+hQY$%~tQQxx5U zg1t9p2VKGyGKZb~zCR?=qq*t{_n@%x?~+#SCn|F~lNzmh?elfW44mwScqF!J?vb5N zNRU6>Rqnf!7l*MLNJ4Y%>^#FX!m>u{%7Q{ZB|$Bgz&>}nL#Ob;XuCThA}*3#wol+$bM6bp-1R>Jqa z2=kvXRp@qlN$B-0%08}5X96z>G+dkgIRDbgjeUFBGs%c9u_wih)wH8ls^R=}^K$n6 z2rr?+B%CD`>cy`ND7bKe8lyN3{v$*JTHPtsh)^?+T{&G^GgQv2B&@25V)|^B;ekIP z9t+ITjn{}o@z^W@Nf%1O@R z*9ggj`IeQLWJ|ck(Hjs-xM{nzTESz!A+6ku77pnK(0^6HI85Bb?%IPBJs;fXaurF2 zQ0(t$XIT)jnSHw!-tpPd_v?f?jY<6Pz~|(hx&ZCC*+@qyDA-a3u%M+Ankewyi4HCV z8hLKCMI9=?-LPCHTa-lm=cIl!s@H)AxREpFv!zr>yHjOQF64X`5Evb8TA4xKHi4rT z9-8RD6V%7AD00Ol;OXr;_p5^|U0?$$^XVb6V!Ot}(6`o)9)!iUpH>kwxsZGn)>NVna$yf89sIWn|D%!G+XQVEj?5<^+2Rp5OX-I{x$LYpvX71Dn`Lif zDV(09bU-P>Ll7t*>R&$ud3<%74oaBQd?|~2=6R{^{yQ(HeS-qdT%ay~-!YX^acL>( zK7Or3LQpUo33S5o#C2BkvX|gADfH8}kWSbky4gN})6~R9O&_c5{t%Q)HYD!~Ctt4< zt`R2KM=Q}0%caB8p5S0g<{Gb$`_Mhd6(sdfr&YmRDrX@K5y@#Xe&lQ2FYcq{SD0KU zQKlQ!xy2kVG^6b-)mjcu9h#P7Y{uziwwk=a0B&q)p z(K`P~>#)3kD8?&F((CE%j?%?RB~^TyrLG&h^O=T0r|X{3iTKeUKm@yP#R_GFbu{7h zb*D1}uenO;;g1}%N*=pWP(6$FI6|zW9i=j(9#~HDu6iBb9Bd@4Xv4X$m zBSNJAT|v$UIYl;h<1i#c^U)c~?nR+r>6q($ej`7S-qrU9gCUybCiT$o&8r_sBo~aV zlC6RQ@svdIg>Wbw{tv}6B@@vZO5$&{tKrSB4D-b*gYPR}3I5Z|=Ra&UZ58wWeKH*O zGk(de`eZyQo(vrhUxu{4?kwFFB7j)!s_nA zAxzL4rvBCX!rEx|Wk`4>KzOFh7TkncJ09EJpcVpLYXWOHQZg9WC%bOf(44nj@Vj(lk;RL=7XSNkLa!1bY>1aYzl5G{8 zE_Xte@}xj?W)m^c(=;(rp#P9@j6jXda<`ET%^{ni*)%oCZj=CSoqu<|nS=uoKMxj1 zsB`WOWK7FXKFKjR&Jal)KknByBq;wW>11Xi@)HSheY$Lgy((U+I$WN8{9XwDmC&w5 zsEo$<^JMv{QzD+!OmNv;r-Bqv1U*fGB%~5AKjP0SrB6y_GCZ6h_OSr@>9Vtw^ZZan zGW9gllmVURrKJM7rnkVT1=C_7NR>#tcHCxCwtRc7%G|hsx0zGzW&x&z-XPZn+3~FR zPOsu(l8K7k7yW;~A5_E;r%poxy+B_~$3QyI*bgGJZQ6={xI>>{Z!K{`{ATIV-7eqt zZ8uP8ftO7^vkaBd?r4SZ8_ufCU*DO$O zdA|7QQAP;yql!6`d02z>G0g(b2;z}KHXD~W3+d2#{ucxQ;$)&&sFjPmAKo+K=Z<*~ zKoR5bW0Va=jUy&;{zrrAB=>w378vTTYXl*^l6Gt z?{~_njp|5%Ep{i?d&+qG@AMv1j8Uvrp{~Rh5cAEdaVz+!qdOgK$5d8X$UD1>0wj~$ z?}8?s3T=z%rf_;JU=PlcW%ebsVK{SOxBC9+bERdIh*39ds{f%XgH+%^+ekxb5J z9UlIxhwiHU+*n~MSV`Sk2@*GsQ42#cRdf&E>HSf7T(hO5Bj;PncuS%cw~dPj1G?lI z5pv3%XFxfg1`Z|uy;p2nKnG=_p@fKuE6xbRZB{A}Rf;dUH?K+uHsO>udKzG?lNHj( zTQU^{M*D$Gls%o{4|ABP)Lj1$@Q;%U#q`<}qmLJTza^M&{v#>Qxld4@IE1|;YMeTm z=%A;MDK}~WTk;{Ne?~R3IW{N4Hs%wYP@e+wR4Ka?7WS()b{Dv;Cz_VqgSP<>1X5JMLP;)HRqSSV$&}1I_&Dw zQL@0*UthFA&ik+?u5C`LuS9&>`<285Q%zm@ETRgZ0PT$2B!KTmxD*K2Hm|PwwaYeQ zcb5J3SAv==j(!rVkzP~hXQd5!qkaNzjC!^%`{leVd)mO}3v;IF;H}X(v1R|X>I(Qw zaL4rEem@;`7T_-KK|FLSCWM84yqHx9%SY+Z&G}~@frr`M4A(2gA98f^ZZr;xM*s-p zW1kQ|a6l|@%SKU8rOxTwQcwaEkY+%UgYX0kVN_>{=X+UOUmrC$=392iDhIU7ez9Qq z6I7>EP}(cli@^EeyTl_pwCh>Z7t4o-%Y&B6n_Yi7Wo(-i*tfzbEuc_UYXHnm>3)JV zgbJ@xEo#>XFfTSI+W67^=t4Ri>`N<3%I@|l>8Lu+ZY|5=zrgh)(6D;3o8YQ7;i&RI zlM>yf^ke(g!5ERwB1Ok`(X;33@b?%UIhIH#4H?kY0}Re`vW<-v{ou8Sa}MuZ z&UF?Aoga~wlb`#&oaXZ6=cT|nNG<+rW)q=LYsL!CtY8#7@T$YN#G@FCIjhNH-g@lw z!ccd>0&b8R7XY&kI>F9efF-LW*dqkgy`%-8PlyJZ;b&2?JbqIJUuG@Y6UNLkB0)pZ zxpT6FDZYA6o+zr8)NW0vn(A0sFbyL316XqJ9Aqb<|GLVNLThGxc`^u#aWi=R=ekzq zkVPNg!x$!IP>A5RBB0zigR~|}Zx~boR_ypHR0hpf1VSAxHhDDYqaScBcmw$yN-7m3 zS~V)l!sR@n87*YIS=qT9s_d+49D;Q{IN?}6=YW^-!P`{lI1q4yMuGX`p8vGDG=Ya_ zNzJ}XCJy~c9WRQq2uehvS9Wuad3iGhVEEEQQvu;7rI>&^Nx4Bj@IO zlu*@<;hsEX#gs>a`YbA4&Xv4TClCW8{%5<9Dyz}=)oT3oBa>KSkz8f7NVNRZ*`g@l ze2)~MgN`@bFzdvO%TFN7k^!bFv-z5lOvW|K*A7OvTq#@GoZ4k3l~IA2 zZX(-Zn+a|_tsOx_evMnUD!bX^sVv$w8Str;4zf!I76-}@^RIQTLPfGmG}6Z%Rcv-P zUQLTwYQ7xS99o6@aT!Mlnl5q|TI?hY5T)y9u`8Wx+jD7dajnG3K2vTR3{-!N4cJ$g zbkG;~9#)@(%rTM1A7*2xlLf=wrH{YZRmAaa!$51oyX?H>qW<=&#_MB7W<+Pc)~)mq zuWW8d6a*>$3nFna{E09YqDBRFC%B!eESX+y!Gge{@5Y+n?zY{sS|F`FTXi{be00cX zjm|^^H5{|=4%0yW+3QO-k2G0kGi)ypS=sUbs0f;e>A*EmgNKN_2xHr-AnuXFt8+$l z212Fg_9wWHs=|@E#NENG|7j1M2kAq5my0dbk_e)@`2`uM8O$-N9aQL8t^~U7*JbRK zZddbn{M;N}>B&CARdXgRXHZ(+4rjz7Udn7As~ur%{AsXyV~j>kpqu6bALJGs0O!-+ zw0wgKb(^%=5yqKT8ZUO`N`mgpmU0XSZHgrGI~5Kv!YgbdGz&2=RD63H&lmEF38jy` zyq3l0M3oW?h0-j*@R;G-T~kO-hQLdycF1;>%UR^=GMKJdy_DMB z;%k!>Gq#`X=%LQs>dLYzr-5Z@An_GR%BZTy%Tc(j$$wIv4qy?dXrOS9o?e>muTnnZ z)Rpul(q1b#?DpEyrD9@!I*TYcCv0@Fz9u=ec_r>eWPfkE>ateespzRct#>gkD2iFZb za73g@5(_&#Li#LB}GY)vy{5Li!U% zTAQ@cspSb@VCxE_D zm6v;b)>=RGRf6iJpfH@;3XN^my3+dByjq+Y!wp@Y%0n@ITFGfPHT5gO$rLx^E<2R@ zYob`am!h9K%%n;|$n+~<#8Zv{O0wdd76L;ClYLkH+B;3Z#8*Uve6T>xiPntUWb)!% zPo^}7!+Qt%2d*CNn+|}SwUTU4qp(pDSx0`A* zk2%|2OMGL~KV`VP!&`F^?Y5>8L`+x`&0OEKOYCnnQ~syw4oX>~y@yXi@s5^OTGH>$ z>V^htz^3OK{*6-MZQOiL+G6t+R_CoIMzbFzDG zaRAKNPNs6WMF;$5)AjX2QtzfgUhluUlAM~T?xk5*qNmv47W;B;(yr*zx3A+1-7Q=x z?={Yj89lAu4{87wD(u5TWzlPA>QfF`F?`w;mXs+gcam4EKV-F${Er&z)-s|@1683B zVV0BE1nN_GtkM-4kFi^bgCWX77D6FI7{rDF&=f22Ai|*dZDiBJ=5*KBtB2@+8Rjb9 z>Jp({?ipZ{;gRUwSMj}PFwx`-^81NpW%ASRHvkuOc-(p+55<5G*8pQq$gR5V?G^n1 z>$yO>N`HoYEA!jOZ)%<$!!fokLnz_DT3YI_4Q<-kobs1u3)BnhH$?@dJNtECCcZHO zBOXQdj>sJQD{fIID`&T++lI*R39V%YoH(=J=~h04z8r5j-udj4N5+BGoyhdMco5~n$WC-9tbn~cUA=;7AhiM2y{1&3TGxFT4(sh zIvV|hv(D`m*ES>hBn&bKd47JdqA!$9Ico*wZS8`f7p$8T4K?;#j~r#c6V0f%5NrRK zAMeAyJRew6ATrVXNuok^`A=Ict+9`qOsU8hB!YSMH2Hn%qqhO`UhR)<{Go4U_~=RK z&{mPC7!1GC=pprC4#15GFl^D4; zw01f+1GP%2z6I1OWji*7bsvVpY+h0CzxO!eqz3Bb7i5KPtGG9)jh1_c5xf_fK+>P7`Tay>lmW2*_de^N zu>sNLvs*EsH_KJzz%dAZ6;L>1^95nl&XMdODXFq(rov5}9vM@ic3lmbKZYCcbgS-f z@t-R|HngOnwUn_$3a5VI8PZcf(}JErOUDgxd8q^CB8?~$Gg`nIPmxa%^a zJqQLA5T;b#ciMifj^)$n4dzc&LE{F;&0m9YN5RTNHf^asr6f(RDWpJ-w2IKPy%ga; z@N#)?^K6J3-j&0wz^$mKs_(|OhV*zNE6!2HJ|gw}l)#Yip>`3u!;&6y^~BjeU}SyaykL_^5KgJ_!};94U|_xDQoS+z zvY*zr#?+L_uE{dFe^>!(r45>=IJUc2!fL>kKO4S&~qni8(()XqbcipA3KT8kqS%G3%TjF zy8y&(;rnbk4}vuglOHVv6h9`#E9=(( zwmFz-+%A z+|yVed~B=!@TB%S2$2oHQJmn9Np{lH8b_iLwbe8e6kD^&juKR-3Ubj7VC#&E9B-;E zFnBp%=n!jkwpP(VB3AMcWjA~IJtms9ll%vIjcaa+fvIv9(41FP=U_(E#*nHkj@{8W zX#dyE!P&v)v?f!vl;D{I_udMy^}YZlW9_zMhi!~_mk+SNxR~a&2ROS!?4+lk(+6xT zjmae%Q*!iZ^@1xRP8~xxl@L21Ygy|lY7lj`L>T$iQ=yuNek1imanq9^Yn?jSNIAvh z|Amg~)B@d%m4Y6CUeA7n(X&Al_45;;{%UZ{D^8l$MC5+)?L()9`461#VtQYE@MYON zYykyEi1T_lIN9Ytfkaq-h|}goPO|pV#}s&a%L{Z=TZf)g&mpbzs_0*qWq-*4Obl4a z=x3NS1eDffsK7pgHC4)AuF#lh&%Bjl>rDsuDi8na2f1Tkd z7`8ZOFpJnP^oBWjI4WI@$eir@vXAtO#02yXPyg&cHNP=Efdj)X*ihjrbJjK6O z{yofJ$^2Eb|C?;aUvm!r&n&?I$r;qTAZmEn_f89DL`Q}AZfqQ2UnUCva?`FKDc|0% ziCR}n&fE*w!0*LG?Qyg3jjzOq?2QQisu>B+SNfL^;YV8o_YxeC<4Hv`dvLogYCVT^ zJ99feYQ2Gd*+T2tuFs+&`*P+vwLK}p-MY!eJ%7RPBT-Qyvdcx{d|MLi%hs7?%Zpm| zHO_vW7Z*quFWnZRCqYM};sE!EZQXhgSiHD%dl$YU;VroU{Qn-_Abqc5 zTg9fs@hT^LCF05>y+rIqt-DVSG2eUrx$9kALc*6tC#6Z`d<+8Z?Ab`N0^wqT?SLfMDP=9Xx;VVb^1VtL-*9lg3& zjV>u zc`CKzGR^edUY7xiFS%!9GvIUX@9l#HoDMQEMRY^c#~y*8vnZv z-qn$=n4RYM=+B{n>*JO6Ti4D5dSC#0!wxBs0*e@}sz8&m2=->2Q@*nQF7>QO{gG3C zj&Tmcxt!(>PB%k7v)crfRa4;KMN&BJX0qP2SXR+F7x!-0r+sZkn3%Tuu&wZ9?Pen- z7{AIaZU$w{+CBh%rbyTEN{*Cy#<^YfOs3tLD&ZB$e|+&q2*AfU0EHKQwl~Lfc~qs=JYw6;e_8ru(Fa>gl(H5sw=+B`8o0=A$rxf%Frlc3OJ8(zvgjP5tI zDdi;nv?3i*0Itm-UXYMV*lY|1qKf^4_VtX635@`_c95$UIKUwr!iKVeWs^(X_GbN& z4XiNn<@zz*IV%z~epMQgw2CyiF0BAuz|spUIsFwL9o1v)!T`OIP8k;qYca@7nK0lm zUSricr?M=Q)LTWN8;Ys-L)ruG?dN2uGw$QU)4~dSDGf@_aFF(q9@&_-&vn?|T9W;; z_i~1=AZemQWH#XU5J^P3nRT;ZP^31J!31Ha0U*-oyINd)<%OmO^;cm2okX_&Cc9IQ z-~4q#>*G9s^*Fwi4~y@8#K14agIJKH-YeBvILQ!za!EF|#9L&vPwdmY5^IV)sC=?1 zT_kVjl8&q7^%31gk}S{DZ8|?5K$5&9(H6G4+yA_b^<9ys!|UE5|Xd1qzDsI16_C_R>^cYl(8176J#FpRD)336!w_BpdDx!|5FS&y_tMYMYf6fQl=L zSx7aJE#Lb1xIwRXJX;0AYLYjsxB8<=axa7r1hMnGzXlF~`h;((eyIAn)CsR)D@^<= zh*jPz-v>4>?Ya0qTiOx2wemx_hx<)t(1Heu%hMb4!@!ov^+uL*^Hb`hnp8yHmAbRu zApIcm87y}4_%5NplG=cp(9qdcXu`(!byR1bBN4rI+$RJO{SpveOE)-wh<~YuN_TsH zhbLb7eACnTO3|j&_)4*+1MwF8I#t(~S9BcRUgA$~Yzt32$xo3r9yxXZo*kDV`6ZQl zF=3+VJg#D*g`T9b88xILGw@~L>NP0qv0NX$Q#XKY$2?Ch)IQ-)#rF-+c#%gm#55`;qtRNu7);yLrOX z$WmeKQqnZvkNYHn3bgqUuZGrAl2Ub>=R=?_%_p!Fro&rIkz8|iML}m+g~3&p0kxWIv>kXX|O zi=ZlrCJ7NggSZ;KmF%$>z2_etA!s~|)%VO5HrDa16E4+RVSsZgTTENWZC{Q%a%uyA zd!+IhvOJSD4W_#jFuPqBBIBCO6Z|c3f$eZl3uiIwk@a7~gs4B+^LBO3UHTmZ4dWw9 zm0ej=_jWA&c9u5s_Cj`ix*XCp6;&Z^Zf6P3D}$-uRjPy6dUA!80$~&x<-Mp|%TWN)2rntmxT#ffw!0U_}oI zsgGVkY#y))y0|bX+9_`sx0iu#?AOiSm8zM~QXWVuF$nd_uErni35yTJj~2NwS12wv z#0PFgq%IrhW8!}K#C2KO>w=3)MifSrogQXER(wel!$6zb;Cn(k`73_)+*F}56&vU} zSLtv%&U^Rwgq9BKEL018yA-ig$g(q1$oY2nT3n{y${I6s$Afik5$wW}?!#lr3nAJW z^Ce;vf$MB3JtM?{;?0WeVDF$In@=qY#6_Li`E-JAPI>81>OU?E9SWpS`L6a{$We(y zdf#d2&sx3KNZq^oDLgZTV3!~4q--Y^xvA|@l@wgyokoGziZ12j4MQcG>E6funq7^# z?wqd`KwyChp2(UQbTV=APE$2dA?C!h5)_P(oIKXv&zQe;z>M=q}R9$^gn!v$r03F`*sP*N~Rela)y*YcZLBTbC7hlQx;~F!Idwt)TAaEZ*3z zIEmvht^%j)v2P97DY{1(FjTp__~8Y$pB_7?**akh6Qdc8voDT-Ns3L1EfUC%gCNtax3u z5yq!8A)i+uzah1FkKut>uVs$W>l<5fxY^eq&GR*?yyE&p^5Mvx7{|d>{=Rxeg`MpanD=I+@h2iGvg zRRzqGf-hBBR#8&0Gd{e$SUzNp(M}g3{IxIsbxYab#@A#B8$|t; zMs|rCv7t*`)V91mZPKYltF1Dp4%`nY&oFIHiz+%ImEyEG3sp3Z9K)yWmI zyKwuGZT`Y6uMMubYRknVwn5>&m9j_X_yftGSPa%L-z4LcC4tFJGHo`6@FPYoEf2l} zYEL$gfhRo~laj)~CLg1&5^=+tH+gNfaQNM=06tvuX&o=;t#yxd3|IV#J~i~l5Nd48_bBiax}3SWPJa%^d}&Kuwi&~%RCtf=ZH$6HkpfSt6YR^`)fi%h=o{=AoZ^}l z&&TBSC(Pf`nJtnr-YOoG+Q1e}D+2q!CxI@OaG$@(c_p+~kS2R~MgF8l6&61ox9uF) zW9a_IZ0yFKdgjX0!Cp$(BaIMA#MfTS?ksW4fq|pQK#<>9pQxy1*yP#zn2~wabCF@T zvJZWmKx4_*H@T;~(!^mkClVj{Gkhnu&#US_M)in8z%%sjHlN7mSIsH}A@?8y+EEXG zUeci=AdZo{qI4uhpsTQk51*_9#~A9|P!l8Hkva;{VK(T_N1ncx`oqd^Om26i&K`sD zoG`8XHf%d|gI0+1xgPEt3p%g8|K^7^uG!)0Q#$ib-h;5%fNm>S0=*s4yKPK7*|y6x z)}Z^_l5Gj&<#S5Q!wNY)N?xHxVuzeC?TO#QQ_zJViftGDQ8S8K*&SQ{?8As||FDM> z+G$O3-wgcVMA_Z-WfR~Hb!uQVVHd9fl8O#?+3H&>ZW-lNjf%y0iPht!o+JzB_PDtX z%;wu*nw|1wFNG5Fb$F$WJ`1gF;dLDAW~BOW@TQ}*pMUek56i@D|32!TL%1HRZPa_- zAyue04=A$K&Y^zW_`n@g#&pqJYF;=0oK)5*d&&tCym*eEjHr{_7p@C|_z(Uazkd9f z7o3JZ?c(c)F^tME%{=2iJU*5c9nO9vAqX{)CEr6EUW<Qv1y zm(8!~1aFk3w?5bjxPoRF%%1sVrMJwi{lLNv zST4gk6GU+S9p&$+TE%0g;A-$!Mihf;R5_U8sXYZefPV3D-OyT9hDxcX_iMi+N-C54 znRa6%qeq?2uVeY%_kWrbGF0keV|rHAM0_a&v*xU~a1A%Wx83(S`X*DMe0@QfRpHws z(IuoDKDuug?&~~X&zL5)WrgdppoCTZMi0Zv!$THv0}2v;^|s+Rt6smEy7j0@B!vP$ zV=7jw_*<~nj1b?J2?oz>?jTNXhuPnu8sZ?Ke~gZw3#=fhOx=ZUFI?ErU}cK-S71mS zqi%UA^5hx3i}^gkXp1gryW~V`;P7vxrEJyqYFw9)y={rZDJxAJjcIm6_<; zw#)sI_uSMCDqi&SO<{F1UcRfI*=x{nEr!YN3{k<-0v+NadFvjWiPg<0`2M)0q%nPGos|#G6~JO6e?kHTx0lzhw5k%{0o{z8Htk z@P1B8d>n^Cd4^#F4ye!rHQUdn5d*d$S@NTxO**7v?u| z=3Rb%9QM~7^niWs3chIFv;3|7#!u$>?FBBG5vit|CGv~TIbF74gzgIeXYNN_+9{B- zqI(U()5Bk*U47e1nPS<4-Q^2;ovJ4zf>3bZ`CLL)&IzEZX6=lq_;cV3!&EI}Na+RX zaz2BH7s$i{5C?eSoO)Y4$Fa3$msWLkg3mTNU0w)iUC5?a{)Q^t%#)bmeC^CZ-#s!! znECm&;hf{I-C+JEqO(VI|A%T>6kpNKtvIt+#YkC)P$Obl_%&j^NgBN(UaF7rnAnA* z6_&S6a{U}@fT<>eK9(hoiEYRs0%(vUm_dre^H3oT6e$jU*a-uGRHgr2zQnbyhHY4! zKhuIlx0*|dP=_3i@{yGJCj*u)!N7ATNwTgafjq)tc7bXBBEhvQ<=#{sc8i}5G}S`%&EgJ^?tdi1y53$vsf z_B^15CQAbc7o7t{+%tvMs(pN9I+$^yZ~Nz}V4rY8SJTbrH;P&~W$`A;LQTnq@X`AX z%F0cpZXUx0hPe%db1x@`cn*91ye(0}Y+&klFQ2z^r8z5G#RiZu2;3JYFE;?Gh-dyt zh#CnJIlZRmR)5&$M6@_rNmE9tb9G5dO6sL)wSc>nb6K^15s61Lv9WS;KUJ#EH|@lC zRqJ6Ck(w3$ac1|wW2?lP9>rIN)CumLYT}er&S@Ew8ohgwVQkPmjA^# zB^PYr&%-CHm75$4zb{7xxgMLbkZBUruG}58+;NXP;OzcgP8i!t*HEZf3}X)VjFT%+ zbpNF`aw*g(v&~Ej8@@ItY^{9pO-TB?;9))-XgF4Yua^K4IJJIlmNYA!3UX7~@1AEV zskY9#6NO_3rg_qS4?Dt_m4r8TUKRM1v<$+11MY;~XgB$io%%S$IIf>5C^vsCJ#Qzc z`##3-du9QAl&+!6eu`l7t6%`=`9Y?!6@dc;))Q+BN{-t=<{_fs%V>b|RqQtX-URrV z^xY1lITYaA^bFWP$juGCYWzq$`=V^~$7+`?@j)evhT6{2$j&%9d&5 zAKpeW$1Hl!9Ej_h+9dS;&RZK59;ujp&AhjLt}gY0oU+TGIv;i$oc{LJxWc15u1P<~ zrkRi~v3Vw;UVr2n$wy9FH8nm1G>tT|_Y>h|4kUl_8o*TEaXcPv;c~LfC1DLqzXjPKmdUx^xPdszi;l`@40`#z3|g{ zI5}sZv-jF-z3W}&xP*lHjO|OPG+;e!inhevUMYuoO<6gLHaBDIyy@}Y3v;d;5oBvS zHA(FkmCC;gsaJTED&S>qtO!dl6ah_RwXGyVY{PD)na|MZ0G3+k9g{s}?;{k#U;V!7 z*Grdzgb(K{Q6pEbV^_NOF;~VQhGi{*1CmALXn0k4rKTx@zW@pKxmJ!7nTUiAVxPj5 zWSyKfrh%hh0?Xbi%1}P|1v}pY8++$>6Imj0rs6c^#Bs&y-k)*Pu&aJ)u9%B!v-jGI z8^+!GR`5|V_gOVQ3l2Xx#`VAH%O>vlA;unSmKd35WfR+Yej_seIZ>%djneyh!3R^c4 zHsBk@`!0z#Ms;7r!EWbBg8cO-N=__7ZmCMtOg)UHvJ7o-WyH*2i1B>iMYn zoB?v6lc7Cz5LzFRI69_#Aw`rCj-~Y(A3k;B51u-djeqLxBcxJ_yRQF-w|3hS>5A<& z{BYmh(6Gg5%@|vYdHs5KR7MhOw{wOT^U$s_hr-}|-YW<>4VSu?F!vT(|9Km;sBz(t zJagtURQVL=O~_u4VmPN1TOrnXDaZT4=;z1_-{XPG`++7{qIgp6=N(QMU-3Ce%u}peFN<==UKM8Gv+=D zS-ZWIJru)5aPssXTRL>q1Y}o;O?(suso__5cv#IJq^p1p!~j)3_`@Hxfws>0sc?q9 zoJ7lw_nLYe{7Xxy`7BMQe-Z;(yeH!lI$*JO0UKa2@?J@?x}zrZ*N;`XV<+|5umBMm z97PSf@#6FzT+@T4cL4sAKj%X0{hls=>ZhtC(d1v?0E)VF5abj}f#tS&@DBlZlZXt$ zE-NjjLB{(g^kn#BZpke5keSm}=xy`F7D}>h1nz9^;2)t#T(XxSgLN&}t;oz9V=+rA zNS?KaPU)WyZ%AW>$n&(|jxu5;UC`M-%lr#38}2fv|HkDi(qLAxsEYf4!D)KI%fApD zpcGy-)+iahKd=EAZ-&pPcAhh%>3)Bj1Lc;;{4_rTVfH;kF)1uql0#$YlYy{AY5|i| z+ZRZ*2x@+NySTMiRsH;9_cWH4*+GH3d7D6Uo1NI*j z)pqk7S)~%KW_oVCmbqQTZYjo z=CexjyAg+(s>v7VV*~PTK^#KO287{#RxN{o4&Th^5Xq|i?H!Qr#{fPHvFcnC>xdAa zDFA$C4sQUqp~i?}OL$(=8(Ry19rj|T$@@jj_K2Mnzp-0EagYG>*+6yo(18xhe8sNw zg3@tmKW56P(l%{L>siW#F+Q+gKB+%6aWo|GObSpS8^YPQ8(a~VC@R{wR93FU1DUA^ zXkL7p6405(U(#WB0+&T`6GK=@jdi$WcaR~aSRIb-uwT62$W#iS-2N*&tzeo`asAl6 zI@acd*0V!ttTgCam4)X{x~()VhThH3R#<$sgJ>U68`=E(YT`Q>7TyMhm$IoT zFYuy`IAqegJmayd|%v*04i8P`YvBHLA$M0(8;U(P<2A1bm*c*UCAqRxVSlq^8;F0pjpZex827!eVvX zD$tt@r*`p@A!+#WfMa9nvJq_%LDeT{t9GXUE3cZKQ-&wJg7maq@y>TvdRm5P^sOZc_u#X^0!=ocSN_z)h1+qnp4s*r96T3YIl-e+%oBB#C1A07mP2M5^d?e45r(%Y> zW26$8vS_a2+e6OyUOc@vm?Zv+Jzn{xBI0^us=(uhFp`_M#Zty2xrqr`Y<_T3HHj4h zWowNr|M_W_l5_%np#W7IfyVX`B4(~(^vceybtzQ0UYqtBcr%^KN@41UnYE%MN>v{` zmHi}h`1rt%i3C;W;ee>mF&#He!6a?MMTuwEJ^rA&otRV564lOIghq$9OJp$k@tTp_ zLR#Lq2m`*g!fNuC0oc|bdhm_=MHw9lO|QU zB!z1jt7Gz&imr@spoDA|f4pvCJAoSjRn1}vBg8k~{0jgRLOc zKCll+*_Le}@(5ZL$C><;D&MHgl(wp4!d-LgH^ew&BQ&D-Px%H<3WL99Nu}^~nt7_z zyGkPGT$5DyPCj1?N~j`grLzJ75h}{pLLq|qkcQI7CLGhssSYL0Ni?I$C#KfSKdgBU zQY0mFHDD-(^-NvrTtG)u=PPDEFGwpREZ%|QG1@^^@o$=Ar$~b+abTXRI>d}4??&Z{y!td3gPT_3uEKgk?I8Yb?7g q2M-8es(qlfV~9@4 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 D=7J3{ literal 0 HcmV?d00001 diff --git a/static/pic/SWMU-logos_transparent2.png b/static/pic/SWMU-logos_transparent2.png new file mode 100644 index 0000000000000000000000000000000000000000..1987eeae0f263e0f1c20b3fbf54680c2baf1cfb0 GIT binary patch literal 16453 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 literal 0 HcmV?d00001 diff --git a/static/pic/SWMU-logos_transparent3.png b/static/pic/SWMU-logos_transparent3.png new file mode 100644 index 0000000000000000000000000000000000000000..ca8b9b32556357a3a7ae1dfcc25d1435a3de214c GIT binary patch literal 28537 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 literal 0 HcmV?d00001 diff --git a/static/pic/favicon.ico b/static/pic/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c3bca6c625d73f87860860479b7cf01a77e10ed2 GIT binary patch literal 34494 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 literal 0 HcmV?d00001 diff --git a/templates/helpswmu.html b/templates/helpswmu.html new file mode 100644 index 0000000..93a37c0 --- /dev/null +++ b/templates/helpswmu.html @@ -0,0 +1,143 @@ + + + + + + + + +
+ +
+ + + + + + + + + + +SWMU + + + +
+
+SWMU examples:
+
+Example for 5 Software Mobile Units and server host `localhost`:
+$ runswmu 5 --mode run
+$ runswmu 5 --mode sim --log ./test_log.log
+$ runswmu 5 --mode simfast --log ./test_log.log --simulate_pause 0.25
+
+Other examples:
+$ runswmu 1 --mode run --server-host localhost --start-id32 3567779841
+$ runswmu 1 --mode sim --server-host localhost --start-id32 3567779841 --log ./test_log.log
+$ runswmu 1 --mode run --server-host 10.48.172.135 --start-id32 3567779841 --bt-spontaneous-timeout 5  --simulate_pause 0.25
+$ LOG_LEVEL="INFO" runswmu 5 --mode sim --server-host localhost --start-id32 3567779871 --bt-spontaneous-timeout 5  --simulate_pause 0.25 --log ./test_log.log
+$ LOG_LEVEL="INFO" runswmu 2500 --mode run --server-host 10.48.172.135 --bt-spontaneous-timeout 20 --sigma 3 --sta True --sta-pause 60 --x01-pause 11 --x1d-pause 250 --x1a-pause 18 --x1a-type 1
+        --domain DE00 --near_by_domain CZ00 --start-id32 3567779841
+$ runswmu 1 --mode run --server-host 10.48.172.135 --start-id32 3567779841 --bt-spontaneous-timeout 5  --simulate_pause 0.25
+$ runswmu 50 --mode simfast --server-host localhost --start-id32 3567779841 --log ./test_log.log --simulate_pause 0.25
+
+how to create pod (k8s):
+$ kubectl [-n namespace] run [name_of_pod] --rm -i --tty --image [name_of_image] -- /bin/bash
+$ kubectl -n uhura-azure-wagexp run swmu --namespace=uhura-azure-wagexp --image=principazureacr.azurecr.io/uhura/swmu-0.1.0 --requests=cpu=100m,memory=512Mi --limits=cpu=200m,memory=2048Mi --rm -i --tty -- /bin/bash
+$ kubectl -n uhura-azure-wagexp run swmu --rm -i --tty --image=python -- /bin/bash
+
+how to add mulog_file to k8s pod:
+$ kubectl [-n namespace] cp [path to mulog file] [pod_name]:/
+$ kubectl -n uhura-azure-wagexp cp /home/directory/test_log.log swmu:/data
+
+
+
+
+SWMU arguments (command runswmu -h):
+
+mandatory arguments:
+  UNITS                 unit amount
+  --mode MODE           mode run | sim | simfast
+
+optional arguments for "run" mode:
+  --latitude LATITUDE   latitude (default 47.687622035085916)
+  --longitude LONGITUDE
+                        longitude (default 17.744894027593666)
+  --domain DOMAIN       current domain (default HU00)
+  --near_by_domain NEAR_BY_DOMAIN
+                        near by domain (default HU00)
+  --x01 GENERATE_X01    generate x01 (default True)
+  --x01-pause X01_PAUSE
+                        x01 pause in seconds (default 5s)
+  --units-wo-x1a UNITS_WO_X1A
+                        amount of units that will not generate x1a (default 0)
+  --x1a-pause X1A_PAUSE
+                        x1a pause in seconds (default 10s)
+  --x1a-mask X1A_MASK   x1a mask-type of log: 01 - without Regain signal flag; 17 - with Regain signal flag (default)
+  --x1a-type X1A_TYPE   x1a type of log (number of positions): 0 - (default); 1 - 17pos; 2 - 33pos
+  --x1d GENERATE_X1D    generate x1d (default True)
+  --x1d-pause X1D_PAUSE
+                        x1d pause in seconds (default 60sec)
+  --x1d-weight_axles X1D_WEIGHT_AXLES
+                        x1d weight + number of axles: 'auto' - generate 2-10 (default); '42' - set weight 4, axle 2; '76' - set weight 7, axle 6;
+
+optional arguments for "sim" or "simfast" mode:
+  --log IMPORT_DIR      path to simulated log (obligatory with "sim" and "simfast" mode)
+  --simulate_pause SIMULATE_PAUSE
+                        used for mode "simfast" to set delay between each message in seconds (default 2s)
+  --sim_time_check SIM_TIME_CHECK
+                        used for mode 'sim' to check timestamp:
+                        1) if 'no' is set, there is no changes in timestamp (default)
+                        2) if 'max' is set, the the wait between two messages cannot be greater than 60s
+                        3) if 'max_y' is set, the messages older then 5 years are ignored
+  --sim_stop SIM_STOP   turn off/on auto-loop-close for sim/simfast mode (default True)
+
+
+shared arguments:
+  -h, --help            show this help message and exit
+  --server-host SERVER_HOST
+                        server host (default localhost)
+  --server-port SERVER_PORT
+                        server port (default 31001)
+  --start-id32 START_ID32
+                        start id32 (default 3567779840)
+  --start-port START_PORT
+                        start port (default 1024)
+  --bt-spontaneous-timeout BT_SPONTANEOUS_TIMEOUT
+                        BT spontaneous timeout in seconds (default 20)
+  --sigma SIGMA         sigma in seconds (default 0.2)
+  --sta SEND_STA        send sta (default True)
+  --sta-pause STA_PAUSE
+                        STA pause in seconds (default 30sec)
+
+
+    
+
+ +
+ +
+ + + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..575c3c9 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,24 @@ + + + + + The jQuery Example + +

jQuery-AJAX in FLASK. Execute function on button click

+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/index_v2.html b/templates/index_v2.html new file mode 100644 index 0000000..8ae5239 --- /dev/null +++ b/templates/index_v2.html @@ -0,0 +1,636 @@ + + + + + + + + +
+ + TEST +
+ + + + + + + + + + +SWMU + + + +
+ +
+ +
+ +
+
+ +
+ + +
+ + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + + + + +
+ +
 
+ +
+ +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ + +
+ + +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ + +
+ +
+
+ +
+ + + + +
+ +
+ + + + +
+ +
+
+ + +
+ + +
+ +
+
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ +
+ + +
+ + + +
+ + +
+ + + + + + + + + +
+ {% if clear == False %} + {% if questions %} +
+ {% for question in questions %} + {% if "None" == question.mode %} +
+ LOG_LEVEL="{{question.loglevel}}" runswmu {{question.number_swmu}} --mode run --start-id32 {{question.id32}} --server-host {{question.server_host}} --server-port {{question.server_port}} --start-port {{question.start_port}} --bt-spontaneous-timeout {{question.bt_spontaneous_timeout}} --sigma {{question.sigma}} --sta {{question.sta}} --sta-pause {{question.sta_pause}} --ft_delay {{question.ft_delay}} --ft_mode {{question.ft_mode}}
+
+ + {% elif "run" == question.mode %} +
+ LOG_LEVEL="{{question.loglevel}}" + runswmu {{question.number_swmu}} + --mode {{question.mode}} + --start-id32 {{question.id32}} + --server-host {{question.server_host}} + --server-port {{question.server_port}} + --start-port {{question.start_port}} + --bt-spontaneous-timeout {{question.bt_spontaneous_timeout}} + --sigma {{question.sigma}} + --sta {{question.sta}} + --sta-pause {{question.sta_pause}} + --ft_delay {{question.ft_delay}} + --ft_mode {{question.ft_mode}} + --latitude {{question.latitude}} + --longitude {{question.longitude}} + --domain {{question.domain}} + --near_by_domain {{question.near_by_domain}} + --x01 {{question.x01}} + --x01-pause {{question.x01_pause}} + --units-wo-x1a {{question.units_wo_x1a}} + --x1a-pause {{question.x1a_pause}} + --x1a-mask {{question.x1a_mask}} + --x1a-type {{question.x1a_type}} + --x1d {{question.x1d}} + --x1d-pause {{question.x1d_pause}} + --x1d-weight_axles {{question.x1d_weight_axles}}
+
+ + {% elif "sim" == question.mode %} +
+ LOG_LEVEL="{{question.loglevel}}" + runswmu {{question.number_swmu}} + --mode {{question.mode}} + --start-id32 {{question.id32}} + --server-host {{question.server_host}} + --server-port {{question.server_port}} + --start-port {{question.start_port}} + --bt-spontaneous-timeout {{question.bt_spontaneous_timeout}} + --sigma {{question.sigma}} + --sta {{question.sta}} + --sta-pause {{question.sta_pause}} + --ft_delay {{question.ft_delay}} + --ft_mode {{question.ft_mode}} + --log {{question.log}} + --sim_time_check {{question.sim_time_check}} + --sim_stop {{question.sim_stop}}
+
+ + {% elif "simfast" == question.mode %} +
+ LOG_LEVEL="{{question.loglevel}}" + runswmu {{question.number_swmu}} + --mode {{question.mode}} + --start-id32 {{question.id32}} + --server-host {{question.server_host}} + --server-port {{question.server_port}} + --start-port {{question.start_port}} + --bt-spontaneous-timeout {{question.bt_spontaneous_timeout}} + --sigma {{question.sigma}} + --sta {{question.sta}} + --sta-pause {{question.sta_pause}} + --ft_delay {{question.ft_delay}} + --ft_mode {{question.ft_mode}} + --log {{question.log}} + --sim_time_check {{question.sim_time_check}} + --sim_stop {{question.sim_stop}} + --simulate_pause {{question.simulate_pause}}
+
+ + {% endif %} + {% endfor %} +
+ {% endif %} + {% else %} +
+ + {% endif %} + +
 
+
 
+
 
+
+ +
+ +
+ + + \ No newline at end of file diff --git a/templates/info.html b/templates/info.html new file mode 100644 index 0000000..e381b35 --- /dev/null +++ b/templates/info.html @@ -0,0 +1,51 @@ + + + + + + + + +
+ +
+ + + + + + + + + + +SWMU + + + +
+ +
+ + + \ No newline at end of file diff --git a/templates/mulog_read.html b/templates/mulog_read.html new file mode 100644 index 0000000..232848e --- /dev/null +++ b/templates/mulog_read.html @@ -0,0 +1,202 @@ + + + + + + + + +
+ +
+ + + + + + + + + + + +SWMU + + +
+
supports only .log format with max file size {{ max_size }}mb
+
+
+
+
+ + + + + + + + +
+
+ {% if files %} + {% for file in files %} + +
+ Download log + Download position file + +
name: {{files}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
x01_log_book_record: {{mulog[0]}} +  info + x04_driver_login: {{mulog[1]}} +  info +
x05_driver_logout: {{mulog[2]}} +  info + x08x09_log_record: {{mulog[3]}} +  info +
x08x09_log_record: {{mulog[4]}} +  info + x13_driving_style: {{mulog[5]}} +  info +
x1400_accelerometer_event: {{mulog[6]}} +  info + x25_perfect_drive: {{mulog[7]}} +  info +
x26_long_mext: {{mulog[8]}} +  info + x0b_log_record: {{mulog[9]}} +  info +  info + +
x0d_log_record: {{mulog[10]}} +  info + x1a_fastlog: {{mulog[11]}} +  info +
x1c_log_record: {{mulog[12]}} +  info + x1d_domain_vehicle_parameters: {{mulog[13]}} +  info +
0x0e_record: {{mulog[15]}} +  info + other_type: {{mulog[16]}}
0x10_record: {{mulog[14]}} +  info +
+ + + + + +
number of timestamps: {{ts_c}}number of positions: {{pos_c}}
+ + {% if pos_c > max_pos %} + + + + +
recommended amount position for rendering is {{max_pos}}, otherwise, it may cause delay or instability
+ {% endif %} + + {% if warn %} +
+ timestamp in mulog is suspicious ([row in mulog], [message], [timestamp]): {list_ts_warning} {{warn}} +
+ {% endif %} + {% if text %} + {{text}} + {% endif %} +
+ {% endfor %} + {% endif %} +
+ +
+
+ + {% if files %} + {% if text %} + {% else %} +
+ +
+ {% endif %} + {% endif %} +
+ +
+
+
 
+
 
+
 
+
+ +
+ +
+ + + \ No newline at end of file diff --git a/templates/test.html b/templates/test.html new file mode 100644 index 0000000..95a3ce0 --- /dev/null +++ b/templates/test.html @@ -0,0 +1,17 @@ + + + + File Upload + + +

File Upload

+
+

+

+
+
+ {% for file in files %} + + {% endfor %} + + \ No newline at end of file diff --git a/uploads/.a b/uploads/.a new file mode 100644 index 0000000..e69de29