diff --git a/callbacks.py b/callbacks.py
deleted file mode 100644
index 4e8e0a4bed84d76efba5bcd2d8cb4903b4697d7a..0000000000000000000000000000000000000000
--- a/callbacks.py
+++ /dev/null
@@ -1,265 +0,0 @@
-import dearpygui.dearpygui as dpg
-import tifffile
-from uuid import uuid4
-
-from utils import *
-from constants import SPACE, TREE_COLOR, ROAD_COLOR, BUILDING_COLOR
-from remote_run import start_execution_lab_server, start_model_build, get_server_output_structure
-from map_edit import dump_height_map, load_height_map, update_texture
-from styles import get_accent_color, apply_theme
-from generator import LCZ
-from config import load_config, dump_config
-from dynamic_ui import construct_config_ui, construct_model_output_structure_ui
-
-def map_window_on_close_clb(s, a, u):
-    delete_item_and_clear_alias(f'map_buildings_texture')
-    delete_item_and_clear_alias(f'map_trees_texture')
-    delete_item_and_clear_alias(f'map_roads_texture')
-    delete_item_children_and_clear_aliases(f'map_drawlist')
-    user_data = {
-        'buildings_map': None,
-        'trees_map': None,
-        'roads_map': None,
-        'height_map_file_path': None,
-        'drawing': False,
-        'prev_coords': None,
-        'current_action': None,
-        'max_height': 0,
-        'output_dirs': None,
-    }
-    dpg.set_item_user_data('map_window', user_data)
-
-def set_file_path_clb(s, a, u):
-    file_path = a['file_path_name']
-    dpg.set_value(u, file_path)
-
-def construct_config_ui_clb(s, a, u):
-    if not get_config_file_path():
-        return
-    delete_config_items_and_clear_aliases()
-    update_config_values()
-    construct_config_ui(get_config_file_path(), get_config())
-
-
-################################################################################
-#
-#       Config
-#
-################################################################################
-
-
-def update_config_values():
-    config = get_config()
-    for path in config:
-        if dpg.does_item_exist(f'{get_config_file_path()}.{path}'):
-            config[path].value = dpg.get_value(f'{get_config_file_path()}.{path}')
-    set_main_window_value('config', config)
-
-def config_save_as_clb(s, a, u):
-    update_config_values()
-    dump_config(get_config(), a['file_path_name'])
-    dpg.show_item('message_popup')
-
-def config_open_clb(s, a, u):
-    delete_config_items_and_clear_aliases()
-    config_file_path = a['file_path_name']
-    config = load_config(config_file_path)
-    set_main_window_value('config', config)
-    set_main_window_value('config_file_path', config_file_path)
-    construct_config_ui(a['file_path_name'], config)
-
-def config_save_clb(s, a, u):
-    update_config_values()
-    dump_config(get_config(), get_config_file_path())
-    dpg.show_item('message_popup')
-
-def open_config_open_dialog_clb(s, a, u):
-    dpg.show_item('config_open')
-
-def show_config_search_window_clb(s, a, u):
-    dpg.show_item('search_popup')
-
-def open_config_save_as_dialog_clb(s, a, u):
-    dpg.show_item('config_open')
-
-################################################################################
-#
-#       Config Search
-#
-################################################################################
-
-
-def search_clb(s, data, u):
-    if not get_config_file_path():
-        return
-
-    if not data:
-        return
-
-    for path in get_config():
-        if data.lower() in path.split('.')[-1]:
-            dpg.set_y_scroll('main', dpg.get_item_pos('.'.join([get_config_file_path(), path.split('.')[0]]))[1])
-            for tag in path_iter(path, prefix=get_config_file_path()):
-                if dpg.get_value(COLLAPSING_HEADERS_UI) == True:
-                    dpg.set_value(tag, True)
-                else:
-                    dpg.set_value(dpg.get_item_parent(dpg.get_item_parent(tag)), dpg.get_item_parent(tag))
-            change_color_temporarily('.'.join([get_config_file_path(), path, 'text']), color=get_accent_color())
-
-
-################################################################################
-#
-#       Map edit
-#
-################################################################################
-
-def construct_map_layers(w, h):
-    dpg.set_item_width('map_child_window', w)
-    dpg.set_item_height('map_child_window', h)
-
-    # dpg.add_texture_registry(tag='textures')
-    dpg.add_dynamic_texture(w, h, np.zeros(w * h * 4), tag=f'map_buildings_texture', parent='textures')
-    dpg.add_dynamic_texture(w, h, np.zeros(w * h * 4), tag=f'map_trees_texture', parent='textures')
-    dpg.add_dynamic_texture(w, h, np.zeros(w * h * 4), tag=f'map_roads_texture', parent='textures')
-
-    dpg.bind_item_theme('map_child_window', 'map_image_theme')
-    dpg.add_drawlist(w, h, tag=f'map_drawlist', parent='map_child_window', pos=[0, 0])
-
-    dpg.draw_image(f'map_buildings_texture', color=BUILDING_COLOR, tag=f'map_buildings_image', pmin=(0, 0), pmax=(w, h), parent=f'map_drawlist')
-    dpg.draw_image(f'map_trees_texture', color=TREE_COLOR, tag=f'map_trees_image', pmin=(0, 0), pmax=(w, h), parent=f'map_drawlist')
-    dpg.draw_image(f'map_roads_texture', color=ROAD_COLOR, tag=f'map_roads_image', pmin=(0, 0), pmax=(w, h), parent=f'map_drawlist')
-
-def map_open_clb(s, a, u):
-    height_map_file_path = a['file_path_name']
-
-    if height_map_file_path.endswith('txt'):
-        height_map = load_height_map(height_map_file_path)
-        max_height = np.max(height_map)
-        height_map /= max_height
-    else:
-        height_map = tifffile.imread(height_map_file_path)
-        max_height = 1
-
-    h, w = height_map.shape
-
-    print(dpg.get_item_user_data('map_window'))
-
-    set_map_window_value('buildings_map', height_map)
-    set_map_window_value('roads_map', np.zeros((h, w)))
-    set_map_window_value('trees_map', np.zeros((h, w)))
-    set_map_window_value('height_map_file_path', height_map_file_path)
-    set_map_window_value('max_height', max_height)
-
-    construct_map_layers(w, h)
-    
-    update_texture()
-
-    dpg.show_item('map_window')
-
-def generate_map_clb(s, a, u):
-    height_map = LCZ(config_path=f'configs/{s}.json').to_height_map(dtype=np.float64)
-
-    max_height = np.max(height_map)
-    height_map /= max_height
-
-    h, w = height_map.shape
-
-    set_map_window_value('buildings_map', height_map)
-    set_map_window_value('roads_map', np.zeros((h, w)))
-    set_map_window_value('trees_map', np.zeros((h, w)))
-    set_map_window_value('height_map_file_path', f'{uuid4()}.txt')
-    set_map_window_value('max_height', max_height)
-
-    construct_map_layers(w, h)
-
-    update_texture()
-
-    dpg.show_item('map_window')
-
-def save_map(file_path):
-    if file_path.endswith('.tif') or file_path.endswith('.tiff'):
-        with TiffWriter(file_path) as tif:
-            tif.write(get_map_window_value('buildings_map'))
-            tif.write(get_map_window_value('roads_map'))
-            tif.write(get_map_window_value('trees_map'))
-    else:
-        dump_height_map(get_map_window_value('buildings_map'), file_path)
-
-def map_save_clb(s, a, u):
-    file_path = get_height_map_file_path()
-    save_map(file_path)
-    dpg.show_item('message_popup')
-
-def map_save_as_clb(s, a, u):
-    file_path = a['file_path_name']
-    save_map(file_path)
-    dpg.show_item('message_popup')
-
-def open_map_save_as_dialog_clb(s, a, u):
-    dpg.show_item('map_save_as')
-
-def open_map_open_dialog_clb(s, a, u):
-    dpg.show_item('map_open')
-
-def set_action_clb(s, a, u):
-    set_map_window_value('current_action', s)
-
-def set_action_none_clb(s, a, u):
-    set_map_window_value('current_action', None)
-
-
-################################################################################
-#
-#       Styles
-#
-################################################################################
-
-
-def apply_theme_clb(s, a, u):
-    apply_theme(s)
-
-
-################################################################################
-#
-#       Remote execution
-#
-################################################################################
-
-
-def start_remote_execution_clb(s, a, u):
-    dpg.configure_item('login_modal', show=False)
-    u = dpg.get_item_user_data('login_modal')
-    if u == 'build_model':
-        start_model_build(dpg.get_value('server_username'), dpg.get_value('server_password'), dpg.get_value('gitlab_username'), dpg.get_value('gitlab_password'))
-    elif u == 'run_on_lab_server':
-        start_execution_lab_server(dpg.get_value('server_username'), dpg.get_value('server_password'))
-    elif u == 'download_output':
-        s = get_server_output_structure(dpg.get_value('server_username'), dpg.get_value('server_password'))
-        folders, filepaths = parse_dirs(s)
-        delete_item_children_and_clear_aliases('output')
-        construct_model_output_structure_ui(filepaths, folders)
-        dpg.show_item('model_output_window')
-
-def build_model_on_lab_server_clb(s, a, u):
-    pass
-
-def show_get_credentials_modal_clb(s, a, u):
-    dpg.set_item_user_data('login_modal', u)
-
-    if u == 'run_on_lab_server':
-        if not get_config_file_path():
-            show_status_text('no config.txt specified. cannot run.')
-            return
-
-        update_config_values()
-    
-        dump_config(get_config(), 'tmp.txt')
-
-        dpg.hide_item('gitlab_password') 
-        dpg.hide_item('gitlab_username')
-
-    elif u == 'download_output':
-        dpg.hide_item('gitlab_password') 
-        dpg.hide_item('gitlab_username')
-
-    dpg.show_item('login_modal')
\ No newline at end of file
diff --git a/config.py b/config.py
index a35a5417feb8dee77fd42fb9c372fbabdaaa6460..a68c6779240763255e1f670be2cb0417ee72be90 100644
--- a/config.py
+++ b/config.py
@@ -163,6 +163,7 @@ def load_config(file_path):
     config = parse(text)
 
     for line in lines:
+        line = line.strip('\r\n')
         match = re.match(r" > (\w+) '(.*)' = *(.*)", line)
         if match:
             value_type, path, value = match.groups()
@@ -251,4 +252,6 @@ def dump_config(config, file_path):
 
 
 if __name__ == '__main__':
-    print(load_config('../config-ex.txt'))
\ No newline at end of file
+    cfg = load_config('../config-neutral-ex.txt')
+    print(cfg)
+    print(dump_config(cfg, '../cfg.txt'))
\ No newline at end of file
diff --git a/config_callbacks.py b/config_callbacks.py
index 0cf9b6c5e9ca9b32cdd104694b4f67fb6b2ef6e5..967e4b991c7aff6bbc33f4bc889e9ea9e8ba0cb3 100644
--- a/config_callbacks.py
+++ b/config_callbacks.py
@@ -1,6 +1,6 @@
 import dearpygui.dearpygui as dpg
 
-from utils import get_config_file_path, delete_config_items_and_clear_aliases, update_config_values, get_config, update_config_values, set_main_window_value, change_color_temporarily, path_iter
+from utils import show_message, get_config_file_path, delete_config_items_and_clear_aliases, update_config_values, get_config, update_config_values, set_main_window_value, change_color_temporarily, path_iter
 
 from style_constants import SPACE, COLLAPSING_HEADERS_UI
 from style import get_accent_color, apply_theme
diff --git a/map_edit_callbacks.py b/map_edit_callbacks.py
index f13050f26e26fe1e3f2e6c4347fbfdee780cdac0..48dbe38e5b2142acbbc3319ec966d9e202a77a96 100644
--- a/map_edit_callbacks.py
+++ b/map_edit_callbacks.py
@@ -1,3 +1,5 @@
+import os
+
 import dearpygui.dearpygui as dpg
 import tifffile
 import numpy as np
@@ -5,6 +7,7 @@ import numpy as np
 from map_edit_constants import TREE_COLOR, ROAD_COLOR, BUILDING_COLOR, LAYER_TO_COLOR
 from map_edit import dump_height_map, load_height_map, update_texture
 from generator import LCZ
+from paths import BASE_PATH
 from utils import show_message, set_main_window_value, get_config, get_config_file_path, delete_item_and_clear_alias, delete_item_children_and_clear_aliases, set_map_window_value, get_map_window_value, get_height_map_file_path
 
 def delete_emission_point_clb(s, a, u):
@@ -159,7 +162,7 @@ def map_open_clb(s, a, u):
     dpg.show_item('map_window')
 
 def generate_map_clb(s, a, u):
-    height_map = LCZ(config_path=f'configs/{s}.json').to_height_map(dtype=np.float64)
+    height_map = LCZ(config_path=os.path.join(BASE_PATH, 'configs', f'{s}.json')).to_height_map(dtype=np.float64)
 
     max_height = np.max(height_map)
     height_map /= max_height
diff --git a/paths.py b/paths.py
index ebb9cf724d6f49b379435f20faafb17b32634fdc..c92170276438cd2d7ff286e0b2024639b3b6da08 100644
--- a/paths.py
+++ b/paths.py
@@ -1,5 +1,8 @@
 import os
+import sys
 
-FONT_PATH = os.path.join('fonts', 'Montserrat-Medium.ttf')
-ICON_PATH = os.path.join('icons', 'icon.ico')
-CONFIG_PARSER_EXECUTABLE = "config-parser/parser-cli"
\ No newline at end of file
+BASE_PATH = getattr(sys, '_MEIPASS', os.getcwd())
+
+FONT_PATH = os.path.join(BASE_PATH, 'fonts', 'Montserrat-Medium.ttf')
+ICON_PATH = os.path.join(BASE_PATH, 'icons', 'icon.ico')
+CONFIG_PARSER_EXECUTABLE = os.path.join(BASE_PATH, 'config-parser', 'parser-cli')
\ No newline at end of file
diff --git a/remote_run_callbacks.py b/remote_run_callbacks.py
index 87cdd2cb97bf612d99efa5437d9f763e585b383e..7356adeae0fc637da2b9cd4c11197a3f9fbd7ad0 100644
--- a/remote_run_callbacks.py
+++ b/remote_run_callbacks.py
@@ -8,7 +8,7 @@ from uuid import uuid4
 import dearpygui.dearpygui as dpg
 from paramiko.ssh_exception import BadHostKeyException, AuthenticationException, UnableToAuthenticate, NoValidConnectionsError, SSHException
 
-from utils import get_config_file_path, get_config, update_config_values, get_run_window_value, set_run_window_value
+from utils import show_message, get_config_file_path, parse_dirs, construct_folder_structure, get_config, update_config_values, get_run_window_value, set_run_window_value, delete_item_children_and_clear_aliases
 from remote_run import Connection, BuildingSession, RunningSession
 from remote_run_constants import *
 from style_constants import FONT_SIZE
@@ -201,7 +201,6 @@ def show_download_output_window_clb(s, a, running_session_id):
     stdout = conn.exec_command(f'cd ./{running_session_id}/output; find . -type f')
     output = stdout.read().decode()
     dirs, filepaths = parse_dirs(output)
-
     construct_model_output_structure_ui(filepaths, dirs)
 
     dpg.set_item_user_data('model_output_window', (dirs, filepaths, running_session_id))
diff --git a/remote_run_ui.py b/remote_run_ui.py
index cb4123a8015cfad724fef67716999a8a4b0ac7ca..fac0c38cb36c2726a5d2d3184e93e0ec2b7340a8 100644
--- a/remote_run_ui.py
+++ b/remote_run_ui.py
@@ -4,6 +4,7 @@ import os
 
 from remote_run_constants import *
 from remote_run_callbacks import *
+from remote_run import *
 
 def construct_remote_run_window():
     user_data = {