From cf2f49919e57ff8acf12481368f4d945fc2982fb Mon Sep 17 00:00:00 2001 From: Louis Date: Fri, 15 Aug 2025 09:10:29 -0700 Subject: [PATCH 01/51] Structure GUI composition and make buttons look more modern --- sw/.gitignore | 4 +- sw/wulpus/gui.py | 97 ++++++++++++++++++++++++++++++------------------ 2 files changed, 63 insertions(+), 38 deletions(-) diff --git a/sw/.gitignore b/sw/.gitignore index 513a04c..51088d2 100644 --- a/sw/.gitignore +++ b/sw/.gitignore @@ -4,4 +4,6 @@ # .json are user config files and should not be tracked, except for the configs in examples *.json -!examples/*.json \ No newline at end of file +!examples/*.json + +.venv \ No newline at end of file diff --git a/sw/wulpus/gui.py b/sw/wulpus/gui.py index 8d6f72a..43e33df 100644 --- a/sw/wulpus/gui.py +++ b/sw/wulpus/gui.py @@ -36,42 +36,45 @@ FILE_NAME_BASE = 'data_' -box_layout = widgets.Layout(display='flex', - flex_flow='column', - align_items='center', - width='50%') - class WulpusGuiSingleCh(widgets.VBox): - + def __init__(self, com_link:WulpusDongle, uss_conf, max_vis_fps = 20): super().__init__() - + # Communication link self.com_link = com_link - + # Ultrasound Subsystem Configurator self.uss_conf = uss_conf - + # Allocate memory to store the data and other parameters self.data_arr = np.zeros((self.com_link.acq_length, uss_conf.num_acqs), dtype='Wulpus") # Serial port related self.ser_scan_button = widgets.Button(description="Scan ports", disabled=False, @@ -97,6 +100,7 @@ def __init__(self, com_link:WulpusDongle, uss_conf, max_vis_fps = 20): description='Serial port:', disabled=True, style= {'description_width': 'initial'}) + # pre-populate by scanning once self.click_scan_ports(self.ser_scan_button) # Visualization-related @@ -148,6 +152,15 @@ def __init__(self, com_link:WulpusDongle, uss_conf, max_vis_fps = 20): self.start_stop_button = widgets.Button(description="Start measurement", disabled=True) + + # make buttons more visually prominent + try: + self.ser_scan_button.button_style = 'info' + self.ser_open_button.button_style = 'primary' + self.start_stop_button.button_style = 'success' + except Exception: + # older ipywidgets may not support button_style assignment + pass self.save_data_check = widgets.Checkbox(value=True, description='Save Data as .npz', @@ -155,30 +168,45 @@ def __init__(self, com_link:WulpusDongle, uss_conf, max_vis_fps = 20): self.save_data_label = widgets.Label(value='') - # Setup Visualization + # Setup Visualization output container self.output = widgets.Output() - self.one_time_fig_config() + def compose_layout(self): + """Compose the widget layout from the built widgets.""" + padding_layout = widgets.Layout(padding='6px') + gap_layout = widgets.Layout(gap='6px') + box_layout = widgets.Layout(display='flex', + flex_flow='column', + align_items='center', + width='100%') + flex_start_layout = widgets.Layout(justify_content='flex-start', width='100%') + + controls_1 = widgets.VBox([ + widgets.HBox([self.ser_open_button, self.ser_scan_button], layout=gap_layout) , + self.ports_dd, + self.tx_rx_sel_dd, + self.band_pass_frs + ], layout=padding_layout) - # Construct GUI grid - controls_1 = widgets.VBox([self.raw_data_check, self.filt_data_check, self.env_data_check, self.bmode_check]) - - controls_2 = widgets.VBox([widgets.HBox([self.ser_open_button, self.ser_scan_button]) , self.ports_dd, self.tx_rx_sel_dd, self.band_pass_frs]) - - controls = widgets.HBox([controls_1, controls_2]) - - out_box = widgets.Box([self.output]) + controls_2 = widgets.VBox([self.raw_data_check, self.filt_data_check, self.env_data_check, self.bmode_check], + layout=padding_layout) + + controls = widgets.HBox([controls_1, controls_2], layout=flex_start_layout) - progr_ctl_box_1 = widgets.VBox([self.start_stop_button, self.frame_progr_bar]) - progr_ctl_box_2 = widgets.VBox([self.save_data_check, self.save_data_label]) - progr_ctl_box = widgets.HBox([progr_ctl_box_1, progr_ctl_box_2]) + out_box = widgets.Box([self.output], layout=widgets.Layout(width='100%')) + progr_ctl_box_1 = widgets.VBox([self.start_stop_button, self.frame_progr_bar], layout=widgets.Layout(padding='6px')) + progr_ctl_box_2 = widgets.VBox([self.save_data_check, self.save_data_label], layout=widgets.Layout(padding='6px')) + progr_ctl_box = widgets.HBox([progr_ctl_box_1, progr_ctl_box_2], layout=flex_start_layout) - main_box = widgets.VBox([controls, out_box, progr_ctl_box]) - + # Compose main box with title and consistent box layout + main_box = widgets.VBox([self.title, controls, out_box, progr_ctl_box], layout=box_layout) - # Connect callbacks - + # attach to widget children + self.children = [main_box] + + def connect_callbacks(self): + """Wire up widget callbacks/observers.""" # To serial port related buttons self.ser_scan_button.on_click(self.click_scan_ports) self.ser_open_button.on_click(self.click_open_port) @@ -197,9 +225,6 @@ def __init__(self, com_link:WulpusDongle, uss_conf, max_vis_fps = 20): # To start stop acqusition button self.start_stop_button.on_click(self.click_start_stop_acq) - - # add to children - self.children = [main_box] def one_time_fig_config(self): @@ -387,8 +412,6 @@ def click_start_stop_acq(self, b): self.ser_open_button.disabled = False def run_acquisition_loop(self): - -# self.fig.show() # Clean data buffer acq_length = self.com_link.acq_length @@ -548,7 +571,7 @@ def get_envelope(self, data_in): def save_data_to_file(self): # Check filename - for i in range(100): + for i in range(1000): filename = FILE_NAME_BASE + str(i) + '.npz' if not os.path.isfile(filename): break From 4d4cd47eb1c1275109df33b77ece6062103815f7 Mon Sep 17 00:00:00 2001 From: Louis Date: Fri, 15 Aug 2025 09:15:34 -0700 Subject: [PATCH 02/51] make formatting consistent --- sw/wulpus/gui.py | 277 ++++++++++++++++++++++++----------------------- 1 file changed, 144 insertions(+), 133 deletions(-) diff --git a/sw/wulpus/gui.py b/sw/wulpus/gui.py index 43e33df..4b5409a 100644 --- a/sw/wulpus/gui.py +++ b/sw/wulpus/gui.py @@ -28,17 +28,18 @@ # plt.ioff() -V_TISSUE = 1540 # m/s +V_TISSUE = 1540 # m/s -LOWER_BOUNDS_MM = 7 # data below this depth will be discarded +LOWER_BOUNDS_MM = 7 # data below this depth will be discarded LINE_N_SAMPLES = 400 FILE_NAME_BASE = 'data_' + class WulpusGuiSingleCh(widgets.VBox): - - def __init__(self, com_link:WulpusDongle, uss_conf, max_vis_fps = 20): + + def __init__(self, com_link: WulpusDongle, uss_conf, max_vis_fps=20): super().__init__() # Communication link @@ -48,8 +49,10 @@ def __init__(self, com_link:WulpusDongle, uss_conf, max_vis_fps = 20): self.uss_conf = uss_conf # Allocate memory to store the data and other parameters - self.data_arr = np.zeros((self.com_link.acq_length, uss_conf.num_acqs), dtype='Wulpus") + self.title = widgets.HTML( + value="

Wulpus

") # Serial port related self.ser_scan_button = widgets.Button(description="Scan ports", disabled=False, - style= {'description_width': 'initial'}) - + style={'description_width': 'initial'}) + self.ser_open_button = widgets.Button(description="Open port", disabled=True) - + self.port_opened = False self.acquisition_running = False - + devices = self.com_link.get_available() if len(devices) == 0: @@ -93,13 +97,13 @@ def build_widgets(self): value='No ports found', description='Serial port:', disabled=True, - style= {'description_width': 'initial'}) + style={'description_width': 'initial'}) else: self.ports_dd = widgets.Dropdown(options=[device.description for device in devices], value=devices[0].description, description='Serial port:', disabled=True, - style= {'description_width': 'initial'}) + style={'description_width': 'initial'}) # pre-populate by scanning once self.click_scan_ports(self.ser_scan_button) @@ -107,27 +111,27 @@ def build_widgets(self): self.raw_data_check = widgets.Checkbox(value=True, description='Show Raw Data', disabled=True) - + self.filt_data_check = widgets.Checkbox(value=False, description='Show Filtered Data', disabled=True) - + self.env_data_check = widgets.Checkbox(value=False, description='Show Envelope', disabled=True) - + self.bmode_check = widgets.Checkbox(value=False, description='Show B-Mode', disabled=True) - - opt = [str(x) for x in range(self.uss_conf.num_txrx_configs)] + + opt = [str(x) for x in range(self.uss_conf.num_txrx_configs)] self.tx_rx_sel_dd = widgets.Dropdown(options=opt, value=opt[0], description='Active RX config:', disabled=True, - style= {'description_width': 'initial'}) - - self.band_pass_frs = widgets.FloatRangeSlider(value=[self.f_low_cutoff/10**6,\ + style={'description_width': 'initial'}) + + self.band_pass_frs = widgets.FloatRangeSlider(value=[self.f_low_cutoff/10**6, self.f_high_cutoff/10**6], min=self.f_low_cutoff/10**6, max=self.f_high_cutoff/10**6, @@ -138,18 +142,18 @@ def build_widgets(self): orientation='horizontal', readout=True, readout_format='.1f', - style= {'description_width': 'initial'}) - + style={'description_width': 'initial'}) + # Progress bar, Start and Stop button, save data checkbox and label self.frame_progr_bar = widgets.IntProgress(value=0, min=0, max=self.uss_conf.num_acqs, step=1, description='Progress:', - bar_style='success', # 'success', 'info', 'warning', 'danger' or '' + bar_style='success', # 'success', 'info', 'warning', 'danger' or '' orientation='horizontal', - style= {'description_width': 'initial'}) - + style={'description_width': 'initial'}) + self.start_stop_button = widgets.Button(description="Start measurement", disabled=True) @@ -161,11 +165,11 @@ def build_widgets(self): except Exception: # older ipywidgets may not support button_style assignment pass - + self.save_data_check = widgets.Checkbox(value=True, description='Save Data as .npz', disabled=True) - + self.save_data_label = widgets.Label(value='') # Setup Visualization output container @@ -176,31 +180,39 @@ def compose_layout(self): padding_layout = widgets.Layout(padding='6px') gap_layout = widgets.Layout(gap='6px') box_layout = widgets.Layout(display='flex', - flex_flow='column', - align_items='center', - width='100%') - flex_start_layout = widgets.Layout(justify_content='flex-start', width='100%') + flex_flow='column', + align_items='center', + width='100%') + flex_start_layout = widgets.Layout( + justify_content='flex-start', width='100%') controls_1 = widgets.VBox([ - widgets.HBox([self.ser_open_button, self.ser_scan_button], layout=gap_layout) , + widgets.HBox( + [self.ser_open_button, self.ser_scan_button], layout=gap_layout), self.ports_dd, self.tx_rx_sel_dd, self.band_pass_frs ], layout=padding_layout) - + controls_2 = widgets.VBox([self.raw_data_check, self.filt_data_check, self.env_data_check, self.bmode_check], - layout=padding_layout) + layout=padding_layout) - controls = widgets.HBox([controls_1, controls_2], layout=flex_start_layout) - - out_box = widgets.Box([self.output], layout=widgets.Layout(width='100%')) - - progr_ctl_box_1 = widgets.VBox([self.start_stop_button, self.frame_progr_bar], layout=widgets.Layout(padding='6px')) - progr_ctl_box_2 = widgets.VBox([self.save_data_check, self.save_data_label], layout=widgets.Layout(padding='6px')) - progr_ctl_box = widgets.HBox([progr_ctl_box_1, progr_ctl_box_2], layout=flex_start_layout) + controls = widgets.HBox( + [controls_1, controls_2], layout=flex_start_layout) + + out_box = widgets.Box( + [self.output], layout=widgets.Layout(width='100%')) + + progr_ctl_box_1 = widgets.VBox( + [self.start_stop_button, self.frame_progr_bar], layout=widgets.Layout(padding='6px')) + progr_ctl_box_2 = widgets.VBox( + [self.save_data_check, self.save_data_label], layout=widgets.Layout(padding='6px')) + progr_ctl_box = widgets.HBox( + [progr_ctl_box_1, progr_ctl_box_2], layout=flex_start_layout) # Compose main box with title and consistent box layout - main_box = widgets.VBox([self.title, controls, out_box, progr_ctl_box], layout=box_layout) + main_box = widgets.VBox( + [self.title, controls, out_box, progr_ctl_box], layout=box_layout) # attach to widget children self.children = [main_box] @@ -210,57 +222,58 @@ def connect_callbacks(self): # To serial port related buttons self.ser_scan_button.on_click(self.click_scan_ports) self.ser_open_button.on_click(self.click_open_port) - + # To checkboxes self.raw_data_check.observe(self.turn_on_off_raw_data_plot, 'value') self.filt_data_check.observe(self.turn_on_off_filt_data_plot, 'value') self.env_data_check.observe(self.turn_on_off_env_plot, 'value') self.bmode_check.observe(self.toggle_bmode, 'value') - + # To TX RX select dropdown self.tx_rx_sel_dd.observe(self.select_rx_conf_to_plot, 'value') - + # To progress slider self.band_pass_frs.observe(self.update_band_pass_range, 'value') - + # To start stop acqusition button self.start_stop_button.on_click(self.click_start_stop_acq) - + def one_time_fig_config(self): - + with self.output: - self.fig, self.ax = plt.subplots(constrained_layout=True, figsize=(8, 4), ncols=1, nrows=1) - + self.fig, self.ax = plt.subplots( + constrained_layout=True, figsize=(8, 4), ncols=1, nrows=1) + if self.bmode_check.value: self.setup_bmode_plot() else: self.setup_amode_plot() self.fig.canvas.toolbar_position = 'bottom' - + def setup_amode_plot(self): self.ax.clear() - self.raw_data_line, = self.ax.plot(np.zeros(LINE_N_SAMPLES), + self.raw_data_line, = self.ax.plot(np.zeros(LINE_N_SAMPLES), color='blue', marker='o', markersize=1, label='Raw data') - - self.filt_data_line, = self.ax.plot(np.zeros(LINE_N_SAMPLES), + + self.filt_data_line, = self.ax.plot(np.zeros(LINE_N_SAMPLES), color='green', marker='o', markersize=1, label='Filtered data') - - self.envelope_line, = self.ax.plot(np.zeros(LINE_N_SAMPLES), + + self.envelope_line, = self.ax.plot(np.zeros(LINE_N_SAMPLES), color='red', marker='o', markersize=1, label='Envelope') - + self.ax.legend(loc='upper right') - + self.ax.set_xlabel('Samples') self.ax.set_ylabel('ADC digital code') self.ax.set_title('A-mode data') @@ -282,14 +295,14 @@ def setup_bmode_plot(self): self.ax.set_title('B-mode data') # self.bmode_image.set_clim(0, 2) self.bmode_image.set_clim(0, 200) - + meas_time = LINE_N_SAMPLES / self.uss_conf.sampling_freq meas_depth = meas_time * V_TISSUE * 1000 / 2 # self.bmode_image.set_extent((LOWER_BOUNDS_MM, meas_depth, 0.5, 7.5)) self.bmode_image.set_extent((0, meas_depth, 0.5, 7.5)) # Callbacks - + def click_scan_ports(self, b): # Update drop-down for ports and make it enabled self.found_devices = self.com_link.get_available() @@ -300,68 +313,67 @@ def click_scan_ports(self, b): self.ports_dd.disabled = True self.ser_open_button.disabled = True else: - self.ports_dd.options = [device.description for device in self.found_devices] + self.ports_dd.options = [ + device.description for device in self.found_devices] self.ports_dd.value = self.found_devices[0].description self.ports_dd.disabled = False self.ser_open_button.disabled = False - + def click_open_port(self, b): - + if not self.port_opened and len(self.ports_dd.options) > 0: device = self.found_devices[self.ports_dd.index] - + if not self.com_link.open(device): b.description = "Open port" self.port_opened = False self.start_stop_button.disabled = True return - + b.description = "Close port" self.port_opened = True self.start_stop_button.disabled = False - - else : + + else: self.com_link.close() b.description = "Open port" self.port_opened = False self.start_stop_button.disabled = True - - + def turn_on_off_raw_data_plot(self, change): - + self.raw_data_line.set_visible(change.new) - + def turn_on_off_filt_data_plot(self, change): - + self.filt_data_line.set_visible(change.new) - + def turn_on_off_env_plot(self, change): - + self.envelope_line.set_visible(change.new) def toggle_bmode(self, change): - + if change.new: self.setup_bmode_plot() self.tx_rx_sel_dd.disabled = True else: self.setup_amode_plot() self.tx_rx_sel_dd.disabled = False - + self.fig.canvas.draw() self.fig.canvas.flush_events() - + def select_rx_conf_to_plot(self, change): - + self.rx_tx_conf_to_display = int(change.new) - + def update_band_pass_range(self, change): - + self.design_filter(self.uss_conf.sampling_freq, change.new[0]*10**6, change.new[1]*10**6) - - + def click_start_stop_acq(self, b): if not self.acquisition_running: @@ -373,14 +385,13 @@ def click_start_stop_acq(self, b): self.tx_rx_sel_dd.disabled = False self.band_pass_frs.disabled = False self.save_data_check.disabled = False - + # Disable serial port related widgets self.ser_open_button.disabled = True - + # Clean Save data label self.save_data_label.value = '' - - + # Change state of the button b.description = "Stop measurement" @@ -391,11 +402,11 @@ def click_start_stop_acq(self, b): self.current_data = None self.acquisition_thread = Thread(target=self.run_acquisition_loop) self.acquisition_thread.start() - + else: # Stop acquisition, thread will stop by itself self.acquisition_running = False - + # Change state of the button b.description = "Start measurement" @@ -407,12 +418,12 @@ def click_start_stop_acq(self, b): self.tx_rx_sel_dd.disabled = True self.band_pass_frs.disabled = True self.save_data_check.disabled = True - + # Enable serial port related widgets again self.ser_open_button.disabled = False - + def run_acquisition_loop(self): - + # Clean data buffer acq_length = self.com_link.acq_length number_of_acq = self.uss_conf.num_acqs @@ -420,14 +431,14 @@ def run_acquisition_loop(self): self.acq_num_arr = np.zeros(number_of_acq, dtype=' 0: time.sleep(sleep_time) - # Design bandpass filter - def design_filter(self, - f_sampling, - f_low_cutoff, - f_high_cutoff, - trans_width=0.2*10**6, - n_taps = 31): - - temp = [0, f_low_cutoff - trans_width, \ - f_low_cutoff, f_high_cutoff, \ - f_high_cutoff + trans_width, \ + def design_filter(self, + f_sampling, + f_low_cutoff, + f_high_cutoff, + trans_width=0.2*10**6, + n_taps=31): + + temp = [0, f_low_cutoff - trans_width, + f_low_cutoff, f_high_cutoff, + f_high_cutoff + trans_width, f_sampling/2] - - self.filt_b = ss.remez(n_taps, + + self.filt_b = ss.remez(n_taps, temp, - [0, 1, 0], - Hz=f_sampling, + [0, 1, 0], + Hz=f_sampling, maxiter=2500) self.filt_a = 1 - - + def filter_data(self, data_in): return ss.filtfilt(self.filt_b, self.filt_a, data_in) - + def get_envelope(self, data_in): return np.abs(hilbert(data_in)) - + def save_data_to_file(self): - + # Check filename for i in range(1000): filename = FILE_NAME_BASE + str(i) + '.npz' if not os.path.isfile(filename): break - + # Save numpy data array to file - np.savez(filename[:-4], + np.savez(filename[:-4], data_arr=self.data_arr, acq_num_arr=self.acq_num_arr, tx_rx_id_arr=self.tx_rx_id_arr) - - self.save_data_label.value = 'Data saved in ' + filename \ No newline at end of file + + self.save_data_label.value = 'Data saved in ' + filename From f21b9717257ab4cfd4ebf10bfc855859ec97f43c Mon Sep 17 00:00:00 2001 From: Louis Date: Fri, 15 Aug 2025 11:24:21 -0700 Subject: [PATCH 03/51] Add datettime of recording-start into log = switch to compressed log --- sw/wulpus/gui.py | 64 +++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/sw/wulpus/gui.py b/sw/wulpus/gui.py index 4b5409a..796146e 100644 --- a/sw/wulpus/gui.py +++ b/sw/wulpus/gui.py @@ -62,6 +62,9 @@ def __init__(self, com_link: WulpusDongle, uss_conf, max_vis_fps=20): # Extra variables to control visualization self.rx_tx_conf_to_display = 0 + # time when recording of a dataset starts (in seconds since the epoch, as float) + self.record_start = 0.0 + # For Signal Processing self.f_low_cutoff = self.uss_conf.sampling_freq / 2 * 0.1 self.f_high_cutoff = self.uss_conf.sampling_freq / 2 * 0.9 @@ -374,17 +377,20 @@ def update_band_pass_range(self, change): change.new[0]*10**6, change.new[1]*10**6) + def disable_all_widgets(self, state: bool): + + self.raw_data_check.disabled = state + self.filt_data_check.disabled = state + self.env_data_check.disabled = state + self.bmode_check.disabled = state + self.tx_rx_sel_dd.disabled = state + self.band_pass_frs.disabled = state + self.save_data_check.disabled = state + def click_start_stop_acq(self, b): if not self.acquisition_running: - # Enable the widgets active during acquisition - self.raw_data_check.disabled = False - self.filt_data_check.disabled = False - self.env_data_check.disabled = False - self.bmode_check.disabled = False - self.tx_rx_sel_dd.disabled = False - self.band_pass_frs.disabled = False - self.save_data_check.disabled = False + self.disable_all_widgets(False) # Disable serial port related widgets self.ser_open_button.disabled = True @@ -397,6 +403,7 @@ def click_start_stop_acq(self, b): # Declare that acquisition is running self.acquisition_running = True + self.record_start = time.time() # Run data acquisition loop self.current_data = None @@ -410,14 +417,7 @@ def click_start_stop_acq(self, b): # Change state of the button b.description = "Start measurement" - # Disable the widgets when not acquiring - self.raw_data_check.disabled = True - self.filt_data_check.disabled = True - self.env_data_check.disabled = True - self.bmode_check.disabled = True - self.tx_rx_sel_dd.disabled = True - self.band_pass_frs.disabled = True - self.save_data_check.disabled = True + self.disable_all_widgets(True) # Enable serial port related widgets again self.ser_open_button.disabled = False @@ -460,7 +460,7 @@ def run_acquisition_loop(self): # Receive the data data = self.com_link.receive_data() if data is not None: - + # data: rf_arr, acq_nr, tx_rx_id self.current_data = data if data[2] == self.rx_tx_conf_to_display and not self.bmode_check.value: @@ -489,6 +489,11 @@ def run_acquisition_loop(self): self.com_link.send_config(self.uss_conf.get_restart_package()) + # Trim data to actual measured size + self.data_arr = self.data_arr[:, :self.data_cnt] + self.acq_num_arr = self.acq_num_arr[:self.data_cnt] + self.tx_rx_id_arr = self.tx_rx_id_arr[:self.data_cnt] + # Save data to file if needed if (self.save_data_check.value): self.save_data_to_file() @@ -580,17 +585,20 @@ def get_envelope(self, data_in): return np.abs(hilbert(data_in)) def save_data_to_file(self): + start_time = time.localtime(self.record_start) + timestring = time.strftime("%Y-%m-%d_%H-%M-%S", start_time) - # Check filename - for i in range(1000): - filename = FILE_NAME_BASE + str(i) + '.npz' - if not os.path.isfile(filename): - break + filename = FILE_NAME_BASE + timestring + # Check if filename exists (.npz gets added by .savez command) + while os.path.isfile(filename + '.npz'): + filename = filename + "_conflict" # Save numpy data array to file - np.savez(filename[:-4], - data_arr=self.data_arr, - acq_num_arr=self.acq_num_arr, - tx_rx_id_arr=self.tx_rx_id_arr) - - self.save_data_label.value = 'Data saved in ' + filename + np.savez_compressed(filename, + data_arr=self.data_arr, + acq_num_arr=self.acq_num_arr, + tx_rx_id_arr=self.tx_rx_id_arr, + record_start=np.array([self.record_start]) + ) + + self.save_data_label.value = 'Data saved in ' + filename + '.npz' From 549af306c96715b2fd5c1f777457dcfae9a67a9b Mon Sep 17 00:00:00 2001 From: Louis Date: Fri, 15 Aug 2025 11:24:52 -0700 Subject: [PATCH 04/51] Add mocked dongle to ease GUI dev --- sw/wulpus/dongle_mock.py | 78 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 sw/wulpus/dongle_mock.py diff --git a/sw/wulpus/dongle_mock.py b/sw/wulpus/dongle_mock.py new file mode 100644 index 0000000..d67e1e3 --- /dev/null +++ b/sw/wulpus/dongle_mock.py @@ -0,0 +1,78 @@ +""" + Copyright (C) 2023 ETH Zurich. All rights reserved. + Author: Sergei Vostrikov, ETH Zurich + Cedric Hirschi, ETH Zurich + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache-2.0 +""" + +import serial +from serial.tools.list_ports import comports +from serial.tools.list_ports_common import ListPortInfo +import numpy as np +from wulpus.dongle import WulpusDongle + +ACQ_LENGTH_SAMPLES = 400 + + +class WulpusDongleMock(WulpusDongle): + """ + Class representing the Wulpus dongle (mock implementation). + """ + + def __init__(self, port: str = '', timeout_write: int = 3, baudrate: int = 4000000): + self.port = port + self.timeout_write = timeout_write + self.baudrate = baudrate + + self.acq_length = ACQ_LENGTH_SAMPLES + self.acq_num = 0 + + def get_available(self): + """ + Get a list of available devices. + """ + ports = comports() + return sorted(ports) + + def open(self, device: ListPortInfo = None): + """ + Open the device connection. + """ + self.acq_num = 0 + return True + + def close(self): + """ + Close the device connection. + """ + return True + + def send_config(self, conf_bytes_pack: bytes): + """ + Send a configuration package to the device. + """ + print("Configuration sent:", conf_bytes_pack) + self.acq_num = 0 + return True + + def receive_data(self): + """ + Mock: Return random data with the same structure as the original. + """ + rf_arr = np.random.randint( + 1, 1001, size=ACQ_LENGTH_SAMPLES, dtype=" Date: Fri, 15 Aug 2025 14:22:39 -0700 Subject: [PATCH 05/51] Refactor US acquisition setup and add functionality to live-patch configuration --- fw/msp430/wulpus_msp430_firmware/main.c | 54 +++++++++++++------ .../wulpus/wulpus_sys.c | 35 ++++-------- .../wulpus/wulpus_sys.h | 4 +- 3 files changed, 52 insertions(+), 41 deletions(-) diff --git a/fw/msp430/wulpus_msp430_firmware/main.c b/fw/msp430/wulpus_msp430_firmware/main.c index b558a05..86de898 100644 --- a/fw/msp430/wulpus_msp430_firmware/main.c +++ b/fw/msp430/wulpus_msp430_firmware/main.c @@ -45,6 +45,7 @@ static void getConfigPack(void); static void configAfterPowerUp(void); static void receiveUssConfPackage(void); static void usAcquisitionLoop(void); +static void prepareUSSAcquisition(); // Callbacks implementation static void hsPllUnlockCallback(void); @@ -52,6 +53,7 @@ static void saphSeqAcqDoneCallback(void); static void slowTimerCc2Callback(void); static void fastTimerCc0Callback(void); + int main(void) { @@ -72,24 +74,16 @@ int main(void) // Receive Uss configuration package from nRF receiveUssConfPackage(); - // Configure Uss according to the new package - confUsSubsystem(); - - // Configure the events of slow and fast timers - confTimerSlowSwEvents(); - confTimerFastSwEvents(); - - // Power up HV PCB - enableHvPcbSupply(); - // Enable Power for OPA836 - enableOpAmpSupply(); + prepareUSSAcquisition(); // Enter acquisition loop usAcquisitionLoop(); - - } + + // Power down HV PCB after finished recording + disableHvPcbSupply(); + } + // Not reachable - return 0; } @@ -147,7 +141,6 @@ void configAfterPowerUp(void) } static void receiveUssConfPackage(void) - { while(1) { @@ -171,6 +164,20 @@ static void receiveUssConfPackage(void) } } +static void prepareUSSAcquisition(){ + // Configure Uss according to the new package + confUsSubsystem(); + + // Configure the events of slow and fast timers + confTimerSlowSwEvents(); + confTimerFastSwEvents(); + + // Power up HV PCB + enableHvPcbSupply(); + // Enable Power for OPA836 + enableOpAmpSupply(); +} + static void usAcquisitionLoop(void) { @@ -220,6 +227,23 @@ static void usAcquisitionLoop(void) return; } + // Check the SPI RX buffer for restart command + if (isNewConfigCondition(usSpiGetRxPtr())) + { + pauseTimerSlowSwEvents(); + if (extractUsConfig(usSpiGetRxPtr(), &msp_config)) + { + // Update Ultrasound config + setNewUsConfig(&msp_config); + prepareUSSAcquisition(); + continue; + } + else{ + // config invalid + return; + } + } + // Wait for timer to elapse waitTimerSlowElapse(); diff --git a/fw/msp430/wulpus_msp430_firmware/wulpus/wulpus_sys.c b/fw/msp430/wulpus_msp430_firmware/wulpus/wulpus_sys.c index ed11759..a414592 100644 --- a/fw/msp430/wulpus_msp430_firmware/wulpus/wulpus_sys.c +++ b/fw/msp430/wulpus_msp430_firmware/wulpus/wulpus_sys.c @@ -57,8 +57,8 @@ void getDefaultUsConfig(msp_config_t * msp_config) // TX/RX configurations msp_config->txRxConfLen = 0; -// msp_config->txConfigs[TX_RX_CONF_LEN_MAX]; -// msp_config->rxConfigs[TX_RX_CONF_LEN_MAX]; + // msp_config->txConfigs[TX_RX_CONF_LEN_MAX]; + // msp_config->rxConfigs[TX_RX_CONF_LEN_MAX]; // Pulser settins msp_config->driveStrength = PPG_NORMAL_DRIVE; @@ -70,8 +70,6 @@ void getDefaultUsConfig(msp_config_t * msp_config) msp_config->numStopPulses = 0; msp_config->pulserPolarity = PPG_POLARITY_START_WITH_HIGH; msp_config->pulserPauseState = PPG_PAUSE_STATE_LOW; - - return; } // Extract Uss config from spi RX buffer @@ -79,8 +77,9 @@ void getDefaultUsConfig(msp_config_t * msp_config) bool extractUsConfig(uint8_t * spi_rx, msp_config_t * msp_config) { // Check start byte - if (spi_rx[0] != START_BYTE_CONF_PACK) + if(!isNewConfigCondition(spi_rx)){ return 0; + } // Note: The MSP430 cannot access 2-byte words at odd addresses, so the CPU just ignores the lowest bit of word addresses. //Therefore, we do here some magic @@ -120,16 +119,16 @@ bool extractUsConfig(uint8_t * spi_rx, msp_config_t * msp_config) return 1; } -// Check the first byte and check if restart should be done. +// Check the first byte if restart should be performed bool isRestartCondition(uint8_t * spi_rx) { // Check for restart byte - if (spi_rx[0] != START_BYTE_RESTART) - { - return 0; - } + return (spi_rx[0] == START_BYTE_RESTART); +} - return 1; +// Check the first byte if a new config is requested +bool isNewConfigCondition(uint8_t * spi_rx){ + return (spi_rx[0] == START_BYTE_CONF_PACK); } // Initiate MSP430-controlled power switches @@ -149,8 +148,6 @@ void initAllPowerSwitches(void) // Set Pin 4 to output "SW_EN" (Switch DC/DC: TPS61222) // Set Pin 5 to output "HV_EN" (HV DC/DC: LT1945) GPIO_setAsOutputPin(GPIO_PORT_P6, GPIO_PIN0 + GPIO_PIN4 + GPIO_PIN5); - - return; } // Init other GPIOs @@ -162,8 +159,6 @@ void initOtherGpios(void) // Configure LED P1DIR |= GPIO_PIN_LED_MSP430; P1OUT &= ~GPIO_PIN_LED_MSP430; - - return; } bool isBleReady(void) @@ -193,8 +188,6 @@ void enableOpAmp(void) // Enable RX OPA836 // Set Pin 0 "RxEn" to high GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN0); - - return; } // Disable Rx Operational Amplifier @@ -203,8 +196,6 @@ void disableOpAmp(void) // Disable RX OPA836 // Set Pin 0 "RxEn" to low GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0); - - return; } // Enable HV PCB power supply @@ -215,8 +206,6 @@ void enableHvPcbSupply(void) // just for the US measurements // Set Pin 2 "EN HV" to high (power up HV PCB) GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN2); - - return; } // Disable HV PCB power supply @@ -234,8 +223,6 @@ void enableHvPcbDcDc(void) // Set Pin 4 "SW_EN" to high (enables the DC/DC TPS61222) // Set Pin 5 "HV1_EN" to high (enables the HV DC/DC LT1945) GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN4+GPIO_PIN5); - - return; } // Disable DC-DC converters on HV PCB @@ -245,8 +232,6 @@ void disableHvPcbDcDc(void) // Set Pin 4 "SW_EN" to low (disables the DC/DC TPS61222) // Set Pin 5 "HV1_EN" to low (disables the HV DC/DC LT1945) GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN4 + GPIO_PIN5); - - return; } // Disable only HV DC-DC converter on HV PCB diff --git a/fw/msp430/wulpus_msp430_firmware/wulpus/wulpus_sys.h b/fw/msp430/wulpus_msp430_firmware/wulpus/wulpus_sys.h index 7c53a8c..a906831 100644 --- a/fw/msp430/wulpus_msp430_firmware/wulpus/wulpus_sys.h +++ b/fw/msp430/wulpus_msp430_firmware/wulpus/wulpus_sys.h @@ -59,8 +59,10 @@ bool extractUsConfig(uint8_t * spi_rx, msp_config_t * msp_config); //// Extra functions //// -// Check the first byte and check if restart should be performed +// Check the first byte if restart should be performed bool isRestartCondition(uint8_t * spi_rx); +// Check the first byte if a new config is requested +bool isNewConfigCondition(uint8_t * spi_rx); // Initiate MSP430-controlled power switches void initAllPowerSwitches(void); From d255b36c4badffca477ecc88d05cc83b0ec6cafd Mon Sep 17 00:00:00 2001 From: Louis Date: Wed, 20 Aug 2025 14:39:18 -0700 Subject: [PATCH 06/51] add first steps to move towards a http-api --- .gitignore | 1 + sw/requirements.yml | Bin 428 -> 508 bytes wulpus/__init__.py | 0 wulpus/config_models.py | 108 ++++++++++++++++++++ wulpus/dongle.py | 164 +++++++++++++++++++++++++++++++ wulpus/dongle_mock.py | 81 +++++++++++++++ wulpus/main.py | 191 ++++++++++++++++++++++++++++++++++++ wulpus/requirements.txt | 8 ++ wulpus/wulpus_api.py | 76 ++++++++++++++ wulpus/wulpus_api_helper.py | 81 +++++++++++++++ 10 files changed, 710 insertions(+) create mode 100644 wulpus/__init__.py create mode 100644 wulpus/config_models.py create mode 100644 wulpus/dongle.py create mode 100644 wulpus/dongle_mock.py create mode 100644 wulpus/main.py create mode 100644 wulpus/requirements.txt create mode 100644 wulpus/wulpus_api.py create mode 100644 wulpus/wulpus_api_helper.py diff --git a/.gitignore b/.gitignore index ee376b4..2fa3ad2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ __pycache__/ .ipynb_checkpoints/ .vscode +*.clangd diff --git a/sw/requirements.yml b/sw/requirements.yml index 64b6f1096006f59f930e54582929785edd8ffd77..cd56e791c759f5f4351068124f26f6554f89fd7c 100644 GIT binary patch delta 103 zcmZ3({D*nN491CfIARJIDj8B35*hLsN*FR3k{N6nj2QG741tiBfr~)_2z7zDoFSDV oiJ_PwAE+W5$Swi0ZGmb`focuFDhn8jfZ}ODGb$LYfI2|B0cu list[dict[str, str]]: + """ + Get a list of available devices. + + Returns: + list[dict[str, str]]: A list of {device_key: description}. + """ + ports = comports() + self._ports = sorted(ports) + return list(map(lambda p: {p.device: p.description}, self._ports)) + + def open(self, device: ListPortInfo = None, device_str: str = None): + """ + Open the device connection. + """ + if self.__ser__.is_open: + return True + + if device_str is not None: + self.__ser__.port = device_str + + if device is not None: + self.__ser__.port = device.device + + if self.__ser__.port == '': + print("Error: no serial port specified.") + return False + + try: + self.__ser__.open() + except: + print("Error while trying to open serial port ", + str(self.__ser__.port)) + return False + return True + + def close(self): + """ + Close the device connection. + """ + if not self.__ser__.is_open: + return True + + try: + self.__ser__.close() + except: + print("Error while trying to close serial port ", + str(self.__ser__.port)) + return False + return True + + def send_config(self, conf_bytes_pack: bytes): + """ + Send a configuration package to the device. + """ + if not self.__ser__.is_open: + print("Error: serial port is not open.") + return False + + self.__ser__.flushInput() # flush input buffer, discarding all its contents + self.__ser__.flushOutput() # flush output buffer, aborting current output + # and discard all that is in buffer + + self.__ser__.write(conf_bytes_pack) + return True + + def __get_rf_data_and_info__(self, bytes_arr: bytes): + rf_arr = np.frombuffer(bytes_arr[7:], dtype=' 0: + device_name = self._last_connection + else: + raise ValueError("No device name specified.") + + self._last_connection = device_name + self._status = Status.CONNECTING + if self._dongle.open(device_str=device_name): + self._status = Status.READY + else: + self._status = Status.NOT_CONNECTED + + def get_status(self): + return {"status": self._status, "bluetooth": self._dongle.get_status(), "config": self._config} + + def set_config(self, config: WulpusConfig) -> bytes: + self._config = config + + def start(self): + """ + Start executing the config. Config needs to be set before starting. + """ + if self._status == Status.RUNNING: + return + if not self._config: + raise ValueError("No configuration set.") + bytes_config = gen_conf_package(self._config) + + # Send a restart command (in case the system is already running) + # TODO: Remove after live config-update is tested + self._dongle.send_config(gen_restart_package()) + time.sleep(2.5) + + if self._dongle.send_config(bytes_config): + self._status = Status.RUNNING + else: + self._status = Status.NOT_CONNECTED + + async def listen_measurement_data(self): + """ + Start listening for measurement data from the dongle. + """ + if self._status != Status.RUNNING: + return + await asyncio.create_task(self.__measure()) + + def __measure(self): + number_of_acq = self._config.us_config.num_acqs + num_samples = self._config.us_config.num_samples + data_arr = np.zeros((num_samples, number_of_acq), dtype=' len(rx_only_ch): + temp_switch_config = np.bitwise_or.reduce(np.left_shift( + 1, RX_MAP[rx_tx_intersect_ch])) if rx_tx_intersect_ch else 0 + tx_cfgs[i] = np.bitwise_or( + tx_cfgs[i], temp_switch_config) + elif len(rx_only_ch) > 0: + temp_switch_config = np.bitwise_or.reduce( + np.left_shift(1, RX_MAP[rx_only_ch])) + tx_cfgs[i] = np.bitwise_or( + tx_cfgs[i], temp_switch_config) + i += 1 + return tx_cfgs[:i], rx_cfgs[:i] From 92b64662c2db92b0837625d7a7f988712e9d59f6 Mon Sep 17 00:00:00 2001 From: Louis Date: Thu, 21 Aug 2025 10:26:21 -0700 Subject: [PATCH 07/51] refactor --- sw/requirements.yml | Bin 508 -> 548 bytes wulpus/config_models.py | 2 +- wulpus/dongle_mock.py | 3 + wulpus/main.py | 160 ++++-------------------------------- wulpus/requirements.txt | 3 +- wulpus/websocket_manager.py | 43 ++++++++++ wulpus/wulpus.py | 114 +++++++++++++++++++++++++ wulpus/wulpus_api_helper.py | 4 +- 8 files changed, 178 insertions(+), 151 deletions(-) create mode 100644 wulpus/websocket_manager.py create mode 100644 wulpus/wulpus.py diff --git a/sw/requirements.yml b/sw/requirements.yml index cd56e791c759f5f4351068124f26f6554f89fd7c..986ff25d6a5ee9787dbc0f3f3ed9f9bbe01577fa 100644 GIT binary patch delta 68 zcmeyvyo6=L3q~6S1_cIPAkJbaX2@sA1G4iNN*Qt)3K%LGY#EFg^cV~ocp12W{33=_ QhBSsuh6)BNpn8xP0QI5_4gdfE delta 11 ScmZ3&@`riD3&zO;Od 0: - device_name = self._last_connection - else: - raise ValueError("No device name specified.") - - self._last_connection = device_name - self._status = Status.CONNECTING - if self._dongle.open(device_str=device_name): - self._status = Status.READY - else: - self._status = Status.NOT_CONNECTED - - def get_status(self): - return {"status": self._status, "bluetooth": self._dongle.get_status(), "config": self._config} - - def set_config(self, config: WulpusConfig) -> bytes: - self._config = config - - def start(self): - """ - Start executing the config. Config needs to be set before starting. - """ - if self._status == Status.RUNNING: - return - if not self._config: - raise ValueError("No configuration set.") - bytes_config = gen_conf_package(self._config) - - # Send a restart command (in case the system is already running) - # TODO: Remove after live config-update is tested - self._dongle.send_config(gen_restart_package()) - time.sleep(2.5) - - if self._dongle.send_config(bytes_config): - self._status = Status.RUNNING - else: - self._status = Status.NOT_CONNECTED - - async def listen_measurement_data(self): - """ - Start listening for measurement data from the dongle. - """ - if self._status != Status.RUNNING: - return - await asyncio.create_task(self.__measure()) - - def __measure(self): - number_of_acq = self._config.us_config.num_acqs - num_samples = self._config.us_config.num_samples - data_arr = np.zeros((num_samples, number_of_acq), dtype=' 0: + device_name = self._last_connection + else: + raise ValueError("No device name specified.") + + self._last_connection = device_name + self._status = Status.CONNECTING + if self._dongle.open(device_str=device_name): + self._status = Status.READY + else: + self._status = Status.NOT_CONNECTED + + def get_status(self): + return {"status": self._status, + "bluetooth": self._dongle.get_status(), + "us_config": self._config.us_config if self._config else None, + "tx_rx_config": self._config.tx_rx_config if self._config else None} + + def set_config(self, config: WulpusConfig) -> bytes: + self._config = config + + def start(self): + """ + Start executing the config. Config needs to be set before starting. + """ + if self._status == Status.RUNNING: + return + if not self._config: + raise ValueError("No configuration set.") + bytes_config = gen_conf_package(self._config) + + # Send a restart command (in case the system is already running) + # TODO: Remove after live config-update is tested + self._dongle.send_config(gen_restart_package()) + time.sleep(2.5) + + if self._dongle.send_config(bytes_config): + self._status = Status.RUNNING + else: + self._status = Status.NOT_CONNECTED + + async def listen_measurement_data(self, consumers: WebsocketManager): + """ + Start listening for measurement data from the dongle. + """ + if self._status != Status.RUNNING: + return + asyncio.create_task(self.__measure(consumers)) + + async def __measure(self, consumers: WebsocketManager): + number_of_acq = self._config.us_config.num_acqs + num_samples = self._config.us_config.num_samples + data_arr = np.zeros((num_samples, number_of_acq), dtype=' Date: Thu, 21 Aug 2025 11:52:08 -0700 Subject: [PATCH 08/51] send data during measurement --- wulpus/main.py | 14 ++++++---- wulpus/websocket_manager.py | 34 ++++++++++++++++++----- wulpus/wulpus.py | 54 ++++++++++++++++++++----------------- 3 files changed, 66 insertions(+), 36 deletions(-) diff --git a/wulpus/main.py b/wulpus/main.py index 3800c82..a1f55d7 100644 --- a/wulpus/main.py +++ b/wulpus/main.py @@ -1,4 +1,5 @@ import asyncio +import time import uvicorn from fastapi import FastAPI, WebSocket, WebSocketDisconnect @@ -11,7 +12,7 @@ wulpus = Wulpus() manager = WebsocketManager(wulpus) app = FastAPI() - +global_send_data_task = None @app.get("/") def root(): @@ -25,10 +26,7 @@ async def start(config: WulpusConfig): except ValueError as e: return {"connection-error": str(e)} wulpus.set_config(config) - wulpus.start() - await wulpus.listen_measurement_data(manager) - # async for measurement in wulpus: - # await manager.broadcast_text("measurement") + await wulpus.start() return {"ok": "ok"} @@ -44,8 +42,14 @@ def connect(conf: ComPort): @app.websocket("/ws") async def websocket_endpoint(websocket: WebSocket): + global global_send_data_task await manager.connect(websocket) asyncio.create_task(manager.send_status(websocket)) + if global_send_data_task is None or global_send_data_task.done(): + new_measurement_event = asyncio.Event() + wulpus.set_new_measurement_event(new_measurement_event) + global_send_data_task = asyncio.create_task( + manager.send_data(new_measurement_event)) try: while True: data = await websocket.receive_text() diff --git a/wulpus/websocket_manager.py b/wulpus/websocket_manager.py index a15aa59..454458a 100644 --- a/wulpus/websocket_manager.py +++ b/wulpus/websocket_manager.py @@ -1,11 +1,13 @@ from __future__ import annotations -import json -from fastapi import WebSocket -from fastapi.websockets import WebSocketState -from fastapi.encoders import jsonable_encoder import asyncio +import json from typing import TYPE_CHECKING +import json_numpy +from fastapi import WebSocket, WebSocketDisconnect +from fastapi.encoders import jsonable_encoder +from fastapi.websockets import WebSocketState + if TYPE_CHECKING: from wulpus.wulpus import Wulpus @@ -27,11 +29,17 @@ async def send_single_client(self, message: str, websocket: WebSocket): async def broadcast_text(self, message: str): for connection in self.active_connections: - await connection.send_text(message) + try: + await connection.send_text(message) + except RuntimeError: + self.disconnect(connection) async def broadcast_json(self, message: json): for connection in self.active_connections: - await connection.send_json(message) + try: + await connection.send_json(message) + except (RuntimeError, WebSocketDisconnect): # Client disconnected + self.disconnect(connection) async def send_status(self, websocket: WebSocket): try: @@ -39,5 +47,17 @@ async def send_status(self, websocket: WebSocket): status = self.wulpus.get_status() await websocket.send_json(jsonable_encoder(status)) await asyncio.sleep(3) - except RuntimeError: # Client disconnected + except (RuntimeError, WebSocketDisconnect): # Client disconnected return + + async def send_data(self, new_measurement_event: asyncio.Event): + # Send latest frame to new client + latest_frame = self.wulpus.get_latest_frame() + if not latest_frame is None: + await self.broadcast_json(json_numpy.dumps(latest_frame)) + + while True: + await new_measurement_event.wait() + new_measurement_event.clear() + data, acq_num, tx_rx_id = await self.wulpus.get_new_measurement() + await self.broadcast_json(json_numpy.dumps(data)) diff --git a/wulpus/wulpus.py b/wulpus/wulpus.py index bb5f49a..2d54b1b 100644 --- a/wulpus/wulpus.py +++ b/wulpus/wulpus.py @@ -1,13 +1,9 @@ - -from __future__ import annotations - import asyncio import time from enum import IntEnum from typing import Union import numpy as np -import json_numpy from wulpus.config_models import WulpusConfig from wulpus.dongle_mock import WulpusDongleMock @@ -31,6 +27,11 @@ def __init__(self): self._dongle = WulpusDongleMock() self._last_connection: str = '' self._latest_frame: Union[np.ndarray, None] = None + self._data: Union[np.ndarray, None] = None + self._data_acq_num: Union[np.ndarray, None] = None + self._data_tx_rx_id: Union[np.ndarray, None] = None + # Event to signal new measurement data for WebSocket clients + self._new_measurement = asyncio.Event() def get_connection_options(self): return self._dongle.get_available() @@ -60,7 +61,7 @@ def get_status(self): def set_config(self, config: WulpusConfig) -> bytes: self._config = config - def start(self): + async def start(self): """ Start executing the config. Config needs to be set before starting. """ @@ -73,27 +74,23 @@ def start(self): # Send a restart command (in case the system is already running) # TODO: Remove after live config-update is tested self._dongle.send_config(gen_restart_package()) - time.sleep(2.5) + await asyncio.sleep(2.5) if self._dongle.send_config(bytes_config): self._status = Status.RUNNING + asyncio.create_task(self.__measure()) else: self._status = Status.NOT_CONNECTED - async def listen_measurement_data(self, consumers: WebsocketManager): - """ - Start listening for measurement data from the dongle. - """ - if self._status != Status.RUNNING: - return - asyncio.create_task(self.__measure(consumers)) + def get_latest_frame(self): + return self._latest_frame - async def __measure(self, consumers: WebsocketManager): + async def __measure(self): number_of_acq = self._config.us_config.num_acqs num_samples = self._config.us_config.num_samples - data_arr = np.zeros((num_samples, number_of_acq), dtype=' Date: Thu, 21 Aug 2025 13:30:16 -0700 Subject: [PATCH 09/51] working ws json-message of live measurements --- sw/requirements.yml | Bin 548 -> 508 bytes wulpus/requirements.txt | 3 +-- wulpus/websocket_manager.py | 7 +++---- wulpus/wulpus.py | 19 +++++++++++-------- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/sw/requirements.yml b/sw/requirements.yml index 986ff25d6a5ee9787dbc0f3f3ed9f9bbe01577fa..cd56e791c759f5f4351068124f26f6554f89fd7c 100644 GIT binary patch delta 11 ScmZ3&@`riD3&zO;Od bytes: self._config = config @@ -82,8 +85,8 @@ async def start(self): else: self._status = Status.NOT_CONNECTED - def get_latest_frame(self): - return self._latest_frame + def set_new_measurement_event(self, event: asyncio.Event): + self._new_measurement = event async def __measure(self): number_of_acq = self._config.us_config.num_acqs @@ -103,18 +106,18 @@ async def __measure(self): self._data_acq_num[data_cnt] = data[1] self._data_tx_rx_id[data_cnt] = data[2] self._new_measurement.set() + self._live_data_cnt = data_cnt data_cnt += 1 await asyncio.sleep(0.001) + self._live_data_cnt = 1 # Trim data to actual measured size self._data = self._data[:, :data_cnt] self._data_acq_num = self._data_acq_num[:data_cnt] self._data_tx_rx_id = self._data_tx_rx_id[:data_cnt] - def set_new_measurement_event(self, event: asyncio.Event): - self._new_measurement = event + def get_latest_frame(self): + return self._latest_frame - async def get_new_measurement(self): - # await self._new_measurement.wait() - # self._new_measurement.clear() + async def get_measurement(self): return self._data, self._data_acq_num, self._data_tx_rx_id From 320f2b8a003721409c975e0484fc05c833987957 Mon Sep 17 00:00:00 2001 From: Louis Date: Fri, 22 Aug 2025 11:30:55 -0700 Subject: [PATCH 10/51] Fix min/max values of config-requirements (the conversion into ticks was not thought of) --- wulpus/main.py | 5 ++- wulpus/websocket_manager.py | 5 --- wulpus/wulpus.py | 6 +-- wulpus/wulpus_api.py | 8 ++-- wulpus/wulpus_api_helper.py | 15 ++++++-- ...nfig_models.py => wulpus_config_models.py} | 37 ++++++++++--------- 6 files changed, 41 insertions(+), 35 deletions(-) rename wulpus/{config_models.py => wulpus_config_models.py} (76%) diff --git a/wulpus/main.py b/wulpus/main.py index a1f55d7..003fae5 100644 --- a/wulpus/main.py +++ b/wulpus/main.py @@ -4,7 +4,7 @@ import uvicorn from fastapi import FastAPI, WebSocket, WebSocketDisconnect -from wulpus.config_models import ComPort, WulpusConfig +from wulpus.wulpus_config_models import ComPort, WulpusConfig from wulpus.websocket_manager import WebsocketManager from wulpus.wulpus import Wulpus @@ -50,6 +50,9 @@ async def websocket_endpoint(websocket: WebSocket): wulpus.set_new_measurement_event(new_measurement_event) global_send_data_task = asyncio.create_task( manager.send_data(new_measurement_event)) + latest_frame = wulpus.get_latest_frame() + if latest_frame is not None: + await manager.broadcast_json(latest_frame.tolist()) try: while True: data = await websocket.receive_text() diff --git a/wulpus/websocket_manager.py b/wulpus/websocket_manager.py index d5e1c2f..34aec61 100644 --- a/wulpus/websocket_manager.py +++ b/wulpus/websocket_manager.py @@ -50,11 +50,6 @@ async def send_status(self, websocket: WebSocket): return async def send_data(self, new_measurement_event: asyncio.Event): - # Send latest frame to new client - latest_frame = self.wulpus.get_latest_frame() - if not latest_frame is None: - await self.broadcast_json(latest_frame.tolist()) - while True: await new_measurement_event.wait() new_measurement_event.clear() diff --git a/wulpus/wulpus.py b/wulpus/wulpus.py index 02a9db3..4e472a4 100644 --- a/wulpus/wulpus.py +++ b/wulpus/wulpus.py @@ -5,7 +5,7 @@ import numpy as np -from wulpus.config_models import WulpusConfig +from wulpus.wulpus_config_models import WulpusConfig from wulpus.dongle_mock import WulpusDongleMock from wulpus.websocket_manager import WebsocketManager from wulpus.wulpus_api import gen_conf_package, gen_restart_package @@ -106,15 +106,15 @@ async def __measure(self): self._data_acq_num[data_cnt] = data[1] self._data_tx_rx_id[data_cnt] = data[2] self._new_measurement.set() - self._live_data_cnt = data_cnt data_cnt += 1 + self._live_data_cnt = data_cnt await asyncio.sleep(0.001) - self._live_data_cnt = 1 # Trim data to actual measured size self._data = self._data[:, :data_cnt] self._data_acq_num = self._data_acq_num[:data_cnt] self._data_tx_rx_id = self._data_tx_rx_id[:data_cnt] + self._status = Status.READY def get_latest_frame(self): return self._latest_frame diff --git a/wulpus/wulpus_api.py b/wulpus/wulpus_api.py index 32ce2ed..1f8945f 100644 --- a/wulpus/wulpus_api.py +++ b/wulpus/wulpus_api.py @@ -1,12 +1,10 @@ import numpy as np -from wulpus.config_models import (MAX_CH_ID, PGA_GAIN, PGA_GAIN_REG, PGA_GAIN_VALUE, RX_MAP, - TX_MAP, TX_RX_MAX_NUM_OF_CONFIGS, - USS_CAPT_OVER_SAMPLE_RATES_REG, - USS_CAPTURE_ACQ_RATES, USS_CAPTURE_ACQ_RATES_VALUE, UsConfig, - WulpusConfig) from wulpus.wulpus_api_helper import (as_byte, build_tx_rx_configs, fill_package_to_min_len, us_to_ticks) +from wulpus.wulpus_config_models import (PGA_GAIN_REG, + PGA_GAIN_VALUE, USS_CAPT_OVER_SAMPLE_RATES_REG, + USS_CAPTURE_ACQ_RATES_VALUE, WulpusConfig) START_BYTE_CONF_PACK = 250 START_BYTE_RESTART = 251 diff --git a/wulpus/wulpus_api_helper.py b/wulpus/wulpus_api_helper.py index 5f3c76f..3563099 100644 --- a/wulpus/wulpus_api_helper.py +++ b/wulpus/wulpus_api_helper.py @@ -1,11 +1,20 @@ +from __future__ import annotations import numpy as np +from typing import TYPE_CHECKING -from wulpus.config_models import (RX_MAP, - TX_MAP, TX_RX_MAX_NUM_OF_CONFIGS, - WulpusConfig) +if TYPE_CHECKING: + from wulpus.wulpus_config_models import WulpusConfig PACKAGE_LEN = 68 +TX_RX_MAX_NUM_OF_CONFIGS = 16 +# TX RX is configured by activating the +# switches of HV multiplexer +# The arrays below maps transducer channels (0...7) +# to switches IDs (0..15) which we need to activate +RX_MAP = np.array([0, 2, 4, 6, 8, 10, 12, 14]) +TX_MAP = np.array([1, 3, 5, 7, 9, 11, 13, 15]) + def as_byte(value: int, format: str): return np.array([int(value)]).astype(format).tobytes() diff --git a/wulpus/config_models.py b/wulpus/wulpus_config_models.py similarity index 76% rename from wulpus/config_models.py rename to wulpus/wulpus_config_models.py index 30de74c..f2df4ea 100644 --- a/wulpus/config_models.py +++ b/wulpus/wulpus_config_models.py @@ -1,7 +1,8 @@ import numpy as np from pydantic import BaseModel, Field, field_validator from typing import Union, Literal, Tuple, get_args - +from sw.wulpus.rx_tx_conf import TX_RX_MAX_NUM_OF_CONFIGS +from wulpus.wulpus_api_helper import us_to_ticks # Available RX gain in dB PGA_GAIN = Literal[-6.5, -5.5, -4.6, -4.1, -3.3, -2.3, -1.4, -0.8, @@ -32,9 +33,10 @@ class UsConfig(BaseModel): # Number of acquisitions to perform. num_acqs: int = Field(default=400, ge=0) # DC-DC turn on time in microseconds. - dcdc_turnon: int = Field(default=195300, ge=0, le=65535) + dcdc_turnon: int = Field( + default=195300, ge=0, le=2000000) # Measurement period in microseconds. - meas_period: int = Field(default=321965, ge=655, le=65535) + meas_period: int = Field(default=321965, ge=655, le=2000000) # Transducer frequency in Hertz. trans_freq: int = Field(default=225e4, ge=0, le=5000000) # Pulse frequency in Hertz. @@ -54,31 +56,30 @@ class UsConfig(BaseModel): # RX configurations. (Generated by WulpusRxTxConfigGen) rx_configs: list[int] = Field(default_factory=lambda: [0], max_length=16) # HV-MUX RX start time in microseconds. - start_hvmuxrx: int = Field(default=500, ge=0, le=65535) + start_hvmuxrx: int = Field( + default=500, ge=0, le=int(65535/us_to_ticks['start_hvmuxrx'])) # PPG start time in microseconds. - start_ppg: int = Field(default=500, ge=0, le=65535) + start_ppg: int = Field(default=500, ge=0, le=int(65535 / + us_to_ticks['start_ppg'])) # ADC turn on time in microseconds. - turnon_adc: int = Field(default=5, ge=0, le=65535) + turnon_adc: int = Field(default=5, ge=0, le=int(65535 / + us_to_ticks['turnon_adc'])) # PGA in bias start time in microseconds. - start_pgainbias: int = Field(default=5, ge=0, le=65535) + start_pgainbias: int = Field(default=5, ge=0, le=int(65535 / + us_to_ticks['start_pgainbias'])) # ADC sampling start time in microseconds. - start_adcsampl: int = Field(default=503, ge=0, le=65535) + start_adcsampl: int = Field(default=503, ge=0, le=int(65535 / + us_to_ticks['start_adcsampl'])) # Capture restart time in microseconds. - restart_capt: int = Field(default=3000, ge=0, le=65535) + restart_capt: int = Field(default=3000, ge=0, le=int(65535 / + us_to_ticks['restart_capt'])) # Capture timeout time in microseconds. - capt_timeout: int = Field(default=3000, ge=0, le=65535) + capt_timeout: int = Field(default=3000, ge=0, le=int(65535 / + us_to_ticks['capt_timeout'])) -TX_RX_MAX_NUM_OF_CONFIGS = 16 MAX_CH_ID = 7 -# TX RX is configured by activating the -# switches of HV multiplexer -# The arrays below maps transducer channels (0...7) -# to switches IDs (0..15) which we need to activate -RX_MAP = np.array([0, 2, 4, 6, 8, 10, 12, 14]) -TX_MAP = np.array([1, 3, 5, 7, 9, 11, 13, 15]) - class TxRxConfig(BaseModel): config_id: int = Field(default=0, ge=0, lt=TX_RX_MAX_NUM_OF_CONFIGS) From 1fff0e1a1d0e7ef262741199fa3ad6dd9daf5883 Mon Sep 17 00:00:00 2001 From: Louis Date: Fri, 22 Aug 2025 11:31:35 -0700 Subject: [PATCH 11/51] Add first POC of Web-UI --- wulpus-frontend/.gitignore | 24 + wulpus-frontend/README.md | 69 + wulpus-frontend/eslint.config.js | 27 + wulpus-frontend/index.html | 13 + wulpus-frontend/package-lock.json | 6229 ++++++++++++++++++++++++ wulpus-frontend/package.json | 36 + wulpus-frontend/public/vite.svg | 1 + wulpus-frontend/src/App.tsx | 250 + wulpus-frontend/src/api.ts | 47 + wulpus-frontend/src/assets/react.svg | 1 + wulpus-frontend/src/index.css | 1 + wulpus-frontend/src/main.tsx | 10 + wulpus-frontend/src/vite-env.d.ts | 1 + wulpus-frontend/src/websocket-types.ts | 45 + wulpus-frontend/tsconfig.app.json | 27 + wulpus-frontend/tsconfig.json | 7 + wulpus-frontend/tsconfig.node.json | 25 + wulpus-frontend/vite.config.ts | 22 + 18 files changed, 6835 insertions(+) create mode 100644 wulpus-frontend/.gitignore create mode 100644 wulpus-frontend/README.md create mode 100644 wulpus-frontend/eslint.config.js create mode 100644 wulpus-frontend/index.html create mode 100644 wulpus-frontend/package-lock.json create mode 100644 wulpus-frontend/package.json create mode 100644 wulpus-frontend/public/vite.svg create mode 100644 wulpus-frontend/src/App.tsx create mode 100644 wulpus-frontend/src/api.ts create mode 100644 wulpus-frontend/src/assets/react.svg create mode 100644 wulpus-frontend/src/index.css create mode 100644 wulpus-frontend/src/main.tsx create mode 100644 wulpus-frontend/src/vite-env.d.ts create mode 100644 wulpus-frontend/src/websocket-types.ts create mode 100644 wulpus-frontend/tsconfig.app.json create mode 100644 wulpus-frontend/tsconfig.json create mode 100644 wulpus-frontend/tsconfig.node.json create mode 100644 wulpus-frontend/vite.config.ts diff --git a/wulpus-frontend/.gitignore b/wulpus-frontend/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/wulpus-frontend/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/wulpus-frontend/README.md b/wulpus-frontend/README.md new file mode 100644 index 0000000..7959ce4 --- /dev/null +++ b/wulpus-frontend/README.md @@ -0,0 +1,69 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: + +```js +export default tseslint.config([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + + // Remove tseslint.configs.recommended and replace with this + ...tseslint.configs.recommendedTypeChecked, + // Alternatively, use this for stricter rules + ...tseslint.configs.strictTypeChecked, + // Optionally, add this for stylistic rules + ...tseslint.configs.stylisticTypeChecked, + + // Other configs... + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]) +``` + +You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: + +```js +// eslint.config.js +import reactX from 'eslint-plugin-react-x' +import reactDom from 'eslint-plugin-react-dom' + +export default tseslint.config([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + // Enable lint rules for React + reactX.configs['recommended-typescript'], + // Enable lint rules for React DOM + reactDom.configs.recommended, + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]) +``` diff --git a/wulpus-frontend/eslint.config.js b/wulpus-frontend/eslint.config.js new file mode 100644 index 0000000..a67a3b5 --- /dev/null +++ b/wulpus-frontend/eslint.config.js @@ -0,0 +1,27 @@ +import js from "@eslint/js" +import globals from "globals" +import reactHooks from "eslint-plugin-react-hooks" +import reactRefresh from "eslint-plugin-react-refresh" +import tseslint from "typescript-eslint" +import { globalIgnores } from "eslint/config" + +export default tseslint.config([ + globalIgnores(["dist"]), + { + files: ["**/*.{ts,tsx}"], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs["recommended-latest"], + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + rules: { + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": ["off", { argsIgnorePattern: "^_" }], + }, + }, +]) diff --git a/wulpus-frontend/index.html b/wulpus-frontend/index.html new file mode 100644 index 0000000..229c509 --- /dev/null +++ b/wulpus-frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + WULPUS + + +
+ + + diff --git a/wulpus-frontend/package-lock.json b/wulpus-frontend/package-lock.json new file mode 100644 index 0000000..7c77879 --- /dev/null +++ b/wulpus-frontend/package-lock.json @@ -0,0 +1,6229 @@ +{ + "name": "wulpus-frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "wulpus-frontend", + "version": "0.0.0", + "dependencies": { + "@tailwindcss/vite": "^4.1.12", + "plotly.js": "^3.1.0", + "react": "^19.1.1", + "react-dom": "^19.1.1", + "react-plotly.js": "^2.6.0", + "react-use-websocket": "^4.13.0", + "tailwindcss": "^4.1.12" + }, + "devDependencies": { + "@eslint/js": "^9.33.0", + "@types/plotly.js": "^3.0.3", + "@types/react": "^19.1.10", + "@types/react-dom": "^19.1.7", + "@types/react-plotly.js": "^2.6.3", + "@vitejs/plugin-react-swc": "^4.0.0", + "eslint": "^9.33.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.39.1", + "vite": "^7.1.2" + } + }, + "node_modules/@choojs/findup": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@choojs/findup/-/findup-0.2.1.tgz", + "integrity": "sha512-YstAqNb0MCN8PjdLCDfRsBcGVRN41f3vgLvaI0IrIcBp4AqILRSS0DeWNGkicC+f/zRIPJLc+9RURVSepwvfBw==", + "license": "MIT", + "dependencies": { + "commander": "^2.15.1" + }, + "bin": { + "findup": "bin/findup.js" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.33.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.33.0.tgz", + "integrity": "sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mapbox/geojson-rewind": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", + "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", + "license": "ISC", + "dependencies": { + "get-stream": "^6.0.1", + "minimist": "^1.2.6" + }, + "bin": { + "geojson-rewind": "geojson-rewind" + } + }, + "node_modules/@mapbox/geojson-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@mapbox/geojson-types/-/geojson-types-1.0.2.tgz", + "integrity": "sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw==", + "license": "ISC" + }, + "node_modules/@mapbox/jsonlint-lines-primitives": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", + "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@mapbox/mapbox-gl-supported": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.5.0.tgz", + "integrity": "sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg==", + "license": "BSD-3-Clause", + "peerDependencies": { + "mapbox-gl": ">=0.32.1 <2.0.0" + } + }, + "node_modules/@mapbox/point-geometry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", + "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", + "license": "ISC" + }, + "node_modules/@mapbox/tiny-sdf": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-1.2.5.tgz", + "integrity": "sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/unitbezier": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz", + "integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/vector-tile": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", + "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", + "license": "BSD-3-Clause", + "dependencies": { + "@mapbox/point-geometry": "~0.1.0" + } + }, + "node_modules/@mapbox/whoots-js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", + "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", + "license": "ISC", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@maplibre/maplibre-gl-style-spec": { + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.4.0.tgz", + "integrity": "sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw==", + "license": "ISC", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/unitbezier": "^0.0.1", + "json-stringify-pretty-compact": "^4.0.0", + "minimist": "^1.2.8", + "quickselect": "^2.0.0", + "rw": "^1.3.3", + "tinyqueue": "^3.0.0" + }, + "bin": { + "gl-style-format": "dist/gl-style-format.mjs", + "gl-style-migrate": "dist/gl-style-migrate.mjs", + "gl-style-validate": "dist/gl-style-validate.mjs" + } + }, + "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", + "license": "BSD-2-Clause" + }, + "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/tinyqueue": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", + "license": "ISC" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@plotly/d3": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@plotly/d3/-/d3-3.8.2.tgz", + "integrity": "sha512-wvsNmh1GYjyJfyEBPKJLTMzgf2c2bEbSIL50lmqVUi+o1NHaLPi1Lb4v7VxXXJn043BhNyrxUrWI85Q+zmjOVA==", + "license": "BSD-3-Clause" + }, + "node_modules/@plotly/d3-sankey": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@plotly/d3-sankey/-/d3-sankey-0.7.2.tgz", + "integrity": "sha512-2jdVos1N3mMp3QW0k2q1ph7Gd6j5PY1YihBrwpkFnKqO+cqtZq3AdEYUeSGXMeLsBDQYiqTVcihYfk8vr5tqhw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1", + "d3-collection": "1", + "d3-shape": "^1.2.0" + } + }, + "node_modules/@plotly/d3-sankey-circular": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@plotly/d3-sankey-circular/-/d3-sankey-circular-0.33.1.tgz", + "integrity": "sha512-FgBV1HEvCr3DV7RHhDsPXyryknucxtfnLwPtCKKxdolKyTFYoLX/ibEfX39iFYIL7DYbVeRtP43dbFcrHNE+KQ==", + "license": "MIT", + "dependencies": { + "d3-array": "^1.2.1", + "d3-collection": "^1.0.4", + "d3-shape": "^1.2.0", + "elementary-circuits-directed-graph": "^1.0.4" + } + }, + "node_modules/@plotly/mapbox-gl": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/@plotly/mapbox-gl/-/mapbox-gl-1.13.4.tgz", + "integrity": "sha512-sR3/Pe5LqT/fhYgp4rT4aSFf1rTsxMbGiH6Hojc7PH36ny5Bn17iVFUjpzycafETURuFbLZUfjODO8LvSI+5zQ==", + "license": "SEE LICENSE IN LICENSE.txt", + "dependencies": { + "@mapbox/geojson-rewind": "^0.5.2", + "@mapbox/geojson-types": "^1.0.2", + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/mapbox-gl-supported": "^1.5.0", + "@mapbox/point-geometry": "^0.1.0", + "@mapbox/tiny-sdf": "^1.1.1", + "@mapbox/unitbezier": "^0.0.0", + "@mapbox/vector-tile": "^1.3.1", + "@mapbox/whoots-js": "^3.1.0", + "csscolorparser": "~1.0.3", + "earcut": "^2.2.2", + "geojson-vt": "^3.2.1", + "gl-matrix": "^3.2.1", + "grid-index": "^1.1.0", + "murmurhash-js": "^1.0.0", + "pbf": "^3.2.1", + "potpack": "^1.0.1", + "quickselect": "^2.0.0", + "rw": "^1.3.3", + "supercluster": "^7.1.0", + "tinyqueue": "^2.0.3", + "vt-pbf": "^3.1.1" + }, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/@plotly/point-cluster": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@plotly/point-cluster/-/point-cluster-3.1.9.tgz", + "integrity": "sha512-MwaI6g9scKf68Orpr1pHZ597pYx9uP8UEFXLPbsCmuw3a84obwz6pnMXGc90VhgDNeNiLEdlmuK7CPo+5PIxXw==", + "license": "MIT", + "dependencies": { + "array-bounds": "^1.0.1", + "binary-search-bounds": "^2.0.4", + "clamp": "^1.0.1", + "defined": "^1.0.0", + "dtype": "^2.0.0", + "flatten-vertex-data": "^1.0.2", + "is-obj": "^1.0.1", + "math-log2": "^1.0.1", + "parse-rect": "^1.2.0", + "pick-by-alias": "^1.2.0" + } + }, + "node_modules/@plotly/regl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@plotly/regl/-/regl-2.1.2.tgz", + "integrity": "sha512-Mdk+vUACbQvjd0m/1JJjOOafmkp/EpmHjISsopEz5Av44CBq7rPC05HHNbYGKVyNUF2zmEoBS/TT0pd0SPFFyw==", + "license": "MIT" + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.32.tgz", + "integrity": "sha512-QReCdvxiUZAPkvp1xpAg62IeNzykOFA6syH2CnClif4YmALN1XKpB39XneL80008UbtMShthSVDKmrx05N1q/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.47.1.tgz", + "integrity": "sha512-lTahKRJip0knffA/GTNFJMrToD+CM+JJ+Qt5kjzBK/sFQ0EWqfKW3AYQSlZXN98tX0lx66083U9JYIMioMMK7g==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.47.1.tgz", + "integrity": "sha512-uqxkb3RJLzlBbh/bbNQ4r7YpSZnjgMgyoEOY7Fy6GCbelkDSAzeiogxMG9TfLsBbqmGsdDObo3mzGqa8hps4MA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.47.1.tgz", + "integrity": "sha512-tV6reObmxBDS4DDyLzTDIpymthNlxrLBGAoQx6m2a7eifSNEZdkXQl1PE4ZjCkEDPVgNXSzND/k9AQ3mC4IOEQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.47.1.tgz", + "integrity": "sha512-XuJRPTnMk1lwsSnS3vYyVMu4x/+WIw1MMSiqj5C4j3QOWsMzbJEK90zG+SWV1h0B1ABGCQ0UZUjti+TQK35uHQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.47.1.tgz", + "integrity": "sha512-79BAm8Ag/tmJ5asCqgOXsb3WY28Rdd5Lxj8ONiQzWzy9LvWORd5qVuOnjlqiWWZJw+dWewEktZb5yiM1DLLaHw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.47.1.tgz", + "integrity": "sha512-OQ2/ZDGzdOOlyfqBiip0ZX/jVFekzYrGtUsqAfLDbWy0jh1PUU18+jYp8UMpqhly5ltEqotc2miLngf9FPSWIA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.47.1.tgz", + "integrity": "sha512-HZZBXJL1udxlCVvoVadstgiU26seKkHbbAMLg7680gAcMnRNP9SAwTMVet02ANA94kXEI2VhBnXs4e5nf7KG2A==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.47.1.tgz", + "integrity": "sha512-sZ5p2I9UA7T950JmuZ3pgdKA6+RTBr+0FpK427ExW0t7n+QwYOcmDTK/aRlzoBrWyTpJNlS3kacgSlSTUg6P/Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.47.1.tgz", + "integrity": "sha512-3hBFoqPyU89Dyf1mQRXCdpc6qC6At3LV6jbbIOZd72jcx7xNk3aAp+EjzAtN6sDlmHFzsDJN5yeUySvorWeRXA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.47.1.tgz", + "integrity": "sha512-49J4FnMHfGodJWPw73Ve+/hsPjZgcXQGkmqBGZFvltzBKRS+cvMiWNLadOMXKGnYRhs1ToTGM0sItKISoSGUNA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.47.1.tgz", + "integrity": "sha512-4yYU8p7AneEpQkRX03pbpLmE21z5JNys16F1BZBZg5fP9rIlb0TkeQjn5du5w4agConCCEoYIG57sNxjryHEGg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.47.1.tgz", + "integrity": "sha512-fAiq+J28l2YMWgC39jz/zPi2jqc0y3GSRo1yyxlBHt6UN0yYgnegHSRPa3pnHS5amT/efXQrm0ug5+aNEu9UuQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.47.1.tgz", + "integrity": "sha512-daoT0PMENNdjVYYU9xec30Y2prb1AbEIbb64sqkcQcSaR0zYuKkoPuhIztfxuqN82KYCKKrj+tQe4Gi7OSm1ow==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.47.1.tgz", + "integrity": "sha512-JNyXaAhWtdzfXu5pUcHAuNwGQKevR+6z/poYQKVW+pLaYOj9G1meYc57/1Xv2u4uTxfu9qEWmNTjv/H/EpAisw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.47.1.tgz", + "integrity": "sha512-U/CHbqKSwEQyZXjCpY43/GLYcTVKEXeRHw0rMBJP7fP3x6WpYG4LTJWR3ic6TeYKX6ZK7mrhltP4ppolyVhLVQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.47.1.tgz", + "integrity": "sha512-uTLEakjxOTElfeZIGWkC34u2auLHB1AYS6wBjPGI00bWdxdLcCzK5awjs25YXpqB9lS8S0vbO0t9ZcBeNibA7g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.47.1.tgz", + "integrity": "sha512-Ft+d/9DXs30BK7CHCTX11FtQGHUdpNDLJW0HHLign4lgMgBcPFN3NkdIXhC5r9iwsMwYreBBc4Rho5ieOmKNVQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.47.1.tgz", + "integrity": "sha512-N9X5WqGYzZnjGAFsKSfYFtAShYjwOmFJoWbLg3dYixZOZqU7hdMq+/xyS14zKLhFhZDhP9VfkzQnsdk0ZDS9IA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.47.1.tgz", + "integrity": "sha512-O+KcfeCORZADEY8oQJk4HK8wtEOCRE4MdOkb8qGZQNun3jzmj2nmhV/B/ZaaZOkPmJyvm/gW9n0gsB4eRa1eiQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.47.1.tgz", + "integrity": "sha512-CpKnYa8eHthJa3c+C38v/E+/KZyF1Jdh2Cz3DyKZqEWYgrM1IHFArXNWvBLPQCKUEsAqqKX27tTqVEFbDNUcOA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@swc/core": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.13.4.tgz", + "integrity": "sha512-bCq2GCuKV16DSOOEdaRqHMm1Ok4YEoLoNdgdzp8BS/Hxxr/0NVCHBUgRLLRy/TlJGv20Idx+djd5FIDvsnqMaw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.24" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.13.4", + "@swc/core-darwin-x64": "1.13.4", + "@swc/core-linux-arm-gnueabihf": "1.13.4", + "@swc/core-linux-arm64-gnu": "1.13.4", + "@swc/core-linux-arm64-musl": "1.13.4", + "@swc/core-linux-x64-gnu": "1.13.4", + "@swc/core-linux-x64-musl": "1.13.4", + "@swc/core-win32-arm64-msvc": "1.13.4", + "@swc/core-win32-ia32-msvc": "1.13.4", + "@swc/core-win32-x64-msvc": "1.13.4" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.13.4.tgz", + "integrity": "sha512-CGbTu9dGBwgklUj+NAQAYyPjBuoHaNRWK4QXJRv1QNIkhtE27aY7QA9uEON14SODxsio3t8+Pjjl2Mzx1Pxf+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.13.4.tgz", + "integrity": "sha512-qLFwYmLrqHNCf+JO9YLJT6IP/f9LfbXILTaqyfluFLW1GCfJyvUrSt3CWaL2lwwyT1EbBh6BVaAAecXiJIo3vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.13.4.tgz", + "integrity": "sha512-y7SeNIA9em3+smNMpr781idKuNwJNAqewiotv+pIR5FpXdXXNjHWW+jORbqQYd61k6YirA5WQv+Af4UzqEX17g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.13.4.tgz", + "integrity": "sha512-u0c51VdzRmXaphLgghY9+B2Frzler6nIv+J788nqIh6I0ah3MmMW8LTJKZfdaJa3oFxzGNKXsJiaU2OFexNkug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.13.4.tgz", + "integrity": "sha512-Z92GJ98x8yQHn4I/NPqwAQyHNkkMslrccNVgFcnY1msrb6iGSw5uFg2H2YpvQ5u2/Yt6CRpLIUVVh8SGg1+gFA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.13.4.tgz", + "integrity": "sha512-rSUcxgpFF0L8Fk1CbUf946XCX1CRp6eaHfKqplqFNWCHv8HyqAtSFvgCHhT+bXru6Ca/p3sLC775SUeSWhsJ9w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.13.4.tgz", + "integrity": "sha512-qY77eFUvmdXNSmTW+I1fsz4enDuB0I2fE7gy6l9O4koSfjcCxkXw2X8x0lmKLm3FRiINS1XvZSg2G+q4NNQCRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.13.4.tgz", + "integrity": "sha512-xjPeDrOf6elCokxuyxwoskM00JJFQMTT2hTQZE24okjG3JiXzSFV+TmzYSp+LWNxPpnufnUUy/9Ee8+AcpslGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.13.4.tgz", + "integrity": "sha512-Ta+Bblc9tE9X9vQlpa3r3+mVnHYdKn09QsZ6qQHvuXGKWSS99DiyxKTYX2vxwMuoTObR0BHvnhNbaGZSV1VwNA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.13.4.tgz", + "integrity": "sha512-pHnb4QwGiuWs4Z9ePSgJ48HP3NZIno6l75SB8YLCiPVDiLhvCLKEjz/caPRsFsmet9BEP8e3bAf2MV8MXgaTSg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/types": { + "version": "0.1.24", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.24.tgz", + "integrity": "sha512-tjTMh3V4vAORHtdTprLlfoMptu1WfTZG9Rsca6yOKyNYsRr+MUXutKmliB17orgSZk5DpnDxs8GUdd/qwYxOng==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.12.tgz", + "integrity": "sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.5.1", + "lightningcss": "1.30.1", + "magic-string": "^0.30.17", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.12" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.12.tgz", + "integrity": "sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.4.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.12", + "@tailwindcss/oxide-darwin-arm64": "4.1.12", + "@tailwindcss/oxide-darwin-x64": "4.1.12", + "@tailwindcss/oxide-freebsd-x64": "4.1.12", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.12", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.12", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.12", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.12", + "@tailwindcss/oxide-linux-x64-musl": "4.1.12", + "@tailwindcss/oxide-wasm32-wasi": "4.1.12", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.12", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.12" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.12.tgz", + "integrity": "sha512-oNY5pq+1gc4T6QVTsZKwZaGpBb2N1H1fsc1GD4o7yinFySqIuRZ2E4NvGasWc6PhYJwGK2+5YT1f9Tp80zUQZQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.12.tgz", + "integrity": "sha512-cq1qmq2HEtDV9HvZlTtrj671mCdGB93bVY6J29mwCyaMYCP/JaUBXxrQQQm7Qn33AXXASPUb2HFZlWiiHWFytw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.12.tgz", + "integrity": "sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.12.tgz", + "integrity": "sha512-JOH/f7j6+nYXIrHobRYCtoArJdMJh5zy5lr0FV0Qu47MID/vqJAY3r/OElPzx1C/wdT1uS7cPq+xdYYelny1ww==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.12.tgz", + "integrity": "sha512-v4Ghvi9AU1SYgGr3/j38PD8PEe6bRfTnNSUE3YCMIRrrNigCFtHZ2TCm8142X8fcSqHBZBceDx+JlFJEfNg5zQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.12.tgz", + "integrity": "sha512-YP5s1LmetL9UsvVAKusHSyPlzSRqYyRB0f+Kl/xcYQSPLEw/BvGfxzbH+ihUciePDjiXwHh+p+qbSP3SlJw+6g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.12.tgz", + "integrity": "sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.12.tgz", + "integrity": "sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.12.tgz", + "integrity": "sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.12.tgz", + "integrity": "sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.5", + "@emnapi/runtime": "^1.4.5", + "@emnapi/wasi-threads": "^1.0.4", + "@napi-rs/wasm-runtime": "^0.2.12", + "@tybys/wasm-util": "^0.10.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.12.tgz", + "integrity": "sha512-iGLyD/cVP724+FGtMWslhcFyg4xyYyM+5F4hGvKA7eifPkXHRAUDFaimu53fpNg9X8dfP75pXx/zFt/jlNF+lg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.12.tgz", + "integrity": "sha512-NKIh5rzw6CpEodv/++r0hGLlfgT/gFN+5WNdZtvh6wpU2BpGNgdjvj6H2oFc8nCM839QM1YOhjpgbAONUb4IxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.12.tgz", + "integrity": "sha512-4pt0AMFDx7gzIrAOIYgYP0KCBuKWqyW8ayrdiLEjoJTT4pKTjrzG/e4uzWtTLDziC+66R9wbUqZBccJalSE5vQ==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.12", + "@tailwindcss/oxide": "4.1.12", + "tailwindcss": "4.1.12" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@turf/area": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/area/-/area-7.2.0.tgz", + "integrity": "sha512-zuTTdQ4eoTI9nSSjerIy4QwgvxqwJVciQJ8tOPuMHbXJ9N/dNjI7bU8tasjhxas/Cx3NE9NxVHtNpYHL0FSzoA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^7.2.0", + "@turf/meta": "^7.2.0", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bbox": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-7.2.0.tgz", + "integrity": "sha512-wzHEjCXlYZiDludDbXkpBSmv8Zu6tPGLmJ1sXQ6qDwpLE1Ew3mcWqt8AaxfTP5QwDNQa3sf2vvgTEzNbPQkCiA==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^7.2.0", + "@turf/meta": "^7.2.0", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/centroid": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-7.2.0.tgz", + "integrity": "sha512-yJqDSw25T7P48au5KjvYqbDVZ7qVnipziVfZ9aSo7P2/jTE7d4BP21w0/XLi3T/9bry/t9PR1GDDDQljN4KfDw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^7.2.0", + "@turf/meta": "^7.2.0", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/helpers": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.2.0.tgz", + "integrity": "sha512-cXo7bKNZoa7aC7ydLmUR02oB3IgDe7MxiPuRz3cCtYQHn+BJ6h1tihmamYDWWUlPHgSNF0i3ATc4WmDECZafKw==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/meta": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.2.0.tgz", + "integrity": "sha512-igzTdHsQc8TV1RhPuOLVo74Px/hyPrVgVOTgjWQZzt3J9BVseCdpfY/0cJBdlSRI4S/yTmmHl7gAqjhpYH5Yaw==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "^7.2.0", + "@types/geojson": "^7946.0.10" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/geojson-vt": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@types/geojson-vt/-/geojson-vt-3.2.5.tgz", + "integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mapbox__point-geometry": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz", + "integrity": "sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==", + "license": "MIT" + }, + "node_modules/@types/mapbox__vector-tile": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.4.tgz", + "integrity": "sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*", + "@types/mapbox__point-geometry": "*", + "@types/pbf": "*" + } + }, + "node_modules/@types/pbf": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", + "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==", + "license": "MIT" + }, + "node_modules/@types/plotly.js": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/plotly.js/-/plotly.js-3.0.3.tgz", + "integrity": "sha512-9CENH8hh2diOML3o4lEd4H0nwQ4uECEE9mZQc+zriGEdd0zK8ru75t7qFhaMQmiWFFPGWqI4FpodBZFTmWpdbQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.1.10", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.10.tgz", + "integrity": "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.1.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz", + "integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@types/react-plotly.js": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@types/react-plotly.js/-/react-plotly.js-2.6.3.tgz", + "integrity": "sha512-HBQwyGuu/dGXDsWhnQrhH+xcJSsHvjkwfSRjP+YpOsCCWryIuXF78ZCBjpfgO3sCc0Jo8sYp4NOGtqT7Cn3epQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/plotly.js": "*", + "@types/react": "*" + } + }, + "node_modules/@types/supercluster": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz", + "integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.40.0.tgz", + "integrity": "sha512-w/EboPlBwnmOBtRbiOvzjD+wdiZdgFeo17lkltrtn7X37vagKKWJABvyfsJXTlHe6XBzugmYgd4A4nW+k8Mixw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.40.0", + "@typescript-eslint/type-utils": "8.40.0", + "@typescript-eslint/utils": "8.40.0", + "@typescript-eslint/visitor-keys": "8.40.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.40.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.40.0.tgz", + "integrity": "sha512-jCNyAuXx8dr5KJMkecGmZ8KI61KBUhkCob+SD+C+I5+Y1FWI2Y3QmY4/cxMCC5WAsZqoEtEETVhUiUMIGCf6Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.40.0", + "@typescript-eslint/types": "8.40.0", + "@typescript-eslint/typescript-estree": "8.40.0", + "@typescript-eslint/visitor-keys": "8.40.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.40.0.tgz", + "integrity": "sha512-/A89vz7Wf5DEXsGVvcGdYKbVM9F7DyFXj52lNYUDS1L9yJfqjW/fIp5PgMuEJL/KeqVTe2QSbXAGUZljDUpArw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.40.0", + "@typescript-eslint/types": "^8.40.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.40.0.tgz", + "integrity": "sha512-y9ObStCcdCiZKzwqsE8CcpyuVMwRouJbbSrNuThDpv16dFAj429IkM6LNb1dZ2m7hK5fHyzNcErZf7CEeKXR4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.40.0", + "@typescript-eslint/visitor-keys": "8.40.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.40.0.tgz", + "integrity": "sha512-jtMytmUaG9d/9kqSl/W3E3xaWESo4hFDxAIHGVW/WKKtQhesnRIJSAJO6XckluuJ6KDB5woD1EiqknriCtAmcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.40.0.tgz", + "integrity": "sha512-eE60cK4KzAc6ZrzlJnflXdrMqOBaugeukWICO2rB0KNvwdIMaEaYiywwHMzA1qFpTxrLhN9Lp4E/00EgWcD3Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.40.0", + "@typescript-eslint/typescript-estree": "8.40.0", + "@typescript-eslint/utils": "8.40.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.40.0.tgz", + "integrity": "sha512-ETdbFlgbAmXHyFPwqUIYrfc12ArvpBhEVgGAxVYSwli26dn8Ko+lIo4Su9vI9ykTZdJn+vJprs/0eZU0YMAEQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.40.0.tgz", + "integrity": "sha512-k1z9+GJReVVOkc1WfVKs1vBrR5MIKKbdAjDTPvIK3L8De6KbFfPFt6BKpdkdk7rZS2GtC/m6yI5MYX+UsuvVYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.40.0", + "@typescript-eslint/tsconfig-utils": "8.40.0", + "@typescript-eslint/types": "8.40.0", + "@typescript-eslint/visitor-keys": "8.40.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.40.0.tgz", + "integrity": "sha512-Cgzi2MXSZyAUOY+BFwGs17s7ad/7L+gKt6Y8rAVVWS+7o6wrjeFN4nVfTpbE25MNcxyJ+iYUXflbs2xR9h4UBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.40.0", + "@typescript-eslint/types": "8.40.0", + "@typescript-eslint/typescript-estree": "8.40.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.40.0.tgz", + "integrity": "sha512-8CZ47QwalyRjsypfwnbI3hKy5gJDPmrkLjkgMxhi0+DZZ2QNx2naS6/hWoVYUHU7LU2zleF68V9miaVZvhFfTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.40.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-4.0.1.tgz", + "integrity": "sha512-NQhPjysi5duItyrMd5JWZFf2vNOuSMyw+EoZyTBDzk+DkfYD8WNrsUs09sELV2cr1P15nufsN25hsUBt4CKF9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-beta.32", + "@swc/core": "^1.13.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/abs-svg-path": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz", + "integrity": "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==", + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-bounds": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-bounds/-/array-bounds-1.0.1.tgz", + "integrity": "sha512-8wdW3ZGk6UjMPJx/glyEt0sLzzwAE1bhToPsO1W2pbpR2gULyxe3BjSiuJFheP50T/GgODVPz2fuMUmIywt8cQ==", + "license": "MIT" + }, + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-normalize": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array-normalize/-/array-normalize-1.1.4.tgz", + "integrity": "sha512-fCp0wKFLjvSPmCn4F5Tiw4M3lpMZoHlCjfcs7nNzuj3vqQQ1/a8cgB9DXcpDSn18c+coLnaW7rqfcYCvKbyJXg==", + "license": "MIT", + "dependencies": { + "array-bounds": "^1.0.0" + } + }, + "node_modules/array-range": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-range/-/array-range-1.0.1.tgz", + "integrity": "sha512-shdaI1zT3CVNL2hnx9c0JMc0ZogGaxDs5e85akgHWKYa0yVbIyp06Ind3dVkTj/uuFrzaHBOyqFzo+VV6aXgtA==", + "license": "MIT" + }, + "node_modules/array-rearrange": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/array-rearrange/-/array-rearrange-2.2.2.tgz", + "integrity": "sha512-UfobP5N12Qm4Qu4fwLDIi2v6+wZsSf6snYSxAMeKhrh37YGnNWZPRmVEKc/2wfms53TLQnzfpG8wCx2Y/6NG1w==", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/binary-search-bounds": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/binary-search-bounds/-/binary-search-bounds-2.0.5.tgz", + "integrity": "sha512-H0ea4Fd3lS1+sTEB2TgcLoK21lLhwEJzlQv3IN47pJS976Gx4zoWe0ak3q+uYh60ppQxg9F16Ri4tS1sfD4+jA==", + "license": "MIT" + }, + "node_modules/bit-twiddle": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bit-twiddle/-/bit-twiddle-1.0.2.tgz", + "integrity": "sha512-B9UhK0DKFZhoTFcfvAzhqsjStvGJp9vYWf3+6SNTtdSQnvIgfkHbgHrg/e4+TH71N2GDu8tpmCVoyfrL1d7ntA==", + "license": "MIT" + }, + "node_modules/bitmap-sdf": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/bitmap-sdf/-/bitmap-sdf-1.0.4.tgz", + "integrity": "sha512-1G3U4n5JE6RAiALMxu0p1XmeZkTeCwGKykzsLTCqVzfSDaN6S7fKnkIkfejogz+iwqBWc0UYAIKnKHNN7pSfDg==", + "license": "MIT" + }, + "node_modules/bl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "license": "MIT", + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/canvas-fit": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/canvas-fit/-/canvas-fit-1.5.0.tgz", + "integrity": "sha512-onIcjRpz69/Hx5bB5HGbYKUF2uC6QT6Gp+pfpGm3A7mPfcluSLV5v4Zu+oflDUwLdUw0rLIBhUbi0v8hM4FJQQ==", + "license": "MIT", + "dependencies": { + "element-size": "^1.1.1" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/clamp": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/clamp/-/clamp-1.0.1.tgz", + "integrity": "sha512-kgMuFyE78OC6Dyu3Dy7vcx4uy97EIbVxJB/B0eJ3bUNAkwdNcxYzgKltnyADiYwsR7SEqkkUPsEUT//OVS6XMA==", + "license": "MIT" + }, + "node_modules/color-alpha": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/color-alpha/-/color-alpha-1.0.4.tgz", + "integrity": "sha512-lr8/t5NPozTSqli+duAN+x+no/2WaKTeWvxhHGN+aXT6AJ8vPlzLa7UriyjWak0pSC2jHol9JgjBYnnHsGha9A==", + "license": "MIT", + "dependencies": { + "color-parse": "^1.3.8" + } + }, + "node_modules/color-alpha/node_modules/color-parse": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-1.4.3.tgz", + "integrity": "sha512-BADfVl/FHkQkyo8sRBwMYBqemqsgnu7JZAwUgvBvuwwuNUZAhSvLTbsEErS5bQXzOjDR0dWzJ4vXN2Q+QoPx0A==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/color-id/-/color-id-1.1.0.tgz", + "integrity": "sha512-2iRtAn6dC/6/G7bBIo0uupVrIne1NsQJvJxZOBCzQOfk7jRq97feaDZ3RdzuHakRXXnHGNwglto3pqtRx1sX0g==", + "license": "MIT", + "dependencies": { + "clamp": "^1.0.1" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-normalize": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/color-normalize/-/color-normalize-1.5.0.tgz", + "integrity": "sha512-rUT/HDXMr6RFffrR53oX3HGWkDOP9goSAQGBkUaAYKjOE2JxozccdGyufageWDlInRAjm/jYPrf/Y38oa+7obw==", + "license": "MIT", + "dependencies": { + "clamp": "^1.0.1", + "color-rgba": "^2.1.1", + "dtype": "^2.0.0" + } + }, + "node_modules/color-normalize/node_modules/color-parse": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-1.4.3.tgz", + "integrity": "sha512-BADfVl/FHkQkyo8sRBwMYBqemqsgnu7JZAwUgvBvuwwuNUZAhSvLTbsEErS5bQXzOjDR0dWzJ4vXN2Q+QoPx0A==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0" + } + }, + "node_modules/color-normalize/node_modules/color-rgba": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/color-rgba/-/color-rgba-2.4.0.tgz", + "integrity": "sha512-Nti4qbzr/z2LbUWySr7H9dk3Rl7gZt7ihHAxlgT4Ho90EXWkjtkL1avTleu9yeGuqrt/chxTB6GKK8nZZ6V0+Q==", + "license": "MIT", + "dependencies": { + "color-parse": "^1.4.2", + "color-space": "^2.0.0" + } + }, + "node_modules/color-parse": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-2.0.0.tgz", + "integrity": "sha512-g2Z+QnWsdHLppAbrpcFWo629kLOnOPtpxYV69GCqm92gqSgyXbzlfyN3MXs0412fPBkFmiuS+rXposgBgBa6Kg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0" + } + }, + "node_modules/color-rgba": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color-rgba/-/color-rgba-3.0.0.tgz", + "integrity": "sha512-PPwZYkEY3M2THEHHV6Y95sGUie77S7X8v+h1r6LSAPF3/LL2xJ8duUXSrkic31Nzc4odPwHgUbiX/XuTYzQHQg==", + "license": "MIT", + "dependencies": { + "color-parse": "^2.0.0", + "color-space": "^2.0.0" + } + }, + "node_modules/color-space": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/color-space/-/color-space-2.3.2.tgz", + "integrity": "sha512-BcKnbOEsOarCwyoLstcoEztwT0IJxqqQkNwDuA3a65sICvvHL2yoeV13psoDFh5IuiOMnIOKdQDwB4Mk3BypiA==", + "license": "Unlicense" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/country-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/country-regex/-/country-regex-1.1.0.tgz", + "integrity": "sha512-iSPlClZP8vX7MC3/u6s3lrDuoQyhQukh5LyABJ3hvfzbQ3Yyayd4fp04zjLnfi267B/B2FkumcWWgrbban7sSA==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-font": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-font/-/css-font-1.2.0.tgz", + "integrity": "sha512-V4U4Wps4dPDACJ4WpgofJ2RT5Yqwe1lEH6wlOOaIxMi0gTjdIijsc5FmxQlZ7ZZyKQkkutqqvULOp07l9c7ssA==", + "license": "MIT", + "dependencies": { + "css-font-size-keywords": "^1.0.0", + "css-font-stretch-keywords": "^1.0.1", + "css-font-style-keywords": "^1.0.1", + "css-font-weight-keywords": "^1.0.0", + "css-global-keywords": "^1.0.1", + "css-system-font-keywords": "^1.0.0", + "pick-by-alias": "^1.2.0", + "string-split-by": "^1.0.0", + "unquote": "^1.1.0" + } + }, + "node_modules/css-font-size-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-font-size-keywords/-/css-font-size-keywords-1.0.0.tgz", + "integrity": "sha512-Q+svMDbMlelgCfH/RVDKtTDaf5021O486ZThQPIpahnIjUkMUslC+WuOQSWTgGSrNCH08Y7tYNEmmy0hkfMI8Q==", + "license": "MIT" + }, + "node_modules/css-font-stretch-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-font-stretch-keywords/-/css-font-stretch-keywords-1.0.1.tgz", + "integrity": "sha512-KmugPO2BNqoyp9zmBIUGwt58UQSfyk1X5DbOlkb2pckDXFSAfjsD5wenb88fNrD6fvS+vu90a/tsPpb9vb0SLg==", + "license": "MIT" + }, + "node_modules/css-font-style-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-font-style-keywords/-/css-font-style-keywords-1.0.1.tgz", + "integrity": "sha512-0Fn0aTpcDktnR1RzaBYorIxQily85M2KXRpzmxQPgh8pxUN9Fcn00I8u9I3grNr1QXVgCl9T5Imx0ZwKU973Vg==", + "license": "MIT" + }, + "node_modules/css-font-weight-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-font-weight-keywords/-/css-font-weight-keywords-1.0.0.tgz", + "integrity": "sha512-5So8/NH+oDD+EzsnF4iaG4ZFHQ3vaViePkL1ZbZ5iC/KrsCY+WHq/lvOgrtmuOQ9pBBZ1ADGpaf+A4lj1Z9eYA==", + "license": "MIT" + }, + "node_modules/css-global-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-global-keywords/-/css-global-keywords-1.0.1.tgz", + "integrity": "sha512-X1xgQhkZ9n94WDwntqst5D/FKkmiU0GlJSFZSV3kLvyJ1WC5VeyoXDOuleUD+SIuH9C7W05is++0Woh0CGfKjQ==", + "license": "MIT" + }, + "node_modules/css-system-font-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-system-font-keywords/-/css-system-font-keywords-1.0.0.tgz", + "integrity": "sha512-1umTtVd/fXS25ftfjB71eASCrYhilmEsvDEI6wG/QplnmlfmVM5HkZ/ZX46DT5K3eblFPgLUHt5BRCb0YXkSFA==", + "license": "MIT" + }, + "node_modules/csscolorparser": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", + "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-collection": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", + "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", + "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-force": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz", + "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-collection": "1", + "d3-dispatch": "1", + "d3-quadtree": "1", + "d3-timer": "1" + } + }, + "node_modules/d3-format": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", + "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-geo": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", + "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1" + } + }, + "node_modules/d3-geo-projection": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-2.9.0.tgz", + "integrity": "sha512-ZULvK/zBn87of5rWAfFMc9mJOipeSo57O+BBitsKIXmU4rTVAnX1kSsJkE0R+TxY8pGNoM1nbyRRE7GYHhdOEQ==", + "license": "BSD-3-Clause", + "dependencies": { + "commander": "2", + "d3-array": "1", + "d3-geo": "^1.12.0", + "resolve": "^1.1.10" + }, + "bin": { + "geo2svg": "bin/geo2svg", + "geograticule": "bin/geograticule", + "geoproject": "bin/geoproject", + "geoquantize": "bin/geoquantize", + "geostitch": "bin/geostitch" + } + }, + "node_modules/d3-hierarchy": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz", + "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-quadtree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.7.tgz", + "integrity": "sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", + "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-time-format": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", + "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-time": "1" + } + }, + "node_modules/d3-timer": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", + "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==", + "license": "BSD-3-Clause" + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/defined": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-kerning": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-kerning/-/detect-kerning-2.1.2.tgz", + "integrity": "sha512-I3JIbrnKPAntNLl1I6TpSQQdQ4AutYzv/sKMFKbepawV/hlH0GmYKhUoOEMd4xqaUHT+Bm0f4127lh5qs1m1tw==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/draw-svg-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/draw-svg-path/-/draw-svg-path-1.0.0.tgz", + "integrity": "sha512-P8j3IHxcgRMcY6sDzr0QvJDLzBnJJqpTG33UZ2Pvp8rw0apCHhJCWqYprqrXjrgHnJ6tuhP1iTJSAodPDHxwkg==", + "license": "MIT", + "dependencies": { + "abs-svg-path": "~0.1.1", + "normalize-svg-path": "~0.1.0" + } + }, + "node_modules/dtype": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dtype/-/dtype-2.0.0.tgz", + "integrity": "sha512-s2YVcLKdFGS0hpFqJaTwscsyt0E8nNFdmo73Ocd81xNPj4URI4rj6D60A+vFMIw7BXWlb4yRkEwfBqcZzPGiZg==", + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/dup": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dup/-/dup-1.0.0.tgz", + "integrity": "sha512-Bz5jxMMC0wgp23Zm15ip1x8IhYRqJvF3nFC0UInJUDkN1z4uNPk9jTnfCUJXbOGiQ1JbXLQsiV41Fb+HXcj5BA==", + "license": "MIT" + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/earcut": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", + "license": "ISC" + }, + "node_modules/element-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/element-size/-/element-size-1.1.1.tgz", + "integrity": "sha512-eaN+GMOq/Q+BIWy0ybsgpcYImjGIdNLyjLFJU4XsLHXYQao5jCNb36GyN6C2qwmDDYSfIBmKpPpr4VnBdLCsPQ==", + "license": "MIT" + }, + "node_modules/elementary-circuits-directed-graph": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/elementary-circuits-directed-graph/-/elementary-circuits-directed-graph-1.3.1.tgz", + "integrity": "sha512-ZEiB5qkn2adYmpXGnJKkxT8uJHlW/mxmBpmeqawEHzPxh9HkLD4/1mFYX5l0On+f6rcPIt8/EWlRU2Vo3fX6dQ==", + "license": "MIT", + "dependencies": { + "strongly-connected-components": "^1.0.1" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "license": "ISC", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/esbuild": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/eslint": { + "version": "9.33.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.33.0.tgz", + "integrity": "sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.1", + "@eslint/core": "^0.15.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.33.0", + "@eslint/plugin-kit": "^0.3.5", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz", + "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/falafel": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.2.5.tgz", + "integrity": "sha512-HuC1qF9iTnHDnML9YZAdCDQwT0yKl/U55K4XSUXqGAA2GLoafFgWRqdAbhWJxXaYD4pyoVxAJ8wH670jMpI9DQ==", + "license": "MIT", + "dependencies": { + "acorn": "^7.1.1", + "isarray": "^2.0.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/falafel/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-isnumeric": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-isnumeric/-/fast-isnumeric-1.1.4.tgz", + "integrity": "sha512-1mM8qOr2LYz8zGaUdmiqRDiuue00Dxjgcb1NQR7TnhLVh6sQyngP9xvLo7Sl7LZpP/sk5eb+bcyWXw530NTBZw==", + "license": "MIT", + "dependencies": { + "is-string-blank": "^1.0.1" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/flatten-vertex-data": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flatten-vertex-data/-/flatten-vertex-data-1.0.2.tgz", + "integrity": "sha512-BvCBFK2NZqerFTdMDgqfHBwxYWnxeCkwONsw6PvBMcUXqo8U/KDWwmXhqx1x2kLIg7DqIsJfOaJFOmlua3Lxuw==", + "license": "MIT", + "dependencies": { + "dtype": "^2.0.0" + } + }, + "node_modules/font-atlas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/font-atlas/-/font-atlas-2.1.0.tgz", + "integrity": "sha512-kP3AmvX+HJpW4w3d+PiPR2X6E1yvsBXt2yhuCw+yReO9F1WYhvZwx3c95DGZGwg9xYzDGrgJYa885xmVA+28Cg==", + "license": "MIT", + "dependencies": { + "css-font": "^1.0.0" + } + }, + "node_modules/font-measure": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/font-measure/-/font-measure-1.2.2.tgz", + "integrity": "sha512-mRLEpdrWzKe9hbfaF3Qpr06TAjquuBVP5cHy4b3hyeNdjc9i0PO6HniGsX5vjL5OWv7+Bd++NiooNpT/s8BvIA==", + "license": "MIT", + "dependencies": { + "css-font": "^1.2.0" + } + }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/geojson-vt": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", + "integrity": "sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==", + "license": "ISC" + }, + "node_modules/get-canvas-context": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-canvas-context/-/get-canvas-context-1.0.2.tgz", + "integrity": "sha512-LnpfLf/TNzr9zVOGiIY6aKCz8EKuXmlYNV7CM2pUjBa/B+c2I15tS7KLySep75+FuerJdmArvJLcsAXWEy2H0A==", + "license": "MIT" + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gl-mat4": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gl-mat4/-/gl-mat4-1.2.0.tgz", + "integrity": "sha512-sT5C0pwB1/e9G9AvAoLsoaJtbMGjfd/jfxo8jMCKqYYEnjZuFvqV5rehqar0538EmssjdDeiEWnKyBSTw7quoA==", + "license": "Zlib" + }, + "node_modules/gl-matrix": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.4.tgz", + "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==", + "license": "MIT" + }, + "node_modules/gl-text": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/gl-text/-/gl-text-1.4.0.tgz", + "integrity": "sha512-o47+XBqLCj1efmuNyCHt7/UEJmB9l66ql7pnobD6p+sgmBUdzfMZXIF0zD2+KRfpd99DJN+QXdvTFAGCKCVSmQ==", + "license": "MIT", + "dependencies": { + "bit-twiddle": "^1.0.2", + "color-normalize": "^1.5.0", + "css-font": "^1.2.0", + "detect-kerning": "^2.1.2", + "es6-weak-map": "^2.0.3", + "flatten-vertex-data": "^1.0.2", + "font-atlas": "^2.1.0", + "font-measure": "^1.2.2", + "gl-util": "^3.1.2", + "is-plain-obj": "^1.1.0", + "object-assign": "^4.1.1", + "parse-rect": "^1.2.0", + "parse-unit": "^1.0.1", + "pick-by-alias": "^1.2.0", + "regl": "^2.0.0", + "to-px": "^1.0.1", + "typedarray-pool": "^1.1.0" + } + }, + "node_modules/gl-util": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/gl-util/-/gl-util-3.1.3.tgz", + "integrity": "sha512-dvRTggw5MSkJnCbh74jZzSoTOGnVYK+Bt+Ckqm39CVcl6+zSsxqWk4lr5NKhkqXHL6qvZAU9h17ZF8mIskY9mA==", + "license": "MIT", + "dependencies": { + "is-browser": "^2.0.1", + "is-firefox": "^1.0.3", + "is-plain-obj": "^1.1.0", + "number-is-integer": "^1.0.1", + "object-assign": "^4.1.0", + "pick-by-alias": "^1.2.0", + "weak-map": "^1.0.5" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/global-prefix": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz", + "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==", + "license": "MIT", + "dependencies": { + "ini": "^4.1.3", + "kind-of": "^6.0.3", + "which": "^4.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/global-prefix/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/globals": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz", + "integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glsl-inject-defines": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/glsl-inject-defines/-/glsl-inject-defines-1.0.3.tgz", + "integrity": "sha512-W49jIhuDtF6w+7wCMcClk27a2hq8znvHtlGnrYkSWEr8tHe9eA2dcnohlcAmxLYBSpSSdzOkRdyPTrx9fw49+A==", + "license": "MIT", + "dependencies": { + "glsl-token-inject-block": "^1.0.0", + "glsl-token-string": "^1.0.1", + "glsl-tokenizer": "^2.0.2" + } + }, + "node_modules/glsl-resolve": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/glsl-resolve/-/glsl-resolve-0.0.1.tgz", + "integrity": "sha512-xxFNsfnhZTK9NBhzJjSBGX6IOqYpvBHxxmo+4vapiljyGNCY0Bekzn0firQkQrazK59c1hYxMDxYS8MDlhw4gA==", + "license": "MIT", + "dependencies": { + "resolve": "^0.6.1", + "xtend": "^2.1.2" + } + }, + "node_modules/glsl-resolve/node_modules/resolve": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.6.3.tgz", + "integrity": "sha512-UHBY3viPlJKf85YijDUcikKX6tmF4SokIDp518ZDVT92JNDcG5uKIthaT/owt3Sar0lwtOafsQuwrg22/v2Dwg==", + "license": "MIT" + }, + "node_modules/glsl-resolve/node_modules/xtend": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.2.0.tgz", + "integrity": "sha512-SLt5uylT+4aoXxXuwtQp5ZnMMzhDb1Xkg4pEqc00WUJCQifPfV9Ub1VrNhp9kXkrjZD2I2Hl8WnjP37jzZLPZw==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/glsl-token-assignments": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/glsl-token-assignments/-/glsl-token-assignments-2.0.2.tgz", + "integrity": "sha512-OwXrxixCyHzzA0U2g4btSNAyB2Dx8XrztY5aVUCjRSh4/D0WoJn8Qdps7Xub3sz6zE73W3szLrmWtQ7QMpeHEQ==", + "license": "MIT" + }, + "node_modules/glsl-token-defines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/glsl-token-defines/-/glsl-token-defines-1.0.0.tgz", + "integrity": "sha512-Vb5QMVeLjmOwvvOJuPNg3vnRlffscq2/qvIuTpMzuO/7s5kT+63iL6Dfo2FYLWbzuiycWpbC0/KV0biqFwHxaQ==", + "license": "MIT", + "dependencies": { + "glsl-tokenizer": "^2.0.0" + } + }, + "node_modules/glsl-token-depth": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/glsl-token-depth/-/glsl-token-depth-1.1.2.tgz", + "integrity": "sha512-eQnIBLc7vFf8axF9aoi/xW37LSWd2hCQr/3sZui8aBJnksq9C7zMeUYHVJWMhFzXrBU7fgIqni4EhXVW4/krpg==", + "license": "MIT" + }, + "node_modules/glsl-token-descope": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glsl-token-descope/-/glsl-token-descope-1.0.2.tgz", + "integrity": "sha512-kS2PTWkvi/YOeicVjXGgX5j7+8N7e56srNDEHDTVZ1dcESmbmpmgrnpjPcjxJjMxh56mSXYoFdZqb90gXkGjQw==", + "license": "MIT", + "dependencies": { + "glsl-token-assignments": "^2.0.0", + "glsl-token-depth": "^1.1.0", + "glsl-token-properties": "^1.0.0", + "glsl-token-scope": "^1.1.0" + } + }, + "node_modules/glsl-token-inject-block": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/glsl-token-inject-block/-/glsl-token-inject-block-1.1.0.tgz", + "integrity": "sha512-q/m+ukdUBuHCOtLhSr0uFb/qYQr4/oKrPSdIK2C4TD+qLaJvqM9wfXIF/OOBjuSA3pUoYHurVRNao6LTVVUPWA==", + "license": "MIT" + }, + "node_modules/glsl-token-properties": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/glsl-token-properties/-/glsl-token-properties-1.0.1.tgz", + "integrity": "sha512-dSeW1cOIzbuUoYH0y+nxzwK9S9O3wsjttkq5ij9ZGw0OS41BirKJzzH48VLm8qLg+au6b0sINxGC0IrGwtQUcA==", + "license": "MIT" + }, + "node_modules/glsl-token-scope": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/glsl-token-scope/-/glsl-token-scope-1.1.2.tgz", + "integrity": "sha512-YKyOMk1B/tz9BwYUdfDoHvMIYTGtVv2vbDSLh94PT4+f87z21FVdou1KNKgF+nECBTo0fJ20dpm0B1vZB1Q03A==", + "license": "MIT" + }, + "node_modules/glsl-token-string": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/glsl-token-string/-/glsl-token-string-1.0.1.tgz", + "integrity": "sha512-1mtQ47Uxd47wrovl+T6RshKGkRRCYWhnELmkEcUAPALWGTFe2XZpH3r45XAwL2B6v+l0KNsCnoaZCSnhzKEksg==", + "license": "MIT" + }, + "node_modules/glsl-token-whitespace-trim": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/glsl-token-whitespace-trim/-/glsl-token-whitespace-trim-1.0.0.tgz", + "integrity": "sha512-ZJtsPut/aDaUdLUNtmBYhaCmhIjpKNg7IgZSfX5wFReMc2vnj8zok+gB/3Quqs0TsBSX/fGnqUUYZDqyuc2xLQ==", + "license": "MIT" + }, + "node_modules/glsl-tokenizer": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/glsl-tokenizer/-/glsl-tokenizer-2.1.5.tgz", + "integrity": "sha512-XSZEJ/i4dmz3Pmbnpsy3cKh7cotvFlBiZnDOwnj/05EwNp2XrhQ4XKJxT7/pDt4kp4YcpRSKz8eTV7S+mwV6MA==", + "license": "MIT", + "dependencies": { + "through2": "^0.6.3" + } + }, + "node_modules/glsl-tokenizer/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" + }, + "node_modules/glsl-tokenizer/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/glsl-tokenizer/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "license": "MIT" + }, + "node_modules/glsl-tokenizer/node_modules/through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==", + "license": "MIT", + "dependencies": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, + "node_modules/glslify": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glslify/-/glslify-7.1.1.tgz", + "integrity": "sha512-bud98CJ6kGZcP9Yxcsi7Iz647wuDz3oN+IZsjCRi5X1PI7t/xPKeL0mOwXJjo+CRZMqvq0CkSJiywCcY7kVYog==", + "license": "MIT", + "dependencies": { + "bl": "^2.2.1", + "concat-stream": "^1.5.2", + "duplexify": "^3.4.5", + "falafel": "^2.1.0", + "from2": "^2.3.0", + "glsl-resolve": "0.0.1", + "glsl-token-whitespace-trim": "^1.0.0", + "glslify-bundle": "^5.0.0", + "glslify-deps": "^1.2.5", + "minimist": "^1.2.5", + "resolve": "^1.1.5", + "stack-trace": "0.0.9", + "static-eval": "^2.0.5", + "through2": "^2.0.1", + "xtend": "^4.0.0" + }, + "bin": { + "glslify": "bin.js" + } + }, + "node_modules/glslify-bundle": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glslify-bundle/-/glslify-bundle-5.1.1.tgz", + "integrity": "sha512-plaAOQPv62M1r3OsWf2UbjN0hUYAB7Aph5bfH58VxJZJhloRNbxOL9tl/7H71K7OLJoSJ2ZqWOKk3ttQ6wy24A==", + "license": "MIT", + "dependencies": { + "glsl-inject-defines": "^1.0.1", + "glsl-token-defines": "^1.0.0", + "glsl-token-depth": "^1.1.1", + "glsl-token-descope": "^1.0.2", + "glsl-token-scope": "^1.1.1", + "glsl-token-string": "^1.0.1", + "glsl-token-whitespace-trim": "^1.0.0", + "glsl-tokenizer": "^2.0.2", + "murmurhash-js": "^1.0.0", + "shallow-copy": "0.0.1" + } + }, + "node_modules/glslify-deps": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/glslify-deps/-/glslify-deps-1.3.2.tgz", + "integrity": "sha512-7S7IkHWygJRjcawveXQjRXLO2FTjijPDYC7QfZyAQanY+yGLCFHYnPtsGT9bdyHiwPTw/5a1m1M9hamT2aBpag==", + "license": "ISC", + "dependencies": { + "@choojs/findup": "^0.2.0", + "events": "^3.2.0", + "glsl-resolve": "0.0.1", + "glsl-tokenizer": "^2.0.0", + "graceful-fs": "^4.1.2", + "inherits": "^2.0.1", + "map-limit": "0.0.1", + "resolve": "^1.0.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/grid-index": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grid-index/-/grid-index-1.1.0.tgz", + "integrity": "sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-hover": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-hover/-/has-hover-1.0.1.tgz", + "integrity": "sha512-0G6w7LnlcpyDzpeGUTuT0CEw05+QlMuGVk1IHNAlHrGJITGodjZu3x8BNDUMfKJSZXNB2ZAclqc1bvrd+uUpfg==", + "license": "MIT", + "dependencies": { + "is-browser": "^2.0.1" + } + }, + "node_modules/has-passive-events": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-passive-events/-/has-passive-events-1.0.0.tgz", + "integrity": "sha512-2vSj6IeIsgvsRMyeQ0JaCX5Q3lX4zMn5HpoVc7MEhQ6pv8Iq9rsXjsp+E5ZwaT7T0xhMT0KmU8gtt1EFVdbJiw==", + "license": "MIT", + "dependencies": { + "is-browser": "^2.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/is-browser": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-browser/-/is-browser-2.1.0.tgz", + "integrity": "sha512-F5rTJxDQ2sW81fcfOR1GnCXT6sVJC104fCyfj+mjpwNEwaPYSn5fte5jiHmBg3DHsIoL/l8Kvw5VN5SsTRcRFQ==", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-firefox": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-firefox/-/is-firefox-1.0.3.tgz", + "integrity": "sha512-6Q9ITjvWIm0Xdqv+5U12wgOKEM2KoBw4Y926m0OFkvlCxnbG94HKAsVz8w3fWcfAS5YA2fJORXX1dLrkprCCxA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-iexplorer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-iexplorer/-/is-iexplorer-1.0.0.tgz", + "integrity": "sha512-YeLzceuwg3K6O0MLM3UyUUjKAlyULetwryFp1mHy1I5PfArK0AEqlfa+MR4gkJjcbuJXoDJCvXbyqZVf5CR2Sg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-mobile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-4.0.0.tgz", + "integrity": "sha512-mlcHZA84t1qLSuWkt2v0I2l61PYdyQDt4aG1mLIXF5FDMm4+haBCxCPYSr/uwqQNRk1MiTizn0ypEuRAOLRAew==", + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-string-blank": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-string-blank/-/is-string-blank-1.0.1.tgz", + "integrity": "sha512-9H+ZBCVs3L9OYqv8nuUAzpcT9OTgMD1yAWrG7ihlnibdkbtB850heAmYWxHuXc4CHy4lKeK69tN+ny1K7gBIrw==", + "license": "MIT" + }, + "node_modules/is-svg-path": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-svg-path/-/is-svg-path-1.0.2.tgz", + "integrity": "sha512-Lj4vePmqpPR1ZnRctHv8ltSh1OrSxHkhUkd7wi+VQdcdP15/KvQFyk7LhNuM7ZW0EVbJz8kZLVmL9quLrfq4Kg==", + "license": "MIT" + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-pretty-compact": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==", + "license": "MIT" + }, + "node_modules/kdbush": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", + "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==", + "license": "ISC" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/map-limit": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/map-limit/-/map-limit-0.0.1.tgz", + "integrity": "sha512-pJpcfLPnIF/Sk3taPW21G/RQsEEirGaFpCW3oXRwH9dnFHPHNGjNyvh++rdmC2fNqEaTw2MhYJraoJWAHx8kEg==", + "license": "MIT", + "dependencies": { + "once": "~1.3.0" + } + }, + "node_modules/map-limit/node_modules/once": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/mapbox-gl": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-1.13.3.tgz", + "integrity": "sha512-p8lJFEiqmEQlyv+DQxFAOG/XPWN0Wp7j/Psq93Zywz7qt9CcUKFYDBOoOEKzqe6gudHVJY8/Bhqw6VDpX2lSBg==", + "license": "SEE LICENSE IN LICENSE.txt", + "peer": true, + "dependencies": { + "@mapbox/geojson-rewind": "^0.5.2", + "@mapbox/geojson-types": "^1.0.2", + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/mapbox-gl-supported": "^1.5.0", + "@mapbox/point-geometry": "^0.1.0", + "@mapbox/tiny-sdf": "^1.1.1", + "@mapbox/unitbezier": "^0.0.0", + "@mapbox/vector-tile": "^1.3.1", + "@mapbox/whoots-js": "^3.1.0", + "csscolorparser": "~1.0.3", + "earcut": "^2.2.2", + "geojson-vt": "^3.2.1", + "gl-matrix": "^3.2.1", + "grid-index": "^1.1.0", + "murmurhash-js": "^1.0.0", + "pbf": "^3.2.1", + "potpack": "^1.0.1", + "quickselect": "^2.0.0", + "rw": "^1.3.3", + "supercluster": "^7.1.0", + "tinyqueue": "^2.0.3", + "vt-pbf": "^3.1.1" + }, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/maplibre-gl": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.7.1.tgz", + "integrity": "sha512-lgL7XpIwsgICiL82ITplfS7IGwrB1OJIw/pCvprDp2dhmSSEBgmPzYRvwYYYvJGJD7fxUv1Tvpih4nZ6VrLuaA==", + "license": "BSD-3-Clause", + "dependencies": { + "@mapbox/geojson-rewind": "^0.5.2", + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/point-geometry": "^0.1.0", + "@mapbox/tiny-sdf": "^2.0.6", + "@mapbox/unitbezier": "^0.0.1", + "@mapbox/vector-tile": "^1.3.1", + "@mapbox/whoots-js": "^3.1.0", + "@maplibre/maplibre-gl-style-spec": "^20.3.1", + "@types/geojson": "^7946.0.14", + "@types/geojson-vt": "3.2.5", + "@types/mapbox__point-geometry": "^0.1.4", + "@types/mapbox__vector-tile": "^1.3.4", + "@types/pbf": "^3.0.5", + "@types/supercluster": "^7.1.3", + "earcut": "^3.0.0", + "geojson-vt": "^4.0.2", + "gl-matrix": "^3.4.3", + "global-prefix": "^4.0.0", + "kdbush": "^4.0.2", + "murmurhash-js": "^1.0.0", + "pbf": "^3.3.0", + "potpack": "^2.0.0", + "quickselect": "^3.0.0", + "supercluster": "^8.0.1", + "tinyqueue": "^3.0.0", + "vt-pbf": "^3.1.3" + }, + "engines": { + "node": ">=16.14.0", + "npm": ">=8.1.0" + }, + "funding": { + "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1" + } + }, + "node_modules/maplibre-gl/node_modules/@mapbox/tiny-sdf": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.7.tgz", + "integrity": "sha512-25gQLQMcpivjOSA40g3gO6qgiFPDpWRoMfd+G/GoppPIeP6JDaMMkMrEJnMZhKyyS6iKwVt5YKu02vCUyJM3Ug==", + "license": "BSD-2-Clause" + }, + "node_modules/maplibre-gl/node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", + "license": "BSD-2-Clause" + }, + "node_modules/maplibre-gl/node_modules/earcut": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.2.tgz", + "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==", + "license": "ISC" + }, + "node_modules/maplibre-gl/node_modules/geojson-vt": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz", + "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==", + "license": "ISC" + }, + "node_modules/maplibre-gl/node_modules/potpack": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.1.0.tgz", + "integrity": "sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ==", + "license": "ISC" + }, + "node_modules/maplibre-gl/node_modules/quickselect": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", + "license": "ISC" + }, + "node_modules/maplibre-gl/node_modules/supercluster": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", + "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", + "license": "ISC", + "dependencies": { + "kdbush": "^4.0.2" + } + }, + "node_modules/maplibre-gl/node_modules/tinyqueue": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", + "license": "ISC" + }, + "node_modules/math-log2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/math-log2/-/math-log2-1.0.1.tgz", + "integrity": "sha512-9W0yGtkaMAkf74XGYVy4Dqw3YUMnTNB2eeiw9aQbUl4A3KmuCEHTt2DgAB07ENzOYAjsYSAYufkAq0Zd+jU7zA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mouse-change": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/mouse-change/-/mouse-change-1.4.0.tgz", + "integrity": "sha512-vpN0s+zLL2ykyyUDh+fayu9Xkor5v/zRD9jhSqjRS1cJTGS0+oakVZzNm5n19JvvEj0you+MXlYTpNxUDQUjkQ==", + "license": "MIT", + "dependencies": { + "mouse-event": "^1.0.0" + } + }, + "node_modules/mouse-event": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/mouse-event/-/mouse-event-1.0.5.tgz", + "integrity": "sha512-ItUxtL2IkeSKSp9cyaX2JLUuKk2uMoxBg4bbOWVd29+CskYJR9BGsUqtXenNzKbnDshvupjUewDIYVrOB6NmGw==", + "license": "MIT" + }, + "node_modules/mouse-event-offset": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mouse-event-offset/-/mouse-event-offset-3.0.2.tgz", + "integrity": "sha512-s9sqOs5B1Ykox3Xo8b3Ss2IQju4UwlW6LSR+Q5FXWpprJ5fzMLefIIItr3PH8RwzfGy6gxs/4GAmiNuZScE25w==", + "license": "MIT" + }, + "node_modules/mouse-wheel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mouse-wheel/-/mouse-wheel-1.2.0.tgz", + "integrity": "sha512-+OfYBiUOCTWcTECES49neZwL5AoGkXE+lFjIvzwNCnYRlso+EnfvovcBxGoyQ0yQt806eSPjS675K0EwWknXmw==", + "license": "MIT", + "dependencies": { + "right-now": "^1.0.0", + "signum": "^1.0.0", + "to-px": "^1.0.1" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/murmurhash-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", + "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/native-promise-only": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/needle": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", + "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", + "license": "MIT", + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "license": "ISC" + }, + "node_modules/normalize-svg-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/normalize-svg-path/-/normalize-svg-path-0.1.0.tgz", + "integrity": "sha512-1/kmYej2iedi5+ROxkRESL/pI02pkg0OBnaR4hJkSIX6+ORzepwbuUXfrdZaPjysTsJInj0Rj5NuX027+dMBvA==", + "license": "MIT" + }, + "node_modules/number-is-integer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-integer/-/number-is-integer-1.0.1.tgz", + "integrity": "sha512-Dq3iuiFBkrbmuQjGFFF3zckXNCQoSD37/SdSbgcBailUx6knDvDwb5CympBgcoWHy36sfS12u74MHYkXyHq6bg==", + "license": "MIT", + "dependencies": { + "is-finite": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parenthesis": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/parenthesis/-/parenthesis-3.1.8.tgz", + "integrity": "sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw==", + "license": "MIT" + }, + "node_modules/parse-rect": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parse-rect/-/parse-rect-1.2.0.tgz", + "integrity": "sha512-4QZ6KYbnE6RTwg9E0HpLchUM9EZt6DnDxajFZZDSV4p/12ZJEvPO702DZpGvRYEPo00yKDys7jASi+/w7aO8LA==", + "license": "MIT", + "dependencies": { + "pick-by-alias": "^1.2.0" + } + }, + "node_modules/parse-svg-path": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", + "integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==", + "license": "MIT" + }, + "node_modules/parse-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-unit/-/parse-unit-1.0.1.tgz", + "integrity": "sha512-hrqldJHokR3Qj88EIlV/kAyAi/G5R2+R56TBANxNMy0uPlYcttx0jnMW6Yx5KsKPSbC3KddM/7qQm3+0wEXKxg==", + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/pbf": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", + "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "ieee754": "^1.1.12", + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "license": "MIT" + }, + "node_modules/pick-by-alias": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pick-by-alias/-/pick-by-alias-1.2.0.tgz", + "integrity": "sha512-ESj2+eBxhGrcA1azgHs7lARG5+5iLakc/6nlfbpjcLl00HuuUOIuORhYXN4D1HfvMSKuVtFQjAlnwi1JHEeDIw==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/plotly.js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plotly.js/-/plotly.js-3.1.0.tgz", + "integrity": "sha512-vx+CyzApL9tquFpwoPHOGSIWDbFPsA4om/tXZcnsygGUejXideDF9R5VwkltEIDG7Xuof45quVPyz1otv6Aqjw==", + "license": "MIT", + "dependencies": { + "@plotly/d3": "3.8.2", + "@plotly/d3-sankey": "0.7.2", + "@plotly/d3-sankey-circular": "0.33.1", + "@plotly/mapbox-gl": "1.13.4", + "@plotly/regl": "^2.1.2", + "@turf/area": "^7.1.0", + "@turf/bbox": "^7.1.0", + "@turf/centroid": "^7.1.0", + "base64-arraybuffer": "^1.0.2", + "canvas-fit": "^1.5.0", + "color-alpha": "1.0.4", + "color-normalize": "1.5.0", + "color-parse": "2.0.0", + "color-rgba": "3.0.0", + "country-regex": "^1.1.0", + "d3-force": "^1.2.1", + "d3-format": "^1.4.5", + "d3-geo": "^1.12.1", + "d3-geo-projection": "^2.9.0", + "d3-hierarchy": "^1.1.9", + "d3-interpolate": "^3.0.1", + "d3-time": "^1.1.0", + "d3-time-format": "^2.2.3", + "fast-isnumeric": "^1.1.4", + "gl-mat4": "^1.2.0", + "gl-text": "^1.4.0", + "has-hover": "^1.0.1", + "has-passive-events": "^1.0.0", + "is-mobile": "^4.0.0", + "maplibre-gl": "^4.7.1", + "mouse-change": "^1.4.0", + "mouse-event-offset": "^3.0.2", + "mouse-wheel": "^1.2.0", + "native-promise-only": "^0.8.1", + "parse-svg-path": "^0.1.2", + "point-in-polygon": "^1.1.0", + "polybooljs": "^1.2.2", + "probe-image-size": "^7.2.3", + "regl-error2d": "^2.0.12", + "regl-line2d": "^3.1.3", + "regl-scatter2d": "^3.3.1", + "regl-splom": "^1.0.14", + "strongly-connected-components": "^1.0.1", + "superscript-text": "^1.0.0", + "svg-path-sdf": "^1.1.3", + "tinycolor2": "^1.4.2", + "to-px": "1.0.1", + "topojson-client": "^3.1.0", + "webgl-context": "^2.2.0", + "world-calendars": "^1.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/point-in-polygon": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.1.0.tgz", + "integrity": "sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw==", + "license": "MIT" + }, + "node_modules/polybooljs": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/polybooljs/-/polybooljs-1.2.2.tgz", + "integrity": "sha512-ziHW/02J0XuNuUtmidBc6GXE8YohYydp3DWPWXYsd7O721TjcmN+k6ezjdwkDqep+gnWnFY+yqZHvzElra2oCg==", + "license": "MIT" + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/potpack": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", + "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", + "license": "ISC" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/probe-image-size": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-7.2.3.tgz", + "integrity": "sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==", + "license": "MIT", + "dependencies": { + "lodash.merge": "^4.6.2", + "needle": "^2.5.2", + "stream-parser": "~0.3.1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/protocol-buffers-schema": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", + "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quickselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==", + "license": "ISC" + }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "license": "MIT", + "dependencies": { + "performance-now": "^2.1.0" + } + }, + "node_modules/react": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", + "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", + "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.1" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-plotly.js": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-plotly.js/-/react-plotly.js-2.6.0.tgz", + "integrity": "sha512-g93xcyhAVCSt9kV1svqG1clAEdL6k3U+jjuSzfTV7owaSU9Go6Ph8bl25J+jKfKvIGAEYpe4qj++WHJuc9IaeA==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "plotly.js": ">1.34.0", + "react": ">0.13.0" + } + }, + "node_modules/react-use-websocket": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-4.13.0.tgz", + "integrity": "sha512-anMuVoV//g2N76Wxqvqjjo1X48r9Np3y1/gMl7arX84tAPXdy5R7sB5lO5hvCzQRYjqXwV8XMAiEBOUbyrZFrw==", + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/regl": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/regl/-/regl-2.1.1.tgz", + "integrity": "sha512-+IOGrxl3FZ8ZM9ixCWQZzFRiRn7Rzn9bu3iFHwg/yz4tlOUQgbO4PHLgG+1ZT60zcIV8tief6Qrmyl8qcoJP0g==", + "license": "MIT" + }, + "node_modules/regl-error2d": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/regl-error2d/-/regl-error2d-2.0.12.tgz", + "integrity": "sha512-r7BUprZoPO9AbyqM5qlJesrSRkl+hZnVKWKsVp7YhOl/3RIpi4UDGASGJY0puQ96u5fBYw/OlqV24IGcgJ0McA==", + "license": "MIT", + "dependencies": { + "array-bounds": "^1.0.1", + "color-normalize": "^1.5.0", + "flatten-vertex-data": "^1.0.2", + "object-assign": "^4.1.1", + "pick-by-alias": "^1.2.0", + "to-float32": "^1.1.0", + "update-diff": "^1.1.0" + } + }, + "node_modules/regl-line2d": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/regl-line2d/-/regl-line2d-3.1.3.tgz", + "integrity": "sha512-fkgzW+tTn4QUQLpFKsUIE0sgWdCmXAM3ctXcCgoGBZTSX5FE2A0M7aynz7nrZT5baaftLrk9te54B+MEq4QcSA==", + "license": "MIT", + "dependencies": { + "array-bounds": "^1.0.1", + "array-find-index": "^1.0.2", + "array-normalize": "^1.1.4", + "color-normalize": "^1.5.0", + "earcut": "^2.1.5", + "es6-weak-map": "^2.0.3", + "flatten-vertex-data": "^1.0.2", + "object-assign": "^4.1.1", + "parse-rect": "^1.2.0", + "pick-by-alias": "^1.2.0", + "to-float32": "^1.1.0" + } + }, + "node_modules/regl-scatter2d": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/regl-scatter2d/-/regl-scatter2d-3.3.1.tgz", + "integrity": "sha512-seOmMIVwaCwemSYz/y4WE0dbSO9svNFSqtTh5RE57I7PjGo3tcUYKtH0MTSoshcAsreoqN8HoCtnn8wfHXXfKQ==", + "license": "MIT", + "dependencies": { + "@plotly/point-cluster": "^3.1.9", + "array-range": "^1.0.1", + "array-rearrange": "^2.2.2", + "clamp": "^1.0.1", + "color-id": "^1.1.0", + "color-normalize": "^1.5.0", + "color-rgba": "^2.1.1", + "flatten-vertex-data": "^1.0.2", + "glslify": "^7.0.0", + "is-iexplorer": "^1.0.0", + "object-assign": "^4.1.1", + "parse-rect": "^1.2.0", + "pick-by-alias": "^1.2.0", + "to-float32": "^1.1.0", + "update-diff": "^1.1.0" + } + }, + "node_modules/regl-scatter2d/node_modules/color-parse": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-1.4.3.tgz", + "integrity": "sha512-BADfVl/FHkQkyo8sRBwMYBqemqsgnu7JZAwUgvBvuwwuNUZAhSvLTbsEErS5bQXzOjDR0dWzJ4vXN2Q+QoPx0A==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0" + } + }, + "node_modules/regl-scatter2d/node_modules/color-rgba": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/color-rgba/-/color-rgba-2.4.0.tgz", + "integrity": "sha512-Nti4qbzr/z2LbUWySr7H9dk3Rl7gZt7ihHAxlgT4Ho90EXWkjtkL1avTleu9yeGuqrt/chxTB6GKK8nZZ6V0+Q==", + "license": "MIT", + "dependencies": { + "color-parse": "^1.4.2", + "color-space": "^2.0.0" + } + }, + "node_modules/regl-splom": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/regl-splom/-/regl-splom-1.0.14.tgz", + "integrity": "sha512-OiLqjmPRYbd7kDlHC6/zDf6L8lxgDC65BhC8JirhP4ykrK4x22ZyS+BnY8EUinXKDeMgmpRwCvUmk7BK4Nweuw==", + "license": "MIT", + "dependencies": { + "array-bounds": "^1.0.1", + "array-range": "^1.0.1", + "color-alpha": "^1.0.4", + "flatten-vertex-data": "^1.0.2", + "parse-rect": "^1.2.0", + "pick-by-alias": "^1.2.0", + "raf": "^3.4.1", + "regl-scatter2d": "^3.2.3" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-protobuf-schema": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", + "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "license": "MIT", + "dependencies": { + "protocol-buffers-schema": "^3.3.1" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/right-now": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/right-now/-/right-now-1.0.0.tgz", + "integrity": "sha512-DA8+YS+sMIVpbsuKgy+Z67L9Lxb1p05mNxRpDPNksPDEFir4vmBlUtuN9jkTGn9YMMdlBuK7XQgFiz6ws+yhSg==", + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.47.1.tgz", + "integrity": "sha512-iasGAQoZ5dWDzULEUX3jiW0oB1qyFOepSyDyoU6S/OhVlDIwj5knI5QBa5RRQ0sK7OE0v+8VIi2JuV+G+3tfNg==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.47.1", + "@rollup/rollup-android-arm64": "4.47.1", + "@rollup/rollup-darwin-arm64": "4.47.1", + "@rollup/rollup-darwin-x64": "4.47.1", + "@rollup/rollup-freebsd-arm64": "4.47.1", + "@rollup/rollup-freebsd-x64": "4.47.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.47.1", + "@rollup/rollup-linux-arm-musleabihf": "4.47.1", + "@rollup/rollup-linux-arm64-gnu": "4.47.1", + "@rollup/rollup-linux-arm64-musl": "4.47.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.47.1", + "@rollup/rollup-linux-ppc64-gnu": "4.47.1", + "@rollup/rollup-linux-riscv64-gnu": "4.47.1", + "@rollup/rollup-linux-riscv64-musl": "4.47.1", + "@rollup/rollup-linux-s390x-gnu": "4.47.1", + "@rollup/rollup-linux-x64-gnu": "4.47.1", + "@rollup/rollup-linux-x64-musl": "4.47.1", + "@rollup/rollup-win32-arm64-msvc": "4.47.1", + "@rollup/rollup-win32-ia32-msvc": "4.47.1", + "@rollup/rollup-win32-x64-msvc": "4.47.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shallow-copy": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", + "integrity": "sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signum": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/signum/-/signum-1.0.0.tgz", + "integrity": "sha512-yodFGwcyt59XRh7w5W3jPcIQb3Bwi21suEfT7MAWnBX3iCdklJpgDgvGT9o04UonglZN5SNMfJFkHIR/jO8GHw==", + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", + "integrity": "sha512-vjUc6sfgtgY0dxCdnc40mK6Oftjo9+2K8H/NG81TMhgL392FtiPA9tn9RLyTxXmTLPJPjF3VyzFp6bsWFLisMQ==", + "engines": { + "node": "*" + } + }, + "node_modules/static-eval": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.1.tgz", + "integrity": "sha512-MgWpQ/ZjGieSVB3eOJVs4OA2LT/q1vx98KPCTTQPzq/aLr0YUXTsgryTXr4SLfR0ZfUUCiedM9n/ABeDIyy4mA==", + "license": "MIT", + "dependencies": { + "escodegen": "^2.1.0" + } + }, + "node_modules/stream-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", + "integrity": "sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==", + "license": "MIT", + "dependencies": { + "debug": "2" + } + }, + "node_modules/stream-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/stream-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/string-split-by": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string-split-by/-/string-split-by-1.0.0.tgz", + "integrity": "sha512-KaJKY+hfpzNyet/emP81PJA9hTVSfxNLS9SFTWxdCnnW1/zOOwiV248+EfoX7IQFcBaOp4G5YE6xTJMF+pLg6A==", + "license": "MIT", + "dependencies": { + "parenthesis": "^3.1.5" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strongly-connected-components": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strongly-connected-components/-/strongly-connected-components-1.0.1.tgz", + "integrity": "sha512-i0TFx4wPcO0FwX+4RkLJi1MxmcTv90jNZgxMu9XRnMXMeFUY1VJlIoXpZunPUvUUqbCT1pg5PEkFqqpcaElNaA==", + "license": "MIT" + }, + "node_modules/supercluster": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-7.1.5.tgz", + "integrity": "sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==", + "license": "ISC", + "dependencies": { + "kdbush": "^3.0.0" + } + }, + "node_modules/supercluster/node_modules/kdbush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-3.0.0.tgz", + "integrity": "sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==", + "license": "ISC" + }, + "node_modules/superscript-text": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/superscript-text/-/superscript-text-1.0.0.tgz", + "integrity": "sha512-gwu8l5MtRZ6koO0icVTlmN5pm7Dhh1+Xpe9O4x6ObMAsW+3jPbW14d1DsBq1F4wiI+WOFjXF35pslgec/G8yCQ==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-arc-to-cubic-bezier": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz", + "integrity": "sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==", + "license": "ISC" + }, + "node_modules/svg-path-bounds": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/svg-path-bounds/-/svg-path-bounds-1.0.2.tgz", + "integrity": "sha512-H4/uAgLWrppIC0kHsb2/dWUYSmb4GE5UqH06uqWBcg6LBjX2fu0A8+JrO2/FJPZiSsNOKZAhyFFgsLTdYUvSqQ==", + "license": "MIT", + "dependencies": { + "abs-svg-path": "^0.1.1", + "is-svg-path": "^1.0.1", + "normalize-svg-path": "^1.0.0", + "parse-svg-path": "^0.1.2" + } + }, + "node_modules/svg-path-bounds/node_modules/normalize-svg-path": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/normalize-svg-path/-/normalize-svg-path-1.1.0.tgz", + "integrity": "sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==", + "license": "MIT", + "dependencies": { + "svg-arc-to-cubic-bezier": "^3.0.0" + } + }, + "node_modules/svg-path-sdf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/svg-path-sdf/-/svg-path-sdf-1.1.3.tgz", + "integrity": "sha512-vJJjVq/R5lSr2KLfVXVAStktfcfa1pNFjFOgyJnzZFXlO/fDZ5DmM8FpnSKKzLPfEYTVeXuVBTHF296TpxuJVg==", + "license": "MIT", + "dependencies": { + "bitmap-sdf": "^1.0.0", + "draw-svg-path": "^1.0.0", + "is-svg-path": "^1.0.1", + "parse-svg-path": "^0.1.2", + "svg-path-bounds": "^1.0.1" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.12.tgz", + "integrity": "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinyqueue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", + "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==", + "license": "ISC" + }, + "node_modules/to-float32": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/to-float32/-/to-float32-1.1.0.tgz", + "integrity": "sha512-keDnAusn/vc+R3iEiSDw8TOF7gPiTLdK1ArvWtYbJQiVfmRg6i/CAvbKq3uIS0vWroAC7ZecN3DjQKw3aSklUg==", + "license": "MIT" + }, + "node_modules/to-px": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-px/-/to-px-1.0.1.tgz", + "integrity": "sha512-2y3LjBeIZYL19e5gczp14/uRWFDtDUErJPVN3VU9a7SJO+RjGRtYR47aMN2bZgGlxvW4ZcEz2ddUPVHXcMfuXw==", + "license": "MIT", + "dependencies": { + "parse-unit": "^1.0.1" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/topojson-client": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz", + "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==", + "license": "ISC", + "dependencies": { + "commander": "2" + }, + "bin": { + "topo2geo": "bin/topo2geo", + "topomerge": "bin/topomerge", + "topoquantize": "bin/topoquantize" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", + "license": "ISC" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typedarray-pool": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/typedarray-pool/-/typedarray-pool-1.2.0.tgz", + "integrity": "sha512-YTSQbzX43yvtpfRtIDAYygoYtgT+Rpjuxy9iOpczrjpXLgGoyG7aS5USJXV2d3nn8uHTeb9rXDvzS27zUg5KYQ==", + "license": "MIT", + "dependencies": { + "bit-twiddle": "^1.0.0", + "dup": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.40.0.tgz", + "integrity": "sha512-Xvd2l+ZmFDPEt4oj1QEXzA4A2uUK6opvKu3eGN9aGjB8au02lIVcLyi375w94hHyejTOmzIU77L8ol2sRg9n7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.40.0", + "@typescript-eslint/parser": "8.40.0", + "@typescript-eslint/typescript-estree": "8.40.0", + "@typescript-eslint/utils": "8.40.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==", + "license": "MIT" + }, + "node_modules/update-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-diff/-/update-diff-1.1.0.tgz", + "integrity": "sha512-rCiBPiHxZwT4+sBhEbChzpO5hYHjm91kScWgdHf4Qeafs6Ba7MBl+d9GlGv72bcTZQO0sLmtQS1pHSWoCLtN/A==", + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/vite": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.3.tgz", + "integrity": "sha512-OOUi5zjkDxYrKhTV3V7iKsoS37VUM7v40+HuwEmcrsf11Cdx9y3DIr2Px6liIcZFwt3XSRpQvFpL3WVy7ApkGw==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.14" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vt-pbf": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", + "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", + "license": "MIT", + "dependencies": { + "@mapbox/point-geometry": "0.1.0", + "@mapbox/vector-tile": "^1.3.1", + "pbf": "^3.2.1" + } + }, + "node_modules/weak-map": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.8.tgz", + "integrity": "sha512-lNR9aAefbGPpHO7AEnY0hCFjz1eTkWCXYvkTRrTHs9qv8zJp+SkVYpzfLIFXQQiG3tVvbNFQgVg2bQS8YGgxyw==", + "license": "Apache-2.0" + }, + "node_modules/webgl-context": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/webgl-context/-/webgl-context-2.2.0.tgz", + "integrity": "sha512-q/fGIivtqTT7PEoF07axFIlHNk/XCPaYpq64btnepopSWvKNFkoORlQYgqDigBIuGA1ExnFd/GnSUnBNEPQY7Q==", + "license": "MIT", + "dependencies": { + "get-canvas-context": "^1.0.1" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/world-calendars": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/world-calendars/-/world-calendars-1.0.4.tgz", + "integrity": "sha512-VGRnLJS+xJmGDPodgJRnGIDwGu0s+Cr9V2HB3EzlDZ5n0qb8h5SJtGUEkjrphZYAglEiXZ6kiXdmk0H/h/uu/w==", + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/wulpus-frontend/package.json b/wulpus-frontend/package.json new file mode 100644 index 0000000..c14bb5b --- /dev/null +++ b/wulpus-frontend/package.json @@ -0,0 +1,36 @@ +{ + "name": "wulpus-frontend", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@tailwindcss/vite": "^4.1.12", + "plotly.js": "^3.1.0", + "react": "^19.1.1", + "react-dom": "^19.1.1", + "react-plotly.js": "^2.6.0", + "react-use-websocket": "^4.13.0", + "tailwindcss": "^4.1.12" + }, + "devDependencies": { + "@eslint/js": "^9.33.0", + "@types/plotly.js": "^3.0.3", + "@types/react": "^19.1.10", + "@types/react-dom": "^19.1.7", + "@types/react-plotly.js": "^2.6.3", + "@vitejs/plugin-react-swc": "^4.0.0", + "eslint": "^9.33.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.39.1", + "vite": "^7.1.2" + } +} diff --git a/wulpus-frontend/public/vite.svg b/wulpus-frontend/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/wulpus-frontend/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wulpus-frontend/src/App.tsx b/wulpus-frontend/src/App.tsx new file mode 100644 index 0000000..b3f942a --- /dev/null +++ b/wulpus-frontend/src/App.tsx @@ -0,0 +1,250 @@ +import { useEffect, useMemo, useState } from 'react' +import useWebSocket from 'react-use-websocket'; +import type { DataFrame, Status, UsConfig, TxRxConfig, WulpusConfig } from './websocket-types'; +import Plot from 'react-plotly.js'; +// import Plotly types if needed in future +import { getConnections, postConnect, postStart } from './api'; + +function App() { + + const wsUrl = `${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${window.location.host}/ws`; + const { lastJsonMessage, readyState } = useWebSocket(wsUrl, { + shouldReconnect: () => true, + }); + + const [status, setStatus] = useState(null); + + const [dataFrame, setDataFrame] = useState(null); + const [connections, setConnections] = useState([]); + const [selectedPort, setSelectedPort] = useState(""); + + // WulpusConfig state + const [txRxConfigs, setTxRxConfigs] = useState([{ config_id: 0, tx_channels: [0], rx_channels: [0], optimized_switching: true }]); + const [usConfig, setUsConfig] = useState({ + num_acqs: 100, + dcdc_turnon: 195300, + meas_period: 321965, + trans_freq: 2250000, + pulse_freq: 2250000, + num_pulses: 2, + sampling_freq: 8000000, + num_samples: 400, + rx_gain: 21.5, + num_txrx_configs: 1, + tx_configs: [0], + rx_configs: [0], + start_hvmuxrx: 500, + start_ppg: 500, + turnon_adc: 5, + start_pgainbias: 5, + start_adcsampl: 503, + restart_capt: 3000, + capt_timeout: 3000, + }); + + const effectiveConfig: WulpusConfig = useMemo(() => ({ + tx_rx_config: txRxConfigs, + us_config: { + ...usConfig, num_txrx_configs: txRxConfigs.length, + // ensure tx/rx bitmasks lists align in length + tx_configs: txRxConfigs.map((c) => c.config_id), + rx_configs: txRxConfigs.map((c) => c.config_id), + }, + }), [txRxConfigs, usConfig]); + + useEffect(() => { + if (lastJsonMessage) { + if ('status' in lastJsonMessage) { + setStatus(lastJsonMessage); + // If backend provides config, sync UI (non-destructive) + if (lastJsonMessage.us_config) { + setUsConfig(lastJsonMessage.us_config); + } + if (lastJsonMessage.tx_rx_config && Array.isArray(lastJsonMessage.tx_rx_config)) { + setTxRxConfigs(lastJsonMessage.tx_rx_config); + } + } + else if (Array.isArray(lastJsonMessage)) { + setDataFrame(lastJsonMessage); + } + } + }, [lastJsonMessage, setStatus, setDataFrame]); + + useEffect(() => { + // load available connections once + getConnections().then(setConnections).catch(() => setConnections([])); + }, []); + + function updateTxRx(idx: number, field: K, value: TxRxConfig[K]) { + setTxRxConfigs((prev) => prev.map((c, i) => i === idx ? { ...c, [field]: value } : c)); + } + + function addTxRx() { + setTxRxConfigs((prev) => [...prev, { config_id: prev.length, tx_channels: [], rx_channels: [], optimized_switching: true }]); + } + + function removeTxRx(idx: number) { + setTxRxConfigs((prev) => prev.filter((_, i) => i !== idx).map((c, i) => ({ ...c, config_id: i }))); + } + + async function handleConnect() { + if (!selectedPort) return; + await postConnect(selectedPort); + } + + async function handleStart() { + await postStart(effectiveConfig); + } + + return ( +
+ +
+ +
+
+

Connection

+
+ +
+ + +
+
+
+ Status: {status ? StatusLabel(status.status) : 'N/A'} · BT: {status?.bluetooth ?? '—'} · Progress: {Math.round((status?.progress ?? 0) * 100)}% +
+
+ +
+

US Config

+
+ setUsConfig(s => ({ ...s, num_acqs: v }))} /> + setUsConfig(s => ({ ...s, num_samples: v }))} /> + setUsConfig(s => ({ ...s, meas_period: v }))} /> + setUsConfig(s => ({ ...s, dcdc_turnon: v }))} /> + setUsConfig(s => ({ ...s, trans_freq: v }))} /> + setUsConfig(s => ({ ...s, pulse_freq: v }))} /> + setUsConfig(s => ({ ...s, num_pulses: v }))} /> + setUsConfig(s => ({ ...s, sampling_freq: Number(v) as UsConfig['sampling_freq'] }))} options={[8000000, 4000000, 2000000, 1000000, 500000].map(v => ({ value: String(v), label: String(v / 1000000) + "MHz" }))} /> + setUsConfig(s => ({ ...s, rx_gain: v }))} /> + setUsConfig(s => ({ ...s, start_hvmuxrx: v }))} /> + setUsConfig(s => ({ ...s, start_ppg: v }))} /> + setUsConfig(s => ({ ...s, turnon_adc: v }))} /> + setUsConfig(s => ({ ...s, start_pgainbias: v }))} /> + setUsConfig(s => ({ ...s, start_adcsampl: v }))} /> + setUsConfig(s => ({ ...s, restart_capt: v }))} /> + setUsConfig(s => ({ ...s, capt_timeout: v }))} /> +
+
+
+ +
+
+

TX/RX Configurations

+
+ {txRxConfigs.map((cfg, idx) => ( +
+
+
Config #{cfg.config_id}
+ +
+
+ updateTxRx(idx, 'config_id', v)} min={0} /> + updateTxRx(idx, 'tx_channels', vals)} /> + updateTxRx(idx, 'rx_channels', vals)} /> +
+ updateTxRx(idx, 'optimized_switching', e.target.checked)} /> + +
+
+
+ ))} + +
+
+ +
+

Live Signal

+
+ index) ?? [], + y: dataFrame?.map((value) => value) ?? [], + type: 'scatter', + mode: 'lines', + marker: { color: 'red' }, + }, + ]} + style={{ width: "100%", height: "100%" }} + layout={{ + autosize: true, uirevision: "fixed", + showlegend: false, + margin: { t: 10, r: 10, b: 30, l: 40 }, + }} + /> +
+
+
+
+
+ ) +} + +export default App + +// UI helpers +function NumberField({ label, value, onChange, step = 1, min }: { label: string; value: number; onChange: (v: number) => void; step?: number; min?: number }) { + return ( + + ); +} + +function SelectField({ label, value, onChange, options }: { label: string; value: string | number; onChange: (v: string) => void; options: { value: string; label: string }[] }) { + return ( + + ); +} + +function MultiNumField({ label, values, onChange }: { label: string; values: number[]; onChange: (vals: number[]) => void }) { + const [text, setText] = useState(values.join(',')); + useEffect(() => { setText(values.join(',')); }, [values]); + return ( + + ); +} + +function StatusLabel(s?: number) { + switch (s) { + case 0: return 'NOT_CONNECTED'; + case 1: return 'CONNECTING'; + case 2: return 'READY'; + case 3: return 'RUNNING'; + case 9: return 'ERROR'; + default: return String(s ?? '—'); + } +} diff --git a/wulpus-frontend/src/api.ts b/wulpus-frontend/src/api.ts new file mode 100644 index 0000000..487cfdc --- /dev/null +++ b/wulpus-frontend/src/api.ts @@ -0,0 +1,47 @@ +// Simple API client for the FastAPI backend + +export type ConnectResponse = { ok: string } | { [key: string]: string }; + +// Use Vite proxy in dev to avoid CORS; see vite.config.ts +const BASE_URL = "/api"; + +export async function getConnections(): Promise { + const res = await fetch(`${BASE_URL}/connections`); + if (!res.ok) throw new Error(`GET /connections failed: ${res.status}`); + const data = await res.json(); + // Backend might return list of strings or objects; normalize to strings + if (Array.isArray(data)) { + return data.map((item) => { + if (typeof item === "string") return item; + // Try common fields from serial.tools.list_ports + if (item && typeof item === "object") { + const obj = item as Record; + const device = typeof obj.device === "string" ? obj.device : undefined; + const name = typeof obj.name === "string" ? obj.name : undefined; + const desc = typeof obj.description === "string" ? obj.description : undefined; + return device || name || desc || JSON.stringify(item); + } + return String(item); + }); + } + return []; +} + +export async function postConnect(com_port: string): Promise { + const res = await fetch(`${BASE_URL}/connect`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ com_port }), + }); + if (!res.ok) throw new Error(`POST /connect failed: ${res.status}`); +} + +export async function postStart(config: unknown): Promise { + const res = await fetch(`${BASE_URL}/start`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(config), + }); + if (!res.ok) throw new Error(`POST /start failed: ${res.status}`); + return res.json(); +} diff --git a/wulpus-frontend/src/assets/react.svg b/wulpus-frontend/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/wulpus-frontend/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wulpus-frontend/src/index.css b/wulpus-frontend/src/index.css new file mode 100644 index 0000000..a461c50 --- /dev/null +++ b/wulpus-frontend/src/index.css @@ -0,0 +1 @@ +@import "tailwindcss"; \ No newline at end of file diff --git a/wulpus-frontend/src/main.tsx b/wulpus-frontend/src/main.tsx new file mode 100644 index 0000000..bef5202 --- /dev/null +++ b/wulpus-frontend/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.tsx' + +createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/wulpus-frontend/src/vite-env.d.ts b/wulpus-frontend/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/wulpus-frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/wulpus-frontend/src/websocket-types.ts b/wulpus-frontend/src/websocket-types.ts new file mode 100644 index 0000000..a53213f --- /dev/null +++ b/wulpus-frontend/src/websocket-types.ts @@ -0,0 +1,45 @@ +// Types mirrored from backend pydantic models + +export type UsConfig = { + num_acqs: number; + dcdc_turnon: number; + meas_period: number; + trans_freq: number; + pulse_freq: number; + num_pulses: number; + sampling_freq: 8000000 | 4000000 | 2000000 | 1000000 | 500000; + num_samples: number; + rx_gain: number; // constrained to predefined values on backend + num_txrx_configs: number; + tx_configs: number[]; + rx_configs: number[]; + start_hvmuxrx: number; + start_ppg: number; + turnon_adc: number; + start_pgainbias: number; + start_adcsampl: number; + restart_capt: number; + capt_timeout: number; +}; + +export type TxRxConfig = { + config_id: number; + tx_channels: number[]; + rx_channels: number[]; + optimized_switching: boolean; +}; + +export type WulpusConfig = { + tx_rx_config: TxRxConfig[]; + us_config: UsConfig; +}; + +export type Status = { + status: number; // 0.., maps to backend Status enum + bluetooth: string; + us_config: UsConfig | null; + tx_rx_config: TxRxConfig[] | null; + progress: number; // 0..1 +}; + +export type DataFrame = number[]; \ No newline at end of file diff --git a/wulpus-frontend/tsconfig.app.json b/wulpus-frontend/tsconfig.app.json new file mode 100644 index 0000000..227a6c6 --- /dev/null +++ b/wulpus-frontend/tsconfig.app.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/wulpus-frontend/tsconfig.json b/wulpus-frontend/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/wulpus-frontend/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/wulpus-frontend/tsconfig.node.json b/wulpus-frontend/tsconfig.node.json new file mode 100644 index 0000000..f85a399 --- /dev/null +++ b/wulpus-frontend/tsconfig.node.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/wulpus-frontend/vite.config.ts b/wulpus-frontend/vite.config.ts new file mode 100644 index 0000000..3ef46fc --- /dev/null +++ b/wulpus-frontend/vite.config.ts @@ -0,0 +1,22 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' +import tailwindcss from '@tailwindcss/vite' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], + server: { + proxy: { + "/api": { + target: "http://localhost:8000", + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api/, ""), + }, + "/ws": { + target: "ws://localhost:8000", + ws: true, + changeOrigin: true, + }, + }, + }, +}) From 7f069024d1365619084bf73e8a616fe810fdc734 Mon Sep 17 00:00:00 2001 From: Louis Date: Fri, 22 Aug 2025 14:36:54 -0700 Subject: [PATCH 12/51] Implement disconnect functionality and update API methods for Bluetooth connections --- wulpus-frontend/src/App.tsx | 235 ++++++++++++++++++++++++++---------- wulpus-frontend/src/api.ts | 10 +- wulpus/main.py | 5 + wulpus/wulpus.py | 4 + 4 files changed, 191 insertions(+), 63 deletions(-) diff --git a/wulpus-frontend/src/App.tsx b/wulpus-frontend/src/App.tsx index b3f942a..03c35df 100644 --- a/wulpus-frontend/src/App.tsx +++ b/wulpus-frontend/src/App.tsx @@ -1,14 +1,13 @@ -import { useEffect, useMemo, useState } from 'react' +import { useEffect, useMemo, useRef, useState } from 'react' import useWebSocket from 'react-use-websocket'; import type { DataFrame, Status, UsConfig, TxRxConfig, WulpusConfig } from './websocket-types'; import Plot from 'react-plotly.js'; -// import Plotly types if needed in future -import { getConnections, postConnect, postStart } from './api'; +import { getBTHConnections, postConnect, postDisconnect, postStart } from './api'; function App() { const wsUrl = `${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${window.location.host}/ws`; - const { lastJsonMessage, readyState } = useWebSocket(wsUrl, { + const { lastJsonMessage } = useWebSocket(wsUrl, { shouldReconnect: () => true, }); @@ -21,7 +20,7 @@ function App() { // WulpusConfig state const [txRxConfigs, setTxRxConfigs] = useState([{ config_id: 0, tx_channels: [0], rx_channels: [0], optimized_switching: true }]); const [usConfig, setUsConfig] = useState({ - num_acqs: 100, + num_acqs: 400, dcdc_turnon: 195300, meas_period: 321965, trans_freq: 2250000, @@ -29,7 +28,7 @@ function App() { num_pulses: 2, sampling_freq: 8000000, num_samples: 400, - rx_gain: 21.5, + rx_gain: 3.5, num_txrx_configs: 1, tx_configs: [0], rx_configs: [0], @@ -56,13 +55,6 @@ function App() { if (lastJsonMessage) { if ('status' in lastJsonMessage) { setStatus(lastJsonMessage); - // If backend provides config, sync UI (non-destructive) - if (lastJsonMessage.us_config) { - setUsConfig(lastJsonMessage.us_config); - } - if (lastJsonMessage.tx_rx_config && Array.isArray(lastJsonMessage.tx_rx_config)) { - setTxRxConfigs(lastJsonMessage.tx_rx_config); - } } else if (Array.isArray(lastJsonMessage)) { setDataFrame(lastJsonMessage); @@ -71,10 +63,24 @@ function App() { }, [lastJsonMessage, setStatus, setDataFrame]); useEffect(() => { - // load available connections once - getConnections().then(setConnections).catch(() => setConnections([])); + getBTHConnections() + .then((list) => setConnections(list)) + .catch(() => setConnections([])) }, []); + async function refreshConnections() { + try { + const list = await getBTHConnections(); + setConnections(list); + // if previously selected port is gone, clear selection + if (selectedPort && !list.includes(selectedPort)) { + setSelectedPort(""); + } + } catch (e) { + setConnections([]); + } + } + function updateTxRx(idx: number, field: K, value: TxRxConfig[K]) { setTxRxConfigs((prev) => prev.map((c, i) => i === idx ? { ...c, [field]: value } : c)); } @@ -105,21 +111,48 @@ function App() {

Connection

- +
+ + +
- - + )} + {status?.status !== 0 && ( + + )} +
- Status: {status ? StatusLabel(status.status) : 'N/A'} · BT: {status?.bluetooth ?? '—'} · Progress: {Math.round((status?.progress ?? 0) * 100)}% + Status: {status ? StatusLabel(status.status) : 'No Server/Backend'} · BT: {status?.bluetooth ?? '—'} · Progress: {Math.round((status?.progress ?? 0) * 100)}%
@@ -132,9 +165,22 @@ function App() { setUsConfig(s => ({ ...s, dcdc_turnon: v }))} /> setUsConfig(s => ({ ...s, trans_freq: v }))} /> setUsConfig(s => ({ ...s, pulse_freq: v }))} /> - setUsConfig(s => ({ ...s, num_pulses: v }))} /> - setUsConfig(s => ({ ...s, sampling_freq: Number(v) as UsConfig['sampling_freq'] }))} options={[8000000, 4000000, 2000000, 1000000, 500000].map(v => ({ value: String(v), label: String(v / 1000000) + "MHz" }))} /> - setUsConfig(s => ({ ...s, rx_gain: v }))} /> + setUsConfig(s => ({ ...s, num_pulses: v }))} /> + setUsConfig(s => ({ ...s, sampling_freq: Number(v) as UsConfig['sampling_freq'] }))} + options={[8000000, 4000000, 2000000, 1000000, 500000].map(v => ({ value: String(v), label: String(v / 1000000) + "MHz" }))} + /> + setUsConfig(s => ({ ...s, rx_gain: parseFloat(v) }))} + options={[-6.5, -5.5, -4.6, -4.1, -3.3, -2.3, -1.4, -0.8, + 0.1, 1.0, 1.9, 2.6, 3.5, 4.4, 5.2, 6.0, 6.8, 7.7, + 8.7, 9.0, 9.8, 10.7, 11.7, 12.2, 13, 13.9, 14.9, + 15.5, 16.3, 17.2, 18.2, 18.8, 19.6, 20.5, 21.5, + 22, 22.8, 23.6, 24.6, 25.0, 25.8, 26.7, 27.7, + 28.1, 28.9, 29.8, 30.8].map(v => ({ value: String(v), label: String(v) }))} + /> setUsConfig(s => ({ ...s, start_hvmuxrx: v }))} /> setUsConfig(s => ({ ...s, start_ppg: v }))} /> setUsConfig(s => ({ ...s, turnon_adc: v }))} /> @@ -146,32 +192,9 @@ function App() { -
-
-

TX/RX Configurations

-
- {txRxConfigs.map((cfg, idx) => ( -
-
-
Config #{cfg.config_id}
- -
-
- updateTxRx(idx, 'config_id', v)} min={0} /> - updateTxRx(idx, 'tx_channels', vals)} /> - updateTxRx(idx, 'rx_channels', vals)} /> -
- updateTxRx(idx, 'optimized_switching', e.target.checked)} /> - -
-
-
- ))} - -
-
+
+
-

Live Signal

value) ?? [], type: 'scatter', mode: 'lines', - marker: { color: 'red' }, + marker: { color: 'blue' }, }, ]} style={{ width: "100%", height: "100%" }} @@ -193,7 +216,49 @@ function App() { />
-
+ +
+

TX/RX Configurations

+
+ {txRxConfigs.map((cfg, idx) => ( +
+
+
Config #{cfg.config_id}
+ +
+
+ updateTxRx(idx, 'tx_channels', vals)} + showChannelBoxes={true} + color="bg-green-500" /> + updateTxRx(idx, 'rx_channels', vals)} + showChannelBoxes={true} + color="bg-blue-500" /> +
+ updateTxRx(idx, 'optimized_switching', e.target.checked)} + /> + +
+
+
+ ))} + +
+
+ + + ) @@ -223,17 +288,63 @@ function SelectField({ label, value, onChange, options }: { label: string; value ); } -function MultiNumField({ label, values, onChange }: { label: string; values: number[]; onChange: (vals: number[]) => void }) { +function MultiNumField({ label, values, onChange, showChannelBoxes = false, color = 'bg-green-500' }: { + label: string; + values: number[]; + onChange: (vals: number[]) => void; + showChannelBoxes?: boolean; + color?: string; +}) { const [text, setText] = useState(values.join(',')); - useEffect(() => { setText(values.join(',')); }, [values]); + const inputRef = useRef(null); + + // Only overwrite the text when the input is not focused. This prevents + // removing a trailing comma while the user is typing (which made "," disappear). + useEffect(() => { + try { + const active = typeof document !== 'undefined' ? document.activeElement : null; + if (inputRef.current && active === inputRef.current) { + // user is editing — don't clobber their input + return; + } + } catch (e) { + // ignore (e.g., SSR) + } + setText(values.join(',')); + }, [values]); + + function toggleChannel(ch: number) { + const exists = values.includes(ch); + const next = exists ? values.filter(v => v !== ch) : [...values, ch].sort((a, b) => a - b); + onChange(next); + } return ( ); } diff --git a/wulpus-frontend/src/api.ts b/wulpus-frontend/src/api.ts index 487cfdc..e8c4f64 100644 --- a/wulpus-frontend/src/api.ts +++ b/wulpus-frontend/src/api.ts @@ -5,7 +5,7 @@ export type ConnectResponse = { ok: string } | { [key: string]: string }; // Use Vite proxy in dev to avoid CORS; see vite.config.ts const BASE_URL = "/api"; -export async function getConnections(): Promise { +export async function getBTHConnections(): Promise { const res = await fetch(`${BASE_URL}/connections`); if (!res.ok) throw new Error(`GET /connections failed: ${res.status}`); const data = await res.json(); @@ -36,6 +36,14 @@ export async function postConnect(com_port: string): Promise { if (!res.ok) throw new Error(`POST /connect failed: ${res.status}`); } +export async function postDisconnect(): Promise { + const res = await fetch(`${BASE_URL}/disconnect`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + }); + if (!res.ok) throw new Error(`POST /disconnect failed: ${res.status}`); +} + export async function postStart(config: unknown): Promise { const res = await fetch(`${BASE_URL}/start`, { method: "POST", diff --git a/wulpus/main.py b/wulpus/main.py index 003fae5..9cde820 100644 --- a/wulpus/main.py +++ b/wulpus/main.py @@ -40,6 +40,11 @@ def connect(conf: ComPort): wulpus.connect(conf.com_port) +@app.post("/disconnect") +def disconnect(): + wulpus.disconnect() + + @app.websocket("/ws") async def websocket_endpoint(websocket: WebSocket): global global_send_data_task diff --git a/wulpus/wulpus.py b/wulpus/wulpus.py index 4e472a4..c9da809 100644 --- a/wulpus/wulpus.py +++ b/wulpus/wulpus.py @@ -53,6 +53,10 @@ def connect(self, device_name: str = ''): else: self._status = Status.NOT_CONNECTED + def disconnect(self): + self._dongle.close() + self._status = Status.NOT_CONNECTED + def get_status(self): return {"status": self._status, "bluetooth": self._dongle.get_status(), From e51805cd6dc0a71bcabed58a3d6915bdfb203b0d Mon Sep 17 00:00:00 2001 From: Louis Date: Mon, 25 Aug 2025 11:26:12 -0700 Subject: [PATCH 13/51] Fix bug in bluetooth-connection (string wrong interpreted) + Add stop-button + Add fullscreen-mode for graph --- wulpus-frontend/package-lock.json | 7 + wulpus-frontend/package.json | 1 + wulpus-frontend/src/App.tsx | 272 +++++++++--------- wulpus-frontend/src/Fields.tsx | 20 ++ wulpus-frontend/src/MultiNumField.tsx | 62 ++++ wulpus-frontend/src/api.ts | 39 ++- ...24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg | 1 + wulpus-frontend/src/helper.ts | 91 ++++++ wulpus-frontend/src/index.css | 11 +- wulpus/dongle_mock.py | 2 +- wulpus/main.py | 6 + wulpus/wulpus.py | 18 +- wulpus/wulpus_config_models.py | 3 +- 13 files changed, 384 insertions(+), 149 deletions(-) create mode 100644 wulpus-frontend/src/Fields.tsx create mode 100644 wulpus-frontend/src/MultiNumField.tsx create mode 100644 wulpus-frontend/src/assets/icons/fullscreen_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg create mode 100644 wulpus-frontend/src/helper.ts diff --git a/wulpus-frontend/package-lock.json b/wulpus-frontend/package-lock.json index 7c77879..4f5c44e 100644 --- a/wulpus-frontend/package-lock.json +++ b/wulpus-frontend/package-lock.json @@ -8,6 +8,7 @@ "name": "wulpus-frontend", "version": "0.0.0", "dependencies": { + "@material-symbols/font-400": "^0.34.1", "@tailwindcss/vite": "^4.1.12", "plotly.js": "^3.1.0", "react": "^19.1.1", @@ -841,6 +842,12 @@ "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", "license": "ISC" }, + "node_modules/@material-symbols/font-400": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@material-symbols/font-400/-/font-400-0.34.1.tgz", + "integrity": "sha512-0z4VVcupP3Y0XAOs+xHCy9EsGKGTk8lD0p+9zx5kwdppKwFeq84dj0GNtT5uCRqZOPZ2zgYgXHJzuKQ0q1iIXw==", + "license": "Apache-2.0" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", diff --git a/wulpus-frontend/package.json b/wulpus-frontend/package.json index c14bb5b..225d4b3 100644 --- a/wulpus-frontend/package.json +++ b/wulpus-frontend/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "@material-symbols/font-400": "^0.34.1", "@tailwindcss/vite": "^4.1.12", "plotly.js": "^3.1.0", "react": "^19.1.1", diff --git a/wulpus-frontend/src/App.tsx b/wulpus-frontend/src/App.tsx index 03c35df..b9775b9 100644 --- a/wulpus-frontend/src/App.tsx +++ b/wulpus-frontend/src/App.tsx @@ -2,7 +2,11 @@ import { useEffect, useMemo, useRef, useState } from 'react' import useWebSocket from 'react-use-websocket'; import type { DataFrame, Status, UsConfig, TxRxConfig, WulpusConfig } from './websocket-types'; import Plot from 'react-plotly.js'; -import { getBTHConnections, postConnect, postDisconnect, postStart } from './api'; +import type Plotly from 'plotly.js'; +import { getBTHConnections, postConnect, postDisconnect, postStart, postStop, StatusLabel } from './api'; +import { MultiNumField } from './MultiNumField'; +import { NumberField, SelectField } from './Fields'; +import { bandpassFIR, hilbertEnvelope } from './helper'; function App() { @@ -11,11 +15,19 @@ function App() { shouldReconnect: () => true, }); - const [status, setStatus] = useState(null); + const [connections, setConnections] = useState([]); + const [selectedPort, setSelectedPort] = useState(""); + const [status, setStatus] = useState(null); const [dataFrame, setDataFrame] = useState(null); - const [connections, setConnections] = useState([]); - const [selectedPort, setSelectedPort] = useState(""); + + + const bmodeBufferSize = 8; // keep a small ring buffer of recent frames for b-mode (8 rows) + const [showBMode, setShowBMode] = useState(false); + const [bmodeBuffer, setBmodeBuffer] = useState(() => []); + // fullscreen graph support + const plotContainerRef = useRef(null); + const [isFullscreen, setIsFullscreen] = useState(false); // WulpusConfig state const [txRxConfigs, setTxRxConfigs] = useState([{ config_id: 0, tx_channels: [0], rx_channels: [0], optimized_switching: true }]); @@ -58,6 +70,12 @@ function App() { } else if (Array.isArray(lastJsonMessage)) { setDataFrame(lastJsonMessage); + // push into bmode buffer + setBmodeBuffer((prev) => { + const next = [...prev, lastJsonMessage.slice()]; + if (next.length > bmodeBufferSize) next.shift(); + return next; + }); } } }, [lastJsonMessage, setStatus, setDataFrame]); @@ -68,12 +86,42 @@ function App() { .catch(() => setConnections([])) }, []); + // track fullscreen changes + useEffect(() => { + const onFsChange = () => setIsFullscreen(Boolean(document.fullscreenElement)); + document.addEventListener('fullscreenchange', onFsChange); + return () => document.removeEventListener('fullscreenchange', onFsChange); + }, []); + + async function toggleFullscreen() { + const el = plotContainerRef.current; + if (!el) return; + if (!document.fullscreenElement) { + const elWithVendors = el as HTMLElement & { + webkitRequestFullscreen?: () => Promise | void; + msRequestFullscreen?: () => Promise | void; + }; + if (elWithVendors.requestFullscreen) await elWithVendors.requestFullscreen(); + else if (elWithVendors.webkitRequestFullscreen) await elWithVendors.webkitRequestFullscreen(); + else if (elWithVendors.msRequestFullscreen) await elWithVendors.msRequestFullscreen(); + } else { + const docWithVendors = document as Document & { + webkitExitFullscreen?: () => Promise | void; + msExitFullscreen?: () => Promise | void; + }; + if (document.exitFullscreen) await document.exitFullscreen(); + else if (docWithVendors.webkitExitFullscreen) await docWithVendors.webkitExitFullscreen(); + else if (docWithVendors.msExitFullscreen) await docWithVendors.msExitFullscreen(); + } + } + async function refreshConnections() { try { const list = await getBTHConnections(); setConnections(list); + const justPosts: string[] = list.map(item => item[1]); // if previously selected port is gone, clear selection - if (selectedPort && !list.includes(selectedPort)) { + if (selectedPort && !justPosts.includes(selectedPort)) { setSelectedPort(""); } } catch (e) { @@ -94,6 +142,7 @@ function App() { } async function handleConnect() { + console.log("Connecting to port:", selectedPort); if (!selectedPort) return; await postConnect(selectedPort); } @@ -102,6 +151,12 @@ function App() { await postStart(effectiveConfig); } + // compute filter/envelope just-in-time before rendering + const lowCutHz = usConfig.sampling_freq / 2 * 0.1; + const highCutHz = usConfig.sampling_freq / 2 * 0.9; + const filteredFrame = dataFrame ? bandpassFIR(dataFrame, usConfig.sampling_freq, lowCutHz, highCutHz, 31) : []; + const envelopeFrame = filteredFrame.length ? hilbertEnvelope(filteredFrame, 101) : []; + return (
@@ -110,15 +165,15 @@ function App() {

Connection

-
-
- setSelectedPort(e.target.value)}> {connections.map((c) => ( - + ))} @@ -140,15 +195,29 @@ function App() { {status?.status !== 0 && ( )} - + className={`w-full bg-green-600 hover:bg-green-700 text-white rounded px-3 py-2 ${status?.status != 2 ? 'opacity-50' : ''}`} + disabled={status?.status != 2} + > + Start + + )} + {status?.status === 3 && ( + + )}
@@ -193,27 +262,66 @@ function App() {
-
+

Live Signal

- index) ?? [], - y: dataFrame?.map((value) => value) ?? [], - type: 'scatter', - mode: 'lines', - marker: { color: 'blue' }, - }, - ]} - style={{ width: "100%", height: "100%" }} - layout={{ - autosize: true, uirevision: "fixed", - showlegend: false, - margin: { t: 10, r: 10, b: 30, l: 40 }, - }} - /> + {showBMode ? ( + + ) : ( + i) : [], + y: dataFrame ?? [], + type: 'scatter', mode: 'lines', name: 'Raw', line: { color: 'blue' }, + }, + { + x: dataFrame ? dataFrame.map((_, i) => i) : [], + y: filteredFrame.length ? filteredFrame : [], + type: 'scatter', mode: 'lines', name: 'Filter', line: { color: 'green' }, + visible: 'legendonly', + }, + { + x: dataFrame ? dataFrame.map((_, i) => i) : [], + y: envelopeFrame.length ? envelopeFrame : [], + type: 'scatter', mode: 'lines', name: 'Envelope', line: { color: 'red' }, + visible: 'legendonly', + }, + ]) as unknown as Plotly.Data[]} + useResizeHandler + style={{ width: "100%", height: "100%" }} + layout={{ + autosize: true, uirevision: "fixed", + showlegend: true, + legend: { orientation: 'h', }, + margin: { t: 10, r: 10, b: 30, l: 40 }, + }} + /> + )} +
+
+ +
@@ -253,7 +361,9 @@ function App() {
))} - + {txRxConfigs.length < 8 && ( + + )}
@@ -264,98 +374,4 @@ function App() { ) } -export default App - -// UI helpers -function NumberField({ label, value, onChange, step = 1, min }: { label: string; value: number; onChange: (v: number) => void; step?: number; min?: number }) { - return ( - - ); -} - -function SelectField({ label, value, onChange, options }: { label: string; value: string | number; onChange: (v: string) => void; options: { value: string; label: string }[] }) { - return ( - - ); -} - -function MultiNumField({ label, values, onChange, showChannelBoxes = false, color = 'bg-green-500' }: { - label: string; - values: number[]; - onChange: (vals: number[]) => void; - showChannelBoxes?: boolean; - color?: string; -}) { - const [text, setText] = useState(values.join(',')); - const inputRef = useRef(null); - - // Only overwrite the text when the input is not focused. This prevents - // removing a trailing comma while the user is typing (which made "," disappear). - useEffect(() => { - try { - const active = typeof document !== 'undefined' ? document.activeElement : null; - if (inputRef.current && active === inputRef.current) { - // user is editing — don't clobber their input - return; - } - } catch (e) { - // ignore (e.g., SSR) - } - setText(values.join(',')); - }, [values]); - - function toggleChannel(ch: number) { - const exists = values.includes(ch); - const next = exists ? values.filter(v => v !== ch) : [...values, ch].sort((a, b) => a - b); - onChange(next); - } - return ( - - ); -} - -function StatusLabel(s?: number) { - switch (s) { - case 0: return 'NOT_CONNECTED'; - case 1: return 'CONNECTING'; - case 2: return 'READY'; - case 3: return 'RUNNING'; - case 9: return 'ERROR'; - default: return String(s ?? '—'); - } -} +export default App \ No newline at end of file diff --git a/wulpus-frontend/src/Fields.tsx b/wulpus-frontend/src/Fields.tsx new file mode 100644 index 0000000..158cb9e --- /dev/null +++ b/wulpus-frontend/src/Fields.tsx @@ -0,0 +1,20 @@ +// UI helpers +export function NumberField({ label, value, onChange, step = 1, min }: { label: string; value: number; onChange: (v: number) => void; step?: number; min?: number; }) { + return ( + + ); +} +export function SelectField({ label, value, onChange, options }: { label: string; value: string | number; onChange: (v: string) => void; options: { value: string; label: string; }[]; }) { + return ( + + ); +} diff --git a/wulpus-frontend/src/MultiNumField.tsx b/wulpus-frontend/src/MultiNumField.tsx new file mode 100644 index 0000000..631c92b --- /dev/null +++ b/wulpus-frontend/src/MultiNumField.tsx @@ -0,0 +1,62 @@ +import { useEffect, useRef, useState } from 'react'; + +export function MultiNumField({ label, values, onChange, showChannelBoxes = false, color = 'bg-green-500' }: { + label: string; + values: number[]; + onChange: (vals: number[]) => void; + showChannelBoxes?: boolean; + color?: string; +}) { + const [text, setText] = useState(values.join(',')); + const inputRef = useRef(null); + + // Only overwrite the text when the input is not focused. This prevents + // removing a trailing comma while the user is typing (which made "," disappear). + useEffect(() => { + try { + const active = typeof document !== 'undefined' ? document.activeElement : null; + if (inputRef.current && active === inputRef.current) { + // user is editing — don't clobber their input + return; + } + } catch (e) { + // ignore (e.g., SSR) + } + setText(values.join(',')); + }, [values]); + + function toggleChannel(ch: number) { + const exists = values.includes(ch); + const next = exists ? values.filter(v => v !== ch) : [...values, ch].sort((a, b) => a - b); + onChange(next); + } + return ( + + ); +} diff --git a/wulpus-frontend/src/api.ts b/wulpus-frontend/src/api.ts index e8c4f64..6927237 100644 --- a/wulpus-frontend/src/api.ts +++ b/wulpus-frontend/src/api.ts @@ -5,24 +5,17 @@ export type ConnectResponse = { ok: string } | { [key: string]: string }; // Use Vite proxy in dev to avoid CORS; see vite.config.ts const BASE_URL = "/api"; -export async function getBTHConnections(): Promise { +export async function getBTHConnections(): Promise { const res = await fetch(`${BASE_URL}/connections`); if (!res.ok) throw new Error(`GET /connections failed: ${res.status}`); - const data = await res.json(); + const data = await res.json() as { [key: string]: string }[] // Backend might return list of strings or objects; normalize to strings if (Array.isArray(data)) { return data.map((item) => { - if (typeof item === "string") return item; - // Try common fields from serial.tools.list_ports - if (item && typeof item === "object") { - const obj = item as Record; - const device = typeof obj.device === "string" ? obj.device : undefined; - const name = typeof obj.name === "string" ? obj.name : undefined; - const desc = typeof obj.description === "string" ? obj.description : undefined; - return device || name || desc || JSON.stringify(item); - } - return String(item); - }); + // get key of object: + const key = Object.keys(item)[0]; + return [key, item[key]]; + }) } return []; } @@ -53,3 +46,23 @@ export async function postStart(config: unknown): Promise { if (!res.ok) throw new Error(`POST /start failed: ${res.status}`); return res.json(); } + +export async function postStop(): Promise { + const res = await fetch(`${BASE_URL}/stop`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + }); + if (!res.ok) throw new Error(`POST /stop failed: ${res.status}`); + return res.json(); +} + +export function StatusLabel(s?: number) { + switch (s) { + case 0: return 'NOT_CONNECTED'; + case 1: return 'CONNECTING'; + case 2: return 'READY'; + case 3: return 'RUNNING'; + case 9: return 'ERROR'; + default: return String(s ?? '—'); + } +} \ No newline at end of file diff --git a/wulpus-frontend/src/assets/icons/fullscreen_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg b/wulpus-frontend/src/assets/icons/fullscreen_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg new file mode 100644 index 0000000..e4aa7d0 --- /dev/null +++ b/wulpus-frontend/src/assets/icons/fullscreen_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wulpus-frontend/src/helper.ts b/wulpus-frontend/src/helper.ts new file mode 100644 index 0000000..6c0ba59 --- /dev/null +++ b/wulpus-frontend/src/helper.ts @@ -0,0 +1,91 @@ + + +// Helper DSP utilities +function sinc(x: number) { + if (x === 0) return 1; + const pix = Math.PI * x; + return Math.sin(pix) / pix; +} + +function hammingWindow(n: number) { + // return array length n + const out = new Array(n); + for (let i = 0; i < n; i++) { + out[i] = 0.54 - 0.46 * Math.cos((2 * Math.PI * i) / (n - 1)); + } + return out; +} + +export function bandpassFIR(data: number[], fs: number, lowHz: number, highHz: number, nTaps = 101) { + // design windowed-sinc bandpass (linear-phase FIR) + if (nTaps % 2 === 0) nTaps += 1; // make odd + const mid = (nTaps - 1) / 2; + const low = lowHz / fs; // normalized (0..0.5) + const high = highHz / fs; + const win = hammingWindow(nTaps); + const h: number[] = new Array(nTaps); + for (let n = 0; n <= (nTaps - 1); n++) { + const k = n - mid; + // ideal bandpass = high * sinc(2*high*k) - low * sinc(2*low*k) + h[n] = 2 * high * sinc(2 * high * k) - 2 * low * sinc(2 * low * k); + h[n] *= win[n]; + } + // apply forward-backward filtering to approximate filtfilt (zero-phase) + const tmp = new Array(data.length).fill(0); + for (let i = 0; i < data.length; i++) { + let acc = 0; + for (let k = 0; k < nTaps; k++) { + const idx = i - (nTaps - 1 - k); + if (idx >= 0 && idx < data.length) acc += h[k] * data[idx]; + } + tmp[i] = acc; + } + + // reverse, filter again, then reverse to get zero-phase effect + const revIn = tmp.slice().reverse(); + const tmp2 = new Array(data.length).fill(0); + for (let i = 0; i < revIn.length; i++) { + let acc = 0; + for (let k = 0; k < nTaps; k++) { + const idx = i - (nTaps - 1 - k); + if (idx >= 0 && idx < revIn.length) acc += h[k] * revIn[idx]; + } + tmp2[i] = acc; + } + return tmp2.reverse(); +} + +export function hilbertEnvelope(data: number[], nTaps = 101) { + // approximate analytic signal via FIR Hilbert transformer + if (nTaps % 2 === 0) nTaps += 1; // ensure odd + const mid = (nTaps - 1) / 2; + const win = hammingWindow(nTaps); + const h: number[] = new Array(nTaps).fill(0); + for (let n = 0; n < nTaps; n++) { + const k = n - mid; + if (k === 0) { + h[n] = 0; + } else if (k % 2 === 0) { + h[n] = 0; + } else { + h[n] = 2 / (Math.PI * k); + } + h[n] *= win[n]; + } + // compute imaginary part (convolution) + const imag = new Array(data.length).fill(0); + for (let i = 0; i < data.length; i++) { + let acc = 0; + for (let k = 0; k < nTaps; k++) { + const idx = i - (nTaps - 1 - k); + if (idx >= 0 && idx < data.length) acc += h[k] * data[idx]; + } + imag[i] = acc; + } + // envelope sqrt(real^2 + imag^2) + const out = new Array(data.length); + for (let i = 0; i < data.length; i++) { + out[i] = Math.sqrt(data[i] * data[i] + imag[i] * imag[i]); + } + return out; +} diff --git a/wulpus-frontend/src/index.css b/wulpus-frontend/src/index.css index a461c50..eb334d5 100644 --- a/wulpus-frontend/src/index.css +++ b/wulpus-frontend/src/index.css @@ -1 +1,10 @@ -@import "tailwindcss"; \ No newline at end of file +@import "tailwindcss"; +@import '@material-symbols/font-400'; + +@layer base { + + button:not([disabled]), + [role="button"]:not([disabled]) { + cursor: pointer; + } +} \ No newline at end of file diff --git a/wulpus/dongle_mock.py b/wulpus/dongle_mock.py index f4c1944..d4f69cc 100644 --- a/wulpus/dongle_mock.py +++ b/wulpus/dongle_mock.py @@ -71,7 +71,7 @@ def receive_data(self): """ Mock: Return random data with the same structure as the original. """ - time.sleep(0.1) # Simulate some delay + time.sleep(0.2) # Simulate some delay rf_arr = np.random.randint( 1, 1001, size=ACQ_LENGTH_SAMPLES, dtype=" Date: Mon, 25 Aug 2025 15:25:29 -0700 Subject: [PATCH 14/51] Add recording-functionality --- wulpus-frontend/src/App.tsx | 8 ++++---- wulpus/wulpus.py | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/wulpus-frontend/src/App.tsx b/wulpus-frontend/src/App.tsx index b9775b9..adaff30 100644 --- a/wulpus-frontend/src/App.tsx +++ b/wulpus-frontend/src/App.tsx @@ -33,17 +33,17 @@ function App() { const [txRxConfigs, setTxRxConfigs] = useState([{ config_id: 0, tx_channels: [0], rx_channels: [0], optimized_switching: true }]); const [usConfig, setUsConfig] = useState({ num_acqs: 400, - dcdc_turnon: 195300, + dcdc_turnon: 100, meas_period: 321965, trans_freq: 2250000, pulse_freq: 2250000, - num_pulses: 2, + num_pulses: 1, sampling_freq: 8000000, num_samples: 400, rx_gain: 3.5, num_txrx_configs: 1, tx_configs: [0], - rx_configs: [0], + rx_configs: [1], start_hvmuxrx: 500, start_ppg: 500, turnon_adc: 5, @@ -203,7 +203,7 @@ function App() { {status?.status !== 3 && ( - -
- {status?.status === 0 && ( - - )} - {status?.status !== 0 && ( - - )} - - {status?.status !== 3 && ( - - )} - {status?.status === 3 && ( - - )} -
- -
- Status: {status ? StatusLabel(status.status) : 'No Server/Backend'} · BT: {status?.bluetooth ?? '—'} · Progress: {Math.round((status?.progress ?? 0) * 100)}% -
+
+
+
+
-
-

US Config

-
- setUsConfig(s => ({ ...s, num_acqs: v }))} /> - setUsConfig(s => ({ ...s, num_samples: v }))} /> - setUsConfig(s => ({ ...s, meas_period: v }))} /> - setUsConfig(s => ({ ...s, dcdc_turnon: v }))} /> - setUsConfig(s => ({ ...s, trans_freq: v }))} /> - setUsConfig(s => ({ ...s, pulse_freq: v }))} /> - setUsConfig(s => ({ ...s, num_pulses: v }))} /> - setUsConfig(s => ({ ...s, sampling_freq: Number(v) as UsConfig['sampling_freq'] }))} - options={[8000000, 4000000, 2000000, 1000000, 500000].map(v => ({ value: String(v), label: String(v / 1000000) + "MHz" }))} - /> - setUsConfig(s => ({ ...s, rx_gain: parseFloat(v) }))} - options={[-6.5, -5.5, -4.6, -4.1, -3.3, -2.3, -1.4, -0.8, - 0.1, 1.0, 1.9, 2.6, 3.5, 4.4, 5.2, 6.0, 6.8, 7.7, - 8.7, 9.0, 9.8, 10.7, 11.7, 12.2, 13, 13.9, 14.9, - 15.5, 16.3, 17.2, 18.2, 18.8, 19.6, 20.5, 21.5, - 22, 22.8, 23.6, 24.6, 25.0, 25.8, 26.7, 27.7, - 28.1, 28.9, 29.8, 30.8].map(v => ({ value: String(v), label: String(v) }))} - /> - setUsConfig(s => ({ ...s, start_hvmuxrx: v }))} /> - setUsConfig(s => ({ ...s, start_ppg: v }))} /> - setUsConfig(s => ({ ...s, turnon_adc: v }))} /> - setUsConfig(s => ({ ...s, start_pgainbias: v }))} /> - setUsConfig(s => ({ ...s, start_adcsampl: v }))} /> - setUsConfig(s => ({ ...s, restart_capt: v }))} /> - setUsConfig(s => ({ ...s, capt_timeout: v }))} /> -
+
+
-
- -

Live Signal

-
- {showBMode ? ( - - ) : ( - i) : [], - y: dataFrame ?? [], - type: 'scatter', mode: 'lines', name: 'Raw', line: { color: 'blue' }, - }, - { - x: dataFrame ? dataFrame.map((_, i) => i) : [], - y: filteredFrame.length ? filteredFrame : [], - type: 'scatter', mode: 'lines', name: 'Filter', line: { color: 'green' }, - visible: 'legendonly', - }, - { - x: dataFrame ? dataFrame.map((_, i) => i) : [], - y: envelopeFrame.length ? envelopeFrame : [], - type: 'scatter', mode: 'lines', name: 'Envelope', line: { color: 'red' }, - visible: 'legendonly', - }, - ]) as unknown as Plotly.Data[]} - useResizeHandler - style={{ width: "100%", height: "100%" }} - layout={{ - autosize: true, uirevision: "fixed", - showlegend: true, - legend: { orientation: 'h', }, - margin: { t: 10, r: 10, b: 30, l: 40 }, - }} - /> - )} -
-
- - -
+
+
-
-

TX/RX Configurations

-
- {txRxConfigs.map((cfg, idx) => ( -
-
-
Config #{cfg.config_id}
- -
-
- updateTxRx(idx, 'tx_channels', vals)} - showChannelBoxes={true} - color="bg-green-500" /> - updateTxRx(idx, 'rx_channels', vals)} - showChannelBoxes={true} - color="bg-blue-500" /> -
- updateTxRx(idx, 'optimized_switching', e.target.checked)} - /> - -
-
-
- ))} - {txRxConfigs.length < 8 && ( - - )} -
+
+
- -
) diff --git a/wulpus-frontend/src/ConnectionPanel.tsx b/wulpus-frontend/src/ConnectionPanel.tsx new file mode 100644 index 0000000..3859b62 --- /dev/null +++ b/wulpus-frontend/src/ConnectionPanel.tsx @@ -0,0 +1,104 @@ +import { useEffect, useState } from "react"; +import { getBTHConnections, postConnect, postDisconnect, postStart, postStop, StatusLabel } from "./api"; +import type { Status, WulpusConfig } from "./websocket-types"; + +export function ConnectionPanel(props: { effectiveConfig: WulpusConfig, status: Status | null }) { + const { effectiveConfig, status } = props; + const [connections, setConnections] = useState([]); + const [selectedPort, setSelectedPort] = useState(""); + + async function refreshConnections() { + try { + const list = await getBTHConnections(); + setConnections(list); + const justPosts: string[] = list.map(item => item[1]); + // if previously selected port is gone, clear selection + if (selectedPort && !justPosts.includes(selectedPort)) { + setSelectedPort(""); + } + } catch (e) { + setConnections([]); + } + } + + + useEffect(() => { + getBTHConnections() + .then((list) => setConnections(list)) + .catch(() => setConnections([])) + }, []); + + async function handleConnect() { + console.log("Connecting to port:", selectedPort); + if (!selectedPort) return; + await postConnect(selectedPort); + } + + async function handleStart() { + await postStart(effectiveConfig); + } + + return ( +
+

Connection

+
+
+ + +
+
+ {status?.status === 0 && ( + + )} + {status?.status !== 0 && ( + + )} + + {status?.status !== 3 && ( + + )} + {status?.status === 3 && ( + + )} +
+
+
+ Status: {status ? StatusLabel(status.status) : 'No Server/Backend'} · BT: {status?.bluetooth ?? '—'} · Progress: {Math.round((status?.progress ?? 0) * 100)}% +
+
+ ) +} \ No newline at end of file diff --git a/wulpus-frontend/src/Graph.tsx b/wulpus-frontend/src/Graph.tsx new file mode 100644 index 0000000..f2e98a3 --- /dev/null +++ b/wulpus-frontend/src/Graph.tsx @@ -0,0 +1,92 @@ +import type Plotly from 'plotly.js'; +import { useEffect, useRef, useState } from "react"; +import Plot from 'react-plotly.js'; +import { bandpassFIR, hilbertEnvelope, toggleFullscreen } from './helper'; +import type { DataFrame, UsConfig } from './websocket-types'; + +export function Graph(props: { dataFrame: DataFrame | null, bmodeBuffer: number[][], usConfig: UsConfig }) { + const { dataFrame, bmodeBuffer, usConfig } = props; + + const plotContainerRef = useRef(null); + const [showBMode, setShowBMode] = useState(false); + + // fullscreen graph support + const [isFullscreen, setIsFullscreen] = useState(false); + + // track fullscreen changes + useEffect(() => { + const onFsChange = () => setIsFullscreen(Boolean(document.fullscreenElement)); + document.addEventListener('fullscreenchange', onFsChange); + return () => document.removeEventListener('fullscreenchange', onFsChange); + }, []); + + // compute filter/envelope just-in-time before rendering + const lowCutHz = usConfig.sampling_freq / 2 * 0.1; + const highCutHz = usConfig.sampling_freq / 2 * 0.9; + const filteredFrame = dataFrame ? bandpassFIR(dataFrame, usConfig.sampling_freq, lowCutHz, highCutHz, 31) : []; + const envelopeFrame = filteredFrame.length ? hilbertEnvelope(filteredFrame, 101) : []; + + + return ( +
+

Live Signal

+
+ {showBMode ? ( + + ) : ( + i) : [], + y: dataFrame ?? [], + type: 'scatter', mode: 'lines', name: 'Raw', line: { color: 'blue' }, + }, + { + x: dataFrame ? dataFrame.map((_, i) => i) : [], + y: filteredFrame.length ? filteredFrame : [], + type: 'scatter', mode: 'lines', name: 'Filter', line: { color: 'green' }, + visible: 'legendonly', + }, + { + x: dataFrame ? dataFrame.map((_, i) => i) : [], + y: envelopeFrame.length ? envelopeFrame : [], + type: 'scatter', mode: 'lines', name: 'Envelope', line: { color: 'red' }, + visible: 'legendonly', + }, + ]) as unknown as Plotly.Data[]} + useResizeHandler + style={{ width: "100%", height: "100%" }} + layout={{ + autosize: true, uirevision: "fixed", + showlegend: true, + legend: { orientation: 'h', }, + margin: { t: 10, r: 10, b: 30, l: 40 }, + }} + /> + )} +
+
+ + +
+
) +} \ No newline at end of file diff --git a/wulpus-frontend/src/TxRxConfig.tsx b/wulpus-frontend/src/TxRxConfig.tsx new file mode 100644 index 0000000..144aa66 --- /dev/null +++ b/wulpus-frontend/src/TxRxConfig.tsx @@ -0,0 +1,63 @@ +import { MultiNumField } from "./MultiNumField"; +import type { TxRxConfig } from './websocket-types'; + +export function TxRxConfigPanel(props: { txRxConfigs: TxRxConfig[], setTxRxConfigs: React.Dispatch> }) { + const { txRxConfigs, setTxRxConfigs } = props; + + function updateTxRx(idx: number, field: K, value: TxRxConfig[K]) { + setTxRxConfigs((prev) => prev.map((c, i) => i === idx ? { ...c, [field]: value } : c)); + } + + function addTxRx() { + setTxRxConfigs((prev) => [...prev, { config_id: prev.length, tx_channels: [], rx_channels: [], optimized_switching: true }]); + } + + function removeTxRx(idx: number) { + setTxRxConfigs((prev) => prev.filter((_, i) => i !== idx).map((c, i) => ({ ...c, config_id: i }))); + } + + + return ( +
+

TX/RX Configurations

+
+ {txRxConfigs.map((cfg, idx) => ( +
+
+
Config #{cfg.config_id}
+ +
+
+ updateTxRx(idx, 'tx_channels', vals)} + showChannelBoxes={true} + color="bg-green-500" /> + updateTxRx(idx, 'rx_channels', vals)} + showChannelBoxes={true} + color="bg-blue-500" /> +
+ updateTxRx(idx, 'optimized_switching', e.target.checked)} + /> + +
+
+
+ ))} + {txRxConfigs.length < 8 && ( + + )} +
+
+ ) +} \ No newline at end of file diff --git a/wulpus-frontend/src/UsConfig.tsx b/wulpus-frontend/src/UsConfig.tsx new file mode 100644 index 0000000..2ad686e --- /dev/null +++ b/wulpus-frontend/src/UsConfig.tsx @@ -0,0 +1,42 @@ +import { NumberField, SelectField } from "./Fields" +import type { UsConfig } from './websocket-types'; + +export function USConfigPanel(props: { usConfig: UsConfig, setUsConfig: React.Dispatch> }) { + const { usConfig, setUsConfig } = props; + return ( +
+

US Config

+
+ setUsConfig(s => ({ ...s, num_acqs: v }))} /> + setUsConfig(s => ({ ...s, num_samples: v }))} /> + setUsConfig(s => ({ ...s, meas_period: v }))} /> + setUsConfig(s => ({ ...s, dcdc_turnon: v }))} /> + setUsConfig(s => ({ ...s, trans_freq: v }))} /> + setUsConfig(s => ({ ...s, pulse_freq: v }))} /> + setUsConfig(s => ({ ...s, num_pulses: v }))} /> + setUsConfig(s => ({ ...s, sampling_freq: Number(v) as UsConfig['sampling_freq'] }))} + options={[8000000, 4000000, 2000000, 1000000, 500000].map(v => ({ value: String(v), label: String(v / 1000000) + "MHz" }))} + /> + setUsConfig(s => ({ ...s, rx_gain: parseFloat(v) }))} + options={[-6.5, -5.5, -4.6, -4.1, -3.3, -2.3, -1.4, -0.8, + 0.1, 1.0, 1.9, 2.6, 3.5, 4.4, 5.2, 6.0, 6.8, 7.7, + 8.7, 9.0, 9.8, 10.7, 11.7, 12.2, 13, 13.9, 14.9, + 15.5, 16.3, 17.2, 18.2, 18.8, 19.6, 20.5, 21.5, + 22, 22.8, 23.6, 24.6, 25.0, 25.8, 26.7, 27.7, + 28.1, 28.9, 29.8, 30.8].map(v => ({ value: String(v), label: String(v) }))} + /> + setUsConfig(s => ({ ...s, start_hvmuxrx: v }))} /> + setUsConfig(s => ({ ...s, start_ppg: v }))} /> + setUsConfig(s => ({ ...s, turnon_adc: v }))} /> + setUsConfig(s => ({ ...s, start_pgainbias: v }))} /> + setUsConfig(s => ({ ...s, start_adcsampl: v }))} /> + setUsConfig(s => ({ ...s, restart_capt: v }))} /> + setUsConfig(s => ({ ...s, capt_timeout: v }))} /> +
+
+ ) +} \ No newline at end of file diff --git a/wulpus-frontend/src/assets/icons/fullscreen_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg b/wulpus-frontend/src/assets/icons/fullscreen_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg deleted file mode 100644 index e4aa7d0..0000000 --- a/wulpus-frontend/src/assets/icons/fullscreen_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/wulpus-frontend/src/helper.ts b/wulpus-frontend/src/helper.ts index 6c0ba59..e1e26c0 100644 --- a/wulpus-frontend/src/helper.ts +++ b/wulpus-frontend/src/helper.ts @@ -89,3 +89,26 @@ export function hilbertEnvelope(data: number[], nTaps = 101) { } return out; } + + +export async function toggleFullscreen(plotContainerRef: React.RefObject) { + const el = plotContainerRef.current; + if (!el) return; + if (!document.fullscreenElement) { + const elWithVendors = el as HTMLElement & { + webkitRequestFullscreen?: () => Promise | void; + msRequestFullscreen?: () => Promise | void; + }; + if (elWithVendors.requestFullscreen) await elWithVendors.requestFullscreen(); + else if (elWithVendors.webkitRequestFullscreen) await elWithVendors.webkitRequestFullscreen(); + else if (elWithVendors.msRequestFullscreen) await elWithVendors.msRequestFullscreen(); + } else { + const docWithVendors = document as Document & { + webkitExitFullscreen?: () => Promise | void; + msExitFullscreen?: () => Promise | void; + }; + if (document.exitFullscreen) await document.exitFullscreen(); + else if (docWithVendors.webkitExitFullscreen) await docWithVendors.webkitExitFullscreen(); + else if (docWithVendors.msExitFullscreen) await docWithVendors.msExitFullscreen(); + } +} \ No newline at end of file diff --git a/wulpus/wulpus.py b/wulpus/wulpus.py index a394952..ce1151d 100644 --- a/wulpus/wulpus.py +++ b/wulpus/wulpus.py @@ -1,4 +1,5 @@ import asyncio +import inspect import os import time from enum import IntEnum @@ -6,13 +7,10 @@ import numpy as np -from wulpus.wulpus_config_models import WulpusConfig -from wulpus.dongle_mock import WulpusDongleMock +import wulpus from wulpus.dongle import WulpusDongle -from wulpus.websocket_manager import WebsocketManager from wulpus.wulpus_api import gen_conf_package, gen_restart_package -import wulpus -import inspect +from wulpus.wulpus_config_models import WulpusConfig class Status(IntEnum): From 133dcd098df271cc7bfd318f0cad2eaed27e1238 Mon Sep 17 00:00:00 2001 From: Louis Date: Tue, 26 Aug 2025 11:23:03 -0700 Subject: [PATCH 16/51] Add logging and configuration management features, including API endpoints for logs and configs and a new ConfigFilesPanel --- wulpus-frontend/package-lock.json | 66 ++++++++- wulpus-frontend/package.json | 2 + wulpus-frontend/src/App.tsx | 17 +++ wulpus-frontend/src/ConfigFilesPanel.tsx | 177 +++++++++++++++++++++++ wulpus-frontend/src/LogsPage.tsx | 57 ++++++++ wulpus-frontend/src/api.ts | 6 + wulpus-frontend/src/helper.ts | 8 +- wulpus-frontend/src/main.tsx | 14 +- wulpus-frontend/vite.config.ts | 8 + wulpus/helper.py | 25 ++++ wulpus/main.py | 101 ++++++++++++- wulpus/wulpus.py | 17 ++- 12 files changed, 485 insertions(+), 13 deletions(-) create mode 100644 wulpus-frontend/src/ConfigFilesPanel.tsx create mode 100644 wulpus-frontend/src/LogsPage.tsx create mode 100644 wulpus/helper.py diff --git a/wulpus-frontend/package-lock.json b/wulpus-frontend/package-lock.json index 4f5c44e..3d53999 100644 --- a/wulpus-frontend/package-lock.json +++ b/wulpus-frontend/package-lock.json @@ -13,7 +13,9 @@ "plotly.js": "^3.1.0", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-hot-toast": "^2.6.0", "react-plotly.js": "^2.6.0", + "react-router": "^7.8.2", "react-use-websocket": "^4.13.0", "tailwindcss": "^4.1.12" }, @@ -2530,6 +2532,15 @@ "typedarray": "^0.0.6" } }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -2620,7 +2631,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, "license": "MIT" }, "node_modules/d": { @@ -3817,6 +3827,15 @@ "resolve": "^1.0.0" } }, + "node_modules/goober": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", + "integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -5214,6 +5233,23 @@ "react": "^19.1.1" } }, + "node_modules/react-hot-toast": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.6.0.tgz", + "integrity": "sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==", + "license": "MIT", + "dependencies": { + "csstype": "^3.1.3", + "goober": "^2.1.16" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -5233,6 +5269,28 @@ "react": ">0.13.0" } }, + "node_modules/react-router": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.8.2.tgz", + "integrity": "sha512-7M2fR1JbIZ/jFWqelpvSZx+7vd7UlBTfdZqf6OSdF9g6+sfdqJDAWcak6ervbHph200ePlu+7G8LdoiC3ReyAQ==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, "node_modules/react-use-websocket": { "version": "4.13.0", "resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-4.13.0.tgz", @@ -5540,6 +5598,12 @@ "node": ">=10" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/shallow-copy": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", diff --git a/wulpus-frontend/package.json b/wulpus-frontend/package.json index 225d4b3..4ea389a 100644 --- a/wulpus-frontend/package.json +++ b/wulpus-frontend/package.json @@ -15,7 +15,9 @@ "plotly.js": "^3.1.0", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-hot-toast": "^2.6.0", "react-plotly.js": "^2.6.0", + "react-router": "^7.8.2", "react-use-websocket": "^4.13.0", "tailwindcss": "^4.1.12" }, diff --git a/wulpus-frontend/src/App.tsx b/wulpus-frontend/src/App.tsx index 954e1ff..56f11d7 100644 --- a/wulpus-frontend/src/App.tsx +++ b/wulpus-frontend/src/App.tsx @@ -4,6 +4,7 @@ import { ConnectionPanel } from './ConnectionPanel'; import { Graph } from './Graph'; import { TxRxConfigPanel } from './TxRxConfig'; import { USConfigPanel } from './UsConfig'; +import { ConfigFilesPanel } from './ConfigFilesPanel'; import type { DataFrame, Status, TxRxConfig, UsConfig, WulpusConfig } from './websocket-types'; function App() { @@ -72,6 +73,12 @@ function App() { return (
+
+
+

Wulpus Dashboard

+ Recorded logs +
+
@@ -91,6 +98,16 @@ function App() {
+ +
+ { + if (conf?.tx_rx_config) setTxRxConfigs(conf.tx_rx_config); + if (conf?.us_config) setUsConfig(conf.us_config); + }} + /> +
diff --git a/wulpus-frontend/src/ConfigFilesPanel.tsx b/wulpus-frontend/src/ConfigFilesPanel.tsx new file mode 100644 index 0000000..b2dc49b --- /dev/null +++ b/wulpus-frontend/src/ConfigFilesPanel.tsx @@ -0,0 +1,177 @@ +import { useEffect, useMemo, useState } from 'react'; +import { toast } from 'react-hot-toast'; +import type { WulpusConfig } from './websocket-types'; + +type Props = { + effectiveConfig: WulpusConfig; + applyConfig?: (conf: WulpusConfig) => void; +}; + +async function listConfigs(): Promise { + const res = await fetch('/configs'); + if (!res.ok) throw new Error(await res.text()); + return res.json(); +} + +async function downloadConfig(filename: string): Promise { + const res = await fetch(`/configs/${encodeURIComponent(filename)}`); + if (!res.ok) throw new Error(await res.text()); + return res.json(); +} + +async function deleteConfig(filename: string): Promise { + const res = await fetch(`/configs/${encodeURIComponent(filename)}`, { + method: 'DELETE', + }); + if (!res.ok) throw new Error(await res.text()); +} + +export function ConfigFilesPanel({ effectiveConfig, applyConfig }: Props) { + const [saving, setSaving] = useState(false); + const [saveName, setSaveName] = useState(''); + const [error, setError] = useState(null); + const [configList, setConfigList] = useState(null); + const [uploading, setUploading] = useState(false); + + const canSave = useMemo(() => { + return !saving && effectiveConfig && typeof effectiveConfig === 'object'; + }, [saving, effectiveConfig]); + + const refreshList = async () => { + try { + setConfigList(await listConfigs()); + } catch (e) { + setError(String(e)); + } + }; + + useEffect(() => { refreshList(); }, []); + + const onSave = async () => { + setError(null); + setSaving(true); + try { + const params = new URLSearchParams(); + if (saveName.trim()) params.set('name', saveName.trim()); + const res = await fetch(`/configs?${params.toString()}`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(effectiveConfig), + }); + if (!res.ok) throw new Error(await res.text()); + setSaveName(''); + await refreshList(); + toast.success('Configuration saved'); + } catch (e) { + setError(String(e)); + toast.error('Failed to save configuration'); + } finally { + setSaving(false); + } + }; + + const onLoad = async (filename: string) => { + setError(null); + try { + const conf = await downloadConfig(filename); + applyConfig?.(conf); + toast.success('Configuration applied'); + } catch (e) { + setError(String(e)); + } + }; + + const onDelete = async (filename: string) => { + setError(null); + const confirmed = window.confirm(`Delete config "${filename}"?`); + if (!confirmed) return; + try { + await deleteConfig(filename); + await refreshList(); + toast.success('Configuration deleted'); + } catch (e) { + setError(String(e)); + toast.error('Failed to delete configuration'); + } + }; + + const applyLocalFile = async (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + if (!file) return; + + setUploading(true); + setError(null); + + try { + const reader = new FileReader(); + reader.onload = async (e) => { + const content = e.target?.result; + if (typeof content === 'string') { + const config = JSON.parse(content); + applyConfig?.(config); + toast.success('Configuration applied'); + } + }; + reader.readAsText(file); + } catch (e) { + setError(String(e)); + } finally { + setUploading(false); + } + }; + + return ( +
+

Config files

+ {error &&
{error}
} +
+
+
+ +

(.json will be added automatically)

+
+
+ setSaveName(e.target.value)} + placeholder="my-config" + className="mt-1 grow rounded-md border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-600" + /> + +
+
+
+ +
+
Existing configs
+ {configList === null ? ( +
Loading…
+ ) : configList.length === 0 ? ( +
No config files found.
+ ) : ( +
    + {configList.map((f) => ( +
  • + {f} +
    + + Download + +
    +
  • + ))} +
+ )} +
+ + + +
+ ); +} diff --git a/wulpus-frontend/src/LogsPage.tsx b/wulpus-frontend/src/LogsPage.tsx new file mode 100644 index 0000000..e3dc3ac --- /dev/null +++ b/wulpus-frontend/src/LogsPage.tsx @@ -0,0 +1,57 @@ +import { useEffect, useState } from 'react'; + +export function LogsPage() { + const [files, setFiles] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + let cancelled = false; + fetch('/logs') + .then(async (res) => { + if (!res.ok) throw new Error(await res.text()); + return res.json(); + }) + .then((data: string[]) => { if (!cancelled) setFiles(data); }) + .catch((e) => { if (!cancelled) setError(String(e)); }); + return () => { cancelled = true; }; + }, []); + + return ( +
+
+
+

Recorded logs

+ Back to Dashboard +
+ +
+
+ {error && ( +
{error}
+ )} + {files === null ? ( +
Loading…
+ ) : files.length === 0 ? ( +
No logs found.
+ ) : ( + + )} +
+
+
+
+ ); +} diff --git a/wulpus-frontend/src/api.ts b/wulpus-frontend/src/api.ts index 6927237..ed17ff4 100644 --- a/wulpus-frontend/src/api.ts +++ b/wulpus-frontend/src/api.ts @@ -56,6 +56,12 @@ export async function postStop(): Promise { return res.json(); } +export async function getLogs(): Promise { + const res = await fetch('/logs'); + if (!res.ok) throw new Error(await res.text()); + return res.json(); +} + export function StatusLabel(s?: number) { switch (s) { case 0: return 'NOT_CONNECTED'; diff --git a/wulpus-frontend/src/helper.ts b/wulpus-frontend/src/helper.ts index e1e26c0..3d501d7 100644 --- a/wulpus-frontend/src/helper.ts +++ b/wulpus-frontend/src/helper.ts @@ -8,10 +8,12 @@ function sinc(x: number) { } function hammingWindow(n: number) { - // return array length n + const ALPHA = 0.54; + const BETA = 0.46; const out = new Array(n); + for (let i = 0; i < n; i++) { - out[i] = 0.54 - 0.46 * Math.cos((2 * Math.PI * i) / (n - 1)); + out[i] = ALPHA - BETA * Math.cos((2 * Math.PI * i) / (n - 1)); } return out; } @@ -85,7 +87,7 @@ export function hilbertEnvelope(data: number[], nTaps = 101) { // envelope sqrt(real^2 + imag^2) const out = new Array(data.length); for (let i = 0; i < data.length; i++) { - out[i] = Math.sqrt(data[i] * data[i] + imag[i] * imag[i]); + out[i] = Math.hypot(data[i], imag[i]); } return out; } diff --git a/wulpus-frontend/src/main.tsx b/wulpus-frontend/src/main.tsx index bef5202..86b6475 100644 --- a/wulpus-frontend/src/main.tsx +++ b/wulpus-frontend/src/main.tsx @@ -2,9 +2,21 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import './index.css' import App from './App.tsx' +import { createBrowserRouter } from "react-router"; +import { RouterProvider } from "react-router/dom"; +import { LogsPage } from './LogsPage' +import { Toaster } from 'react-hot-toast' + +const router = createBrowserRouter([ + { path: '/', element: }, + { path: '/data', element: }, +]) createRoot(document.getElementById('root')!).render( - + <> + + + , ) diff --git a/wulpus-frontend/vite.config.ts b/wulpus-frontend/vite.config.ts index 3ef46fc..8d48a4e 100644 --- a/wulpus-frontend/vite.config.ts +++ b/wulpus-frontend/vite.config.ts @@ -12,6 +12,14 @@ export default defineConfig({ changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, ""), }, + "/logs": { + target: "http://localhost:8000", + changeOrigin: true, + }, + "/configs": { + target: "http://localhost:8000", + changeOrigin: true, + }, "/ws": { target: "ws://localhost:8000", ws: true, diff --git a/wulpus/helper.py b/wulpus/helper.py new file mode 100644 index 0000000..12bf6a6 --- /dev/null +++ b/wulpus/helper.py @@ -0,0 +1,25 @@ +import os + +from fastapi import HTTPException + + +def ensure_dir(dir: str) -> None: + os.makedirs(dir, exist_ok=True) + + +def check_if_filereq_is_legitimate(req_name: str, system_dir: str, allowed_ending: str) -> str: + """ Check if the requested file seems plausible. + + Raise HTTPExceptions if invalid. + + Returns: + str: The validated file path. + """ + if os.path.sep in req_name or (os.path.altsep and os.path.altsep in req_name) or len(req_name) > 100: + raise HTTPException(status_code=400, detail="Invalid req_name") + if not req_name.lower().endswith(allowed_ending): + raise HTTPException(status_code=400, detail="Invalid file type") + path = os.path.join(system_dir, req_name) + if not os.path.isfile(path): + raise HTTPException(status_code=404, detail="File not found") + return path diff --git a/wulpus/main.py b/wulpus/main.py index b544196..09b80d9 100644 --- a/wulpus/main.py +++ b/wulpus/main.py @@ -1,13 +1,27 @@ import asyncio +import inspect +import os +from typing import List import time +import json + + import uvicorn -from fastapi import FastAPI, WebSocket, WebSocketDisconnect +from fastapi import FastAPI, WebSocket, WebSocketDisconnect, HTTPException, UploadFile, File +from typing import Optional +from fastapi.responses import FileResponse +from helper import check_if_filereq_is_legitimate, ensure_dir +import wulpus as wulpus_pkg from wulpus.wulpus_config_models import ComPort, WulpusConfig from wulpus.websocket_manager import WebsocketManager from wulpus.wulpus import Wulpus +MEASUREMENTS_DIR = os.path.join(os.path.dirname( + inspect.getfile(wulpus_pkg)), 'measurements') +CONFIG_DIR = os.path.join(os.path.dirname( + inspect.getfile(wulpus_pkg)), 'configs') wulpus = Wulpus() manager = WebsocketManager(wulpus) @@ -73,5 +87,90 @@ async def websocket_endpoint(websocket: WebSocket): await manager.broadcast_text("A Client left the chat") +@app.get("/logs", response_model=List[str]) +def list_logs() -> List[str]: + """Return list of saved measurement files (npz) relative names.""" + ensure_dir(MEASUREMENTS_DIR) + try: + files = [f for f in os.listdir( + MEASUREMENTS_DIR) if f.lower().endswith('.npz')] + files.sort(reverse=True) + return files + except FileNotFoundError: + return [] + + +@app.get("/logs/{filename}") +def download_log(filename: str): + """Download a specific measurement file by filename.""" + ensure_dir(MEASUREMENTS_DIR) + filepath = check_if_filereq_is_legitimate( + filename, MEASUREMENTS_DIR, '.npz') + return FileResponse(filepath, media_type='application/octet-stream', filename=filename) + + +@app.get("/configs", response_model=List[str]) +def list_configs() -> List[str]: + """Return list of saved config files (json) relative names.""" + ensure_dir(CONFIG_DIR) + try: + files = [f for f in os.listdir( + CONFIG_DIR) if f.lower().endswith('.json')] + files.sort(reverse=True) + return files + except FileNotFoundError: + return [] + + +@app.get("/configs/{filename}") +def download_config(filename: str): + """Download a specific config file by filename.""" + ensure_dir(CONFIG_DIR) + filepath = check_if_filereq_is_legitimate( + filename, CONFIG_DIR, '.json') + return FileResponse(filepath, media_type='application/octet-stream', filename=filename) + + +@app.post("/configs") +async def save_config(config: WulpusConfig, name: Optional[str] = None): + """Save the provided config JSON to a file in the configs directory.""" + ensure_dir(CONFIG_DIR) + # derive safe base filename + if name is None or len(name.strip()) == 0: + name = "wulpus-config-" + \ + time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime()) + # very simple sanitization + if os.path.sep in name or (os.path.altsep and os.path.altsep in name) or len(name) > 100: + raise HTTPException(status_code=400, detail="Invalid name") + base = os.path.join(CONFIG_DIR, name) + filename = base + ".json" + # avoid overwriting existing files + suffix = 1 + while os.path.exists(filename): + filename = f"{base}_{suffix}.json" + suffix += 1 + try: + with open(filename, 'w', encoding='utf-8') as f: + json.dump(config.model_dump(), f, ensure_ascii=False, indent=2) + return {"filename": os.path.basename(filename)} + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) from e + + +@app.delete("/configs/{filename}") +def delete_config(filename: str): + """Delete a specific config file by filename.""" + ensure_dir(CONFIG_DIR) + try: + filepath = check_if_filereq_is_legitimate( + filename, CONFIG_DIR, '.json') + os.remove(filepath) + return {"ok": True} + except HTTPException: + raise + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) from e + + if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000) diff --git a/wulpus/wulpus.py b/wulpus/wulpus.py index ce1151d..225906d 100644 --- a/wulpus/wulpus.py +++ b/wulpus/wulpus.py @@ -9,6 +9,7 @@ import wulpus from wulpus.dongle import WulpusDongle +from wulpus.dongle_mock import WulpusDongleMock from wulpus.wulpus_api import gen_conf_package, gen_restart_package from wulpus.wulpus_config_models import WulpusConfig @@ -25,8 +26,8 @@ class Wulpus: def __init__(self): self._config: Union[WulpusConfig, None] = None self._status: Status = Status.NOT_CONNECTED - self._dongle = WulpusDongle() - # self._dongle = WulpusDongleMock() + # self._dongle = WulpusDongle() + self._dongle = WulpusDongleMock() self._last_connection: str = '' self._latest_frame: Union[np.ndarray, None] = None self._data: Union[np.ndarray, None] = None @@ -138,21 +139,23 @@ def __save_measurement(self): start_time = time.localtime(self._recording_start) timestring = time.strftime("%Y-%m-%d_%H-%M-%S", start_time) filename = "wulpus-data-" + timestring + # Ensure measurement directory exists module_path = os.path.dirname(inspect.getfile(wulpus)) measurement_path = os.path.join(module_path, 'measurements') - os.chdir(measurement_path) + os.makedirs(measurement_path, exist_ok=True) + basepath = os.path.join(measurement_path, filename) # Check if filename exists (.npz gets added by .savez command) - while os.path.isfile(filename + '.npz'): - filename = filename + "_conflict" + while os.path.isfile(basepath + '.npz'): + basepath = basepath + "_conflict" # Save numpy data array to file - np.savez_compressed(filename, + np.savez_compressed(basepath, data_arr=self._data, acq_num_arr=self._data_acq_num, tx_rx_id_arr=self._data_tx_rx_id, record_start=np.array([self._recording_start])) - print('Data saved in ' + filename + '.npz') + print('Data saved in ' + basepath + '.npz') def get_latest_frame(self): return self._latest_frame From c588bd127a8b6363313bd33d6bd0c71975384685 Mon Sep 17 00:00:00 2001 From: Louis Date: Tue, 26 Aug 2025 14:06:50 -0700 Subject: [PATCH 17/51] make graph filter user-defined --- wulpus-frontend/package-lock.json | 31 ++++++++++++++++++++++++ wulpus-frontend/package.json | 1 + wulpus-frontend/src/Graph.tsx | 40 +++++++++++++++++++++++++++---- wulpus-frontend/src/index.css | 8 +++++++ 4 files changed, 75 insertions(+), 5 deletions(-) diff --git a/wulpus-frontend/package-lock.json b/wulpus-frontend/package-lock.json index 3d53999..f1cdee0 100644 --- a/wulpus-frontend/package-lock.json +++ b/wulpus-frontend/package-lock.json @@ -15,6 +15,7 @@ "react-dom": "^19.1.1", "react-hot-toast": "^2.6.0", "react-plotly.js": "^2.6.0", + "react-range-slider-input": "^3.2.1", "react-router": "^7.8.2", "react-use-websocket": "^4.13.0", "tailwindcss": "^4.1.12" @@ -2403,6 +2404,15 @@ "integrity": "sha512-kgMuFyE78OC6Dyu3Dy7vcx4uy97EIbVxJB/B0eJ3bUNAkwdNcxYzgKltnyADiYwsR7SEqkkUPsEUT//OVS6XMA==", "license": "MIT" }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color-alpha": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/color-alpha/-/color-alpha-1.0.4.tgz", @@ -2541,6 +2551,17 @@ "node": ">=18" } }, + "node_modules/core-js": { + "version": "3.45.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.1.tgz", + "integrity": "sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -5269,6 +5290,16 @@ "react": ">0.13.0" } }, + "node_modules/react-range-slider-input": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/react-range-slider-input/-/react-range-slider-input-3.2.1.tgz", + "integrity": "sha512-MApTX4a/Uzm9ZrJFoWu2kM87TKHJpnHHBV2JR9N9WmOSWk832DDBT3suNN6vCQmFRRtfJO9stw+bsiGpto0Hig==", + "license": "MIT", + "dependencies": { + "clsx": "^1.1.1", + "core-js": "^3.22.4" + } + }, "node_modules/react-router": { "version": "7.8.2", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.8.2.tgz", diff --git a/wulpus-frontend/package.json b/wulpus-frontend/package.json index 4ea389a..acdaf8a 100644 --- a/wulpus-frontend/package.json +++ b/wulpus-frontend/package.json @@ -17,6 +17,7 @@ "react-dom": "^19.1.1", "react-hot-toast": "^2.6.0", "react-plotly.js": "^2.6.0", + "react-range-slider-input": "^3.2.1", "react-router": "^7.8.2", "react-use-websocket": "^4.13.0", "tailwindcss": "^4.1.12" diff --git a/wulpus-frontend/src/Graph.tsx b/wulpus-frontend/src/Graph.tsx index f2e98a3..210faa3 100644 --- a/wulpus-frontend/src/Graph.tsx +++ b/wulpus-frontend/src/Graph.tsx @@ -1,12 +1,13 @@ import type Plotly from 'plotly.js'; -import { useEffect, useRef, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import Plot from 'react-plotly.js'; import { bandpassFIR, hilbertEnvelope, toggleFullscreen } from './helper'; import type { DataFrame, UsConfig } from './websocket-types'; +import RangeSlider from 'react-range-slider-input'; export function Graph(props: { dataFrame: DataFrame | null, bmodeBuffer: number[][], usConfig: UsConfig }) { const { dataFrame, bmodeBuffer, usConfig } = props; - + const sampling_freq = usConfig.sampling_freq; const plotContainerRef = useRef(null); const [showBMode, setShowBMode] = useState(false); @@ -21,11 +22,17 @@ export function Graph(props: { dataFrame: DataFrame | null, bmodeBuffer: number[ }, []); // compute filter/envelope just-in-time before rendering - const lowCutHz = usConfig.sampling_freq / 2 * 0.1; - const highCutHz = usConfig.sampling_freq / 2 * 0.9; - const filteredFrame = dataFrame ? bandpassFIR(dataFrame, usConfig.sampling_freq, lowCutHz, highCutHz, 31) : []; + const minLowCutHz = useCallback((sampling_freq: number) => sampling_freq / 2 * 0.1, []); + const maxHighCutHz = useCallback((sampling_freq: number) => sampling_freq / 2 * 0.9, []); + const [lowCutHz, setLowCutHz] = useState(minLowCutHz(sampling_freq)); + const [highCutHz, setHighCutHz] = useState(maxHighCutHz(sampling_freq)); + const filteredFrame = dataFrame ? bandpassFIR(dataFrame, sampling_freq, lowCutHz, highCutHz, 31) : []; const envelopeFrame = filteredFrame.length ? hilbertEnvelope(filteredFrame, 101) : []; + useEffect(() => { + setLowCutHz(minLowCutHz(sampling_freq)); + setHighCutHz(maxHighCutHz(sampling_freq)); + }, [sampling_freq, setHighCutHz, minLowCutHz, maxHighCutHz]); return (
@@ -87,6 +94,29 @@ export function Graph(props: { dataFrame: DataFrame | null, bmodeBuffer: number[ > {isFullscreen ? fullscreen_exit : fullscreen} + + {!showBMode && ( +
+ Filter: +
+ {Math.round(lowCutHz / 1e4) / 100} MHz +
+ { + const [low, high] = i; + setLowCutHz(low); + setHighCutHz(high); + }} + /> +
+ {Math.round(highCutHz / 1e4) / 100} MHz +
+
+ )}
) } \ No newline at end of file diff --git a/wulpus-frontend/src/index.css b/wulpus-frontend/src/index.css index eb334d5..4997142 100644 --- a/wulpus-frontend/src/index.css +++ b/wulpus-frontend/src/index.css @@ -1,5 +1,6 @@ @import "tailwindcss"; @import '@material-symbols/font-400'; +@import "react-range-slider-input/dist/style.css"; @layer base { @@ -7,4 +8,11 @@ [role="button"]:not([disabled]) { cursor: pointer; } +} +.range-slider .range-slider__thumb { + background: #008000; +} + +.range-slider .range-slider__range { + background: #005f00; } \ No newline at end of file From 30314312188cd9ec32756e2b71a6bead890ab0de Mon Sep 17 00:00:00 2001 From: Louis Date: Wed, 27 Aug 2025 10:30:54 -0700 Subject: [PATCH 18/51] Add mock and replay functionality --- wulpus-frontend/src/ConnectionPanel.tsx | 18 ++++++- wulpus-frontend/src/LogsPage.tsx | 26 ++++++++-- wulpus-frontend/src/api.ts | 19 +++++++ wulpus-frontend/src/websocket-types.ts | 1 + wulpus/main.py | 59 +++++++++++++++------ wulpus/websocket_manager.py | 9 +++- wulpus/wulpus.py | 13 ++--- wulpus/wulpus_mock.py | 69 +++++++++++++++++++++++++ 8 files changed, 186 insertions(+), 28 deletions(-) create mode 100644 wulpus/wulpus_mock.py diff --git a/wulpus-frontend/src/ConnectionPanel.tsx b/wulpus-frontend/src/ConnectionPanel.tsx index 3859b62..5b1b557 100644 --- a/wulpus-frontend/src/ConnectionPanel.tsx +++ b/wulpus-frontend/src/ConnectionPanel.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { getBTHConnections, postConnect, postDisconnect, postStart, postStop, StatusLabel } from "./api"; +import { deactivateMock, getBTHConnections, postConnect, postDisconnect, postStart, postStop, StatusLabel } from "./api"; import type { Status, WulpusConfig } from "./websocket-types"; export function ConnectionPanel(props: { effectiveConfig: WulpusConfig, status: Status | null }) { @@ -7,6 +7,8 @@ export function ConnectionPanel(props: { effectiveConfig: WulpusConfig, status: const [connections, setConnections] = useState([]); const [selectedPort, setSelectedPort] = useState(""); + const isMock = status?.mock ?? false; + async function refreshConnections() { try { const list = await getBTHConnections(); @@ -40,7 +42,19 @@ export function ConnectionPanel(props: { effectiveConfig: WulpusConfig, status: return (
-

Connection

+
+

Connection {isMock ? ' (Simulation)' : ''}

+ {isMock && + <> + + + } +
-
diff --git a/wulpus-frontend/src/Graph.tsx b/wulpus-frontend/src/Graph.tsx index 210faa3..044e0bb 100644 --- a/wulpus-frontend/src/Graph.tsx +++ b/wulpus-frontend/src/Graph.tsx @@ -7,6 +7,7 @@ import RangeSlider from 'react-range-slider-input'; export function Graph(props: { dataFrame: DataFrame | null, bmodeBuffer: number[][], usConfig: UsConfig }) { const { dataFrame, bmodeBuffer, usConfig } = props; + const data = dataFrame?.data ?? [] const sampling_freq = usConfig.sampling_freq; const plotContainerRef = useRef(null); const [showBMode, setShowBMode] = useState(false); @@ -26,7 +27,7 @@ export function Graph(props: { dataFrame: DataFrame | null, bmodeBuffer: number[ const maxHighCutHz = useCallback((sampling_freq: number) => sampling_freq / 2 * 0.9, []); const [lowCutHz, setLowCutHz] = useState(minLowCutHz(sampling_freq)); const [highCutHz, setHighCutHz] = useState(maxHighCutHz(sampling_freq)); - const filteredFrame = dataFrame ? bandpassFIR(dataFrame, sampling_freq, lowCutHz, highCutHz, 31) : []; + const filteredFrame = data ? bandpassFIR(data, sampling_freq, lowCutHz, highCutHz, 31) : []; const envelopeFrame = filteredFrame.length ? hilbertEnvelope(filteredFrame, 101) : []; useEffect(() => { @@ -54,18 +55,18 @@ export function Graph(props: { dataFrame: DataFrame | null, bmodeBuffer: number[ i) : [], - y: dataFrame ?? [], + x: data ? data.map((_, i) => i) : [], + y: data ?? [], type: 'scatter', mode: 'lines', name: 'Raw', line: { color: 'blue' }, }, { - x: dataFrame ? dataFrame.map((_, i) => i) : [], + x: data ? data.map((_, i) => i) : [], y: filteredFrame.length ? filteredFrame : [], type: 'scatter', mode: 'lines', name: 'Filter', line: { color: 'green' }, visible: 'legendonly', }, { - x: dataFrame ? dataFrame.map((_, i) => i) : [], + x: data ? data.map((_, i) => i) : [], y: envelopeFrame.length ? envelopeFrame : [], type: 'scatter', mode: 'lines', name: 'Envelope', line: { color: 'red' }, visible: 'legendonly', diff --git a/wulpus-frontend/src/MultiNumField.tsx b/wulpus-frontend/src/MultiNumField.tsx index 631c92b..67add94 100644 --- a/wulpus-frontend/src/MultiNumField.tsx +++ b/wulpus-frontend/src/MultiNumField.tsx @@ -1,4 +1,5 @@ import { useEffect, useRef, useState } from 'react'; +import { CHANNEL_SIZE } from './App'; export function MultiNumField({ label, values, onChange, showChannelBoxes = false, color = 'bg-green-500' }: { label: string; @@ -45,7 +46,7 @@ export function MultiNumField({ label, values, onChange, showChannelBoxes = fals placeholder="e.g., 0,1,2" /> {showChannelBoxes && (
- {Array.from({ length: 8 }).map((_, ch) => { + {Array.from({ length: CHANNEL_SIZE }).map((_, ch) => { const active = values.includes(ch); const base = `h-6 w-6 rounded flex items-center justify-center text-white text-xs ${active ? `${color} hover:saturate-80` : 'bg-gray-200 text-gray-700 hover:bg-gray-300'}`; return ( diff --git a/wulpus-frontend/src/TxRxConfig.tsx b/wulpus-frontend/src/TxRxConfig.tsx index 144aa66..dcd0c16 100644 --- a/wulpus-frontend/src/TxRxConfig.tsx +++ b/wulpus-frontend/src/TxRxConfig.tsx @@ -1,3 +1,4 @@ +import { CHANNEL_SIZE } from "./App"; import { MultiNumField } from "./MultiNumField"; import type { TxRxConfig } from './websocket-types'; @@ -28,12 +29,12 @@ export function TxRxConfigPanel(props: { txRxConfigs: TxRxConfig[], setTxRxConfi
- updateTxRx(idx, 'tx_channels', vals)} showChannelBoxes={true} color="bg-green-500" /> - updateTxRx(idx, 'rx_channels', vals)} showChannelBoxes={true} @@ -54,7 +55,7 @@ export function TxRxConfigPanel(props: { txRxConfigs: TxRxConfig[], setTxRxConfi
))} - {txRxConfigs.length < 8 && ( + {txRxConfigs.length < CHANNEL_SIZE && ( )}
diff --git a/wulpus-frontend/src/api.ts b/wulpus-frontend/src/api.ts index 7672968..ca84830 100644 --- a/wulpus-frontend/src/api.ts +++ b/wulpus-frontend/src/api.ts @@ -56,6 +56,14 @@ export async function postStop(): Promise { return res.json(); } +export async function postActivateMock(): Promise { + const res = await fetch(`${BASE_URL}/activate-mock`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + }); + if (!res.ok) throw new Error(`POST /activate-mock failed: ${res.status}`); +} + export async function deactivateMock(): Promise { const res = await fetch(`${BASE_URL}/deactivate-mock`, { method: "POST", diff --git a/wulpus-frontend/src/websocket-types.ts b/wulpus-frontend/src/websocket-types.ts index a20a8d0..e7f01f1 100644 --- a/wulpus-frontend/src/websocket-types.ts +++ b/wulpus-frontend/src/websocket-types.ts @@ -43,4 +43,9 @@ export type Status = { progress: number; // 0..1 }; -export type DataFrame = number[]; \ No newline at end of file +export type DataFrame = { + data: number[] + time: number[] + tx: number[] + rx: number[] +} \ No newline at end of file diff --git a/wulpus/main.py b/wulpus/main.py index 1c22467..470a239 100644 --- a/wulpus/main.py +++ b/wulpus/main.py @@ -81,7 +81,7 @@ async def websocket_endpoint(websocket: WebSocket): latest_frame = manager.get_wulpus().get_latest_frame() if latest_frame is not None: - await manager.broadcast_json(latest_frame.tolist()) + await manager.broadcast_json(latest_frame) try: while True: data = await websocket.receive_text() @@ -176,6 +176,13 @@ def delete_config(filename: str): raise HTTPException(status_code=500, detail=str(e)) from e +@app.post("/api/activate-mock") +def activate_mock(): + wulpus.stop() + manager.set_wulpus(wulpus_mock) + return {"ok": "ok"} + + @app.post("/api/deactivate-mock") def deactivate_mock(): wulpus_mock.stop() diff --git a/wulpus/websocket_manager.py b/wulpus/websocket_manager.py index 2bd92a8..29d8f99 100644 --- a/wulpus/websocket_manager.py +++ b/wulpus/websocket_manager.py @@ -61,4 +61,4 @@ async def send_data(self, new_measurement_event: asyncio.Event): new_measurement_event.clear() data = self.wulpus.get_latest_frame() if data is not None: - await self.broadcast_json(data.tolist()) + await self.broadcast_json(data) diff --git a/wulpus/wulpus.py b/wulpus/wulpus.py index 5b53892..78b8c8e 100644 --- a/wulpus/wulpus.py +++ b/wulpus/wulpus.py @@ -12,6 +12,7 @@ from wulpus.dongle_mock import WulpusDongleMock from wulpus.wulpus_api import gen_conf_package, gen_restart_package from wulpus.wulpus_config_models import WulpusConfig +from typing import TypedDict class Status(IntEnum): @@ -22,6 +23,13 @@ class Status(IntEnum): ERROR = 9 +class Measurement(TypedDict): + data: list[float] + time: float + tx: list[int] + rx: list[int] + + class Wulpus: def __init__(self): self._config: Union[WulpusConfig, None] = None @@ -29,10 +37,11 @@ def __init__(self): self._dongle = WulpusDongle() # self._dongle = WulpusDongleMock() self._last_connection: str = '' - self._latest_frame: Union[np.ndarray, None] = None + self._latest_frame: Union[Measurement, None] = None self._data: Union[np.ndarray, None] = None self._data_acq_num: Union[np.ndarray, None] = None self._data_tx_rx_id: Union[np.ndarray, None] = None + self._data_time: Union[np.ndarray, None] = None # Event to signal new measurement data for WebSocket clients self._new_measurement = asyncio.Event() self._recording_start = time.time() @@ -110,17 +119,21 @@ async def _measure(self): self._data = np.zeros((num_samples, number_of_acq), dtype=' Measurement: + tx_rx_config = self._config.tx_rx_config[_tx_rx_id] + return Measurement( + data=_data.tolist(), + time=float(_time), + tx=tx_rx_config.tx_channels, + rx=tx_rx_config.rx_channels + ) diff --git a/wulpus/wulpus_mock.py b/wulpus/wulpus_mock.py index b63ffd3..8dae638 100644 --- a/wulpus/wulpus_mock.py +++ b/wulpus/wulpus_mock.py @@ -50,9 +50,10 @@ async def _measure(self): self._data = data['data_arr'] self._data_acq_num = data['acq_num_arr'] self._data_tx_rx_id = data['tx_rx_id_arr'] - data_cnt = data['data_arr'].shape[1] num_samples = data['data_arr'].shape[0] + self._data_time = data['time_arr'] if 'time_arr' in data else np.zeros( + data_cnt, dtype=np.float32) self._config.us_config.num_acqs = data_cnt self._config.us_config.num_samples = num_samples @@ -61,7 +62,8 @@ async def _measure(self): while index < data_cnt and self._acquisition_running: await asyncio.sleep(0.1) # await asyncio.sleep(self._config.us_config.meas_period/1e6) - self._latest_frame = self._data[:, index] + self._latest_frame = self._structure_measurement( + self._data[:, index], self._data_tx_rx_id[index], self._data_time[index]) self._new_measurement.set() index += 1 self._live_data_cnt = index From d63e4a16d4c5fdc8de80bb8816b57cb3ab355a23 Mon Sep 17 00:00:00 2001 From: Louis Date: Thu, 28 Aug 2025 11:01:47 -0700 Subject: [PATCH 23/51] Fix bug in download-path --- wulpus/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wulpus/main.py b/wulpus/main.py index 470a239..7d8f445 100644 --- a/wulpus/main.py +++ b/wulpus/main.py @@ -104,7 +104,7 @@ def list_logs() -> List[str]: return [] -@app.get("/api/logs/{filename}") +@app.get("/logs/{filename}") def download_log(filename: str): """Download a specific measurement file by filename.""" ensure_dir(MEASUREMENTS_DIR) From be5dc7b441c9d4f35363e03b8742bbb83863b2ce Mon Sep 17 00:00:00 2001 From: Louis Date: Thu, 28 Aug 2025 11:20:36 -0700 Subject: [PATCH 24/51] Add a build-script that works on os-independent --- wulpus-frontend/build.py | 34 ++++++++++++++++++++++++++++++++++ wulpus-frontend/build.sh | 2 -- 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 wulpus-frontend/build.py delete mode 100644 wulpus-frontend/build.sh diff --git a/wulpus-frontend/build.py b/wulpus-frontend/build.py new file mode 100644 index 0000000..011c479 --- /dev/null +++ b/wulpus-frontend/build.py @@ -0,0 +1,34 @@ +import os +import shutil + +if __name__ == "__main__": + currentPath = os.path.dirname(os.path.abspath(__file__)) + destPath = os.path.abspath(os.path.join( + currentPath, '..', 'wulpus', 'production-frontend')) + os.chdir(currentPath) + + print("Starting build process...") + build_result = os.system("npm run build") + + if build_result != 0: + print( + f"Build failed with exit code {build_result}. Aborting copy operation.") + exit(build_result) + + print("Build succeeded. Proceeding to copy files...") + + # Clearing the destination path if it exists, preserving .gitignore + if os.path.exists(destPath): + print(f"Clearing destination directory: {destPath}") + for item in os.listdir(destPath): + if item != '.gitignore': + item_path = os.path.join(destPath, item) + if os.path.isdir(item_path): + shutil.rmtree(item_path) + else: + os.remove(item_path) + + print("Copying built files to production directory...") + shutil.copytree("dist", destPath, dirs_exist_ok=True) + print(f"Successfully copied files to {destPath}") + print("Successfully Finished!") diff --git a/wulpus-frontend/build.sh b/wulpus-frontend/build.sh deleted file mode 100644 index ca39ade..0000000 --- a/wulpus-frontend/build.sh +++ /dev/null @@ -1,2 +0,0 @@ -npm run build -cp -r dist/* ../wulpus/production-frontend \ No newline at end of file From a127b527714b48cec01e54c633852c4d97ced976 Mon Sep 17 00:00:00 2001 From: Louis Date: Thu, 28 Aug 2025 15:17:17 -0700 Subject: [PATCH 25/51] - Restructure project to nicely integrate new GUI - Add documentation for new GUI / wulpus controller --- .gitignore | 1 + README.md | 2 +- docs/CHANGELOG.md | 11 + .../images/v1_2/Gui-Screenshot-2025-08-28.png | Bin 0 -> 275114 bytes docs/images/v1_2/WULPUS-GUI Schema.excalidraw | 789 ++++++++++++++++++ docs/images/v1_2/WULPUS-GUI Schema.png | Bin 0 -> 396798 bytes sw/CHANGELOG.md | 20 + sw/HOW_TO_INSTALL.md | 31 + sw/LICENSE | 2 - sw/README.md | 60 +- sw/how_to_install_dependencies.md | 23 - sw/{ => jupyter notebook (legacy)}/.gitignore | 4 +- sw/jupyter notebook (legacy)/LICENSE | 70 ++ .../examples/data_0.npz | Bin .../examples/tx_rx_configs.json | 0 .../examples/uss_config.json | 0 .../wulpus_gui.ipynb | 14 +- .../wulpus_jptnbk}/__init__.py | 0 .../wulpus_jptnbk}/config_package.py | 0 .../wulpus_jptnbk}/dongle.py | 86 +- .../wulpus_jptnbk}/dongle_mock.py | 10 +- .../wulpus_jptnbk}/gui.py | 2 +- .../wulpus_jptnbk}/rx_tx_conf.py | 75 +- .../wulpus_jptnbk}/rx_tx_conf_gui.py | 128 +-- .../wulpus_jptnbk/test_rx_tx_conf.py | 188 +++++ .../wulpus_jptnbk}/uss_conf.py | 138 +-- .../wulpus_jptnbk}/uss_conf_gui.py | 103 ++- sw/requirements.yml | Bin 508 -> 238 bytes .../wulpus-frontend}/.gitignore | 0 .../wulpus-frontend}/README.md | 0 .../wulpus-frontend}/build.py | 0 .../wulpus-frontend}/eslint.config.js | 0 .../wulpus-frontend}/index.html | 0 .../wulpus-frontend}/package-lock.json | 0 .../wulpus-frontend}/package.json | 0 .../wulpus-frontend}/public/vite.svg | 0 .../wulpus-frontend}/src/App.tsx | 0 .../wulpus-frontend}/src/ConfigFilesPanel.tsx | 0 .../wulpus-frontend}/src/ConnectionPanel.tsx | 0 .../wulpus-frontend}/src/Fields.tsx | 0 .../wulpus-frontend}/src/Graph.tsx | 0 .../wulpus-frontend}/src/LogsPage.tsx | 0 .../wulpus-frontend}/src/MultiNumField.tsx | 0 .../wulpus-frontend}/src/TxRxConfig.tsx | 0 .../wulpus-frontend}/src/UsConfig.tsx | 0 .../wulpus-frontend}/src/api.ts | 0 .../wulpus-frontend}/src/assets/react.svg | 0 .../wulpus-frontend}/src/helper.ts | 0 .../wulpus-frontend}/src/index.css | 0 .../wulpus-frontend}/src/main.tsx | 0 .../wulpus-frontend}/src/vite-env.d.ts | 0 .../wulpus-frontend}/src/websocket-types.ts | 0 .../wulpus-frontend}/tsconfig.app.json | 0 .../wulpus-frontend}/tsconfig.json | 0 .../wulpus-frontend}/tsconfig.node.json | 0 .../wulpus-frontend}/vite.config.ts | 0 {wulpus => sw/wulpus}/configs/.gitignore | 0 sw/wulpus/dongle.py | 86 +- sw/wulpus/dongle_mock.py | 8 +- {wulpus => sw/wulpus}/helper.py | 0 {wulpus => sw/wulpus}/main.py | 15 +- {wulpus => sw/wulpus}/measurements/.gitignore | 0 .../wulpus}/production-frontend/.gitignore | 0 {wulpus => sw/wulpus}/websocket_manager.py | 0 {wulpus => sw/wulpus}/wulpus.py | 0 {wulpus => sw/wulpus}/wulpus_api.py | 0 {wulpus => sw/wulpus}/wulpus_api_helper.py | 0 {wulpus => sw/wulpus}/wulpus_config_models.py | 0 {wulpus => sw/wulpus}/wulpus_mock.py | 0 69 files changed, 1569 insertions(+), 297 deletions(-) create mode 100644 docs/images/v1_2/Gui-Screenshot-2025-08-28.png create mode 100644 docs/images/v1_2/WULPUS-GUI Schema.excalidraw create mode 100644 docs/images/v1_2/WULPUS-GUI Schema.png create mode 100644 sw/HOW_TO_INSTALL.md delete mode 100644 sw/how_to_install_dependencies.md rename sw/{ => jupyter notebook (legacy)}/.gitignore (90%) create mode 100644 sw/jupyter notebook (legacy)/LICENSE rename sw/{ => jupyter notebook (legacy)}/examples/data_0.npz (100%) rename sw/{ => jupyter notebook (legacy)}/examples/tx_rx_configs.json (100%) rename sw/{ => jupyter notebook (legacy)}/examples/uss_config.json (100%) rename sw/{ => jupyter notebook (legacy)}/wulpus_gui.ipynb (96%) rename {wulpus => sw/jupyter notebook (legacy)/wulpus_jptnbk}/__init__.py (100%) rename sw/{wulpus => jupyter notebook (legacy)/wulpus_jptnbk}/config_package.py (100%) rename {wulpus => sw/jupyter notebook (legacy)/wulpus_jptnbk}/dongle.py (68%) rename {wulpus => sw/jupyter notebook (legacy)/wulpus_jptnbk}/dongle_mock.py (89%) rename sw/{wulpus => jupyter notebook (legacy)/wulpus_jptnbk}/gui.py (99%) rename sw/{wulpus => jupyter notebook (legacy)/wulpus_jptnbk}/rx_tx_conf.py (60%) rename sw/{wulpus => jupyter notebook (legacy)/wulpus_jptnbk}/rx_tx_conf_gui.py (81%) create mode 100644 sw/jupyter notebook (legacy)/wulpus_jptnbk/test_rx_tx_conf.py rename sw/{wulpus => jupyter notebook (legacy)/wulpus_jptnbk}/uss_conf.py (55%) rename sw/{wulpus => jupyter notebook (legacy)/wulpus_jptnbk}/uss_conf_gui.py (76%) rename {wulpus-frontend => sw/wulpus-frontend}/.gitignore (100%) rename {wulpus-frontend => sw/wulpus-frontend}/README.md (100%) rename {wulpus-frontend => sw/wulpus-frontend}/build.py (100%) rename {wulpus-frontend => sw/wulpus-frontend}/eslint.config.js (100%) rename {wulpus-frontend => sw/wulpus-frontend}/index.html (100%) rename {wulpus-frontend => sw/wulpus-frontend}/package-lock.json (100%) rename {wulpus-frontend => sw/wulpus-frontend}/package.json (100%) rename {wulpus-frontend => sw/wulpus-frontend}/public/vite.svg (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/App.tsx (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/ConfigFilesPanel.tsx (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/ConnectionPanel.tsx (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/Fields.tsx (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/Graph.tsx (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/LogsPage.tsx (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/MultiNumField.tsx (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/TxRxConfig.tsx (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/UsConfig.tsx (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/api.ts (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/assets/react.svg (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/helper.ts (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/index.css (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/main.tsx (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/vite-env.d.ts (100%) rename {wulpus-frontend => sw/wulpus-frontend}/src/websocket-types.ts (100%) rename {wulpus-frontend => sw/wulpus-frontend}/tsconfig.app.json (100%) rename {wulpus-frontend => sw/wulpus-frontend}/tsconfig.json (100%) rename {wulpus-frontend => sw/wulpus-frontend}/tsconfig.node.json (100%) rename {wulpus-frontend => sw/wulpus-frontend}/vite.config.ts (100%) rename {wulpus => sw/wulpus}/configs/.gitignore (100%) rename {wulpus => sw/wulpus}/helper.py (100%) rename {wulpus => sw/wulpus}/main.py (95%) rename {wulpus => sw/wulpus}/measurements/.gitignore (100%) rename {wulpus => sw/wulpus}/production-frontend/.gitignore (100%) rename {wulpus => sw/wulpus}/websocket_manager.py (100%) rename {wulpus => sw/wulpus}/wulpus.py (100%) rename {wulpus => sw/wulpus}/wulpus_api.py (100%) rename {wulpus => sw/wulpus}/wulpus_api_helper.py (100%) rename {wulpus => sw/wulpus}/wulpus_config_models.py (100%) rename {wulpus => sw/wulpus}/wulpus_mock.py (100%) diff --git a/.gitignore b/.gitignore index 2fa3ad2..61d65b6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ __pycache__/ .ipynb_checkpoints/ .vscode *.clangd +sw/.venv \ No newline at end of file diff --git a/README.md b/README.md index ed75403..293d1b3 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ Thanks to all the people who contributed to the WULPUS platform: - [Cédric Hirschi](https://www.linkedin.com/in/c%C3%A9dric-cyril-hirschi-09624021b/) (GUI improvements, Documentation) - [Josquin Tille](https://www.linkedin.com/in/josquin-tille-829a341a7/) (Silicone package design, Documentation) - [William Bruderer](https://www.linkedin.com/in/william-bruderer-59ba9b26b/) (Documentation) - +- [Louis Dod](https://github.com/13Bytes) (GUI Rework) # License The following files are released under Apache License 2.0 (`Apache-2.0`) (see `sw/LICENSE`): diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index fc11f0a..00e6b43 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +## [1.3.0] - 2025-08-28 + +### Added +- New GUI with replay-functionality and extended logging, which is running in the browser +- This required a new API, which structures the way of communicating with the wulpus-server + +(More details can be found in the [sw-changelog](../sw/CHANGELOG.md)) + + ## [1.2.0] - 2025-01-27 ### Added diff --git a/docs/images/v1_2/Gui-Screenshot-2025-08-28.png b/docs/images/v1_2/Gui-Screenshot-2025-08-28.png new file mode 100644 index 0000000000000000000000000000000000000000..d6944ac9c146dfff7b8c0c3e7c55f50b578f6576 GIT binary patch literal 275114 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,oM$f%OAal$J+3&BcB+G$QW8x6A@Q> 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 Pc_jE5^V4}JFW&hdv|V1> literal 0 HcmV?d00001 diff --git a/docs/images/v1_2/WULPUS-GUI Schema.excalidraw b/docs/images/v1_2/WULPUS-GUI Schema.excalidraw new file mode 100644 index 0000000..091b843 --- /dev/null +++ b/docs/images/v1_2/WULPUS-GUI Schema.excalidraw @@ -0,0 +1,789 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "jPdU1jb5kVGYWfPUXAc5O", + "type": "rectangle", + "x": 685.0299006426962, + "y": 125.91071428571422, + "width": 307.7800180377142, + "height": 508.11959271093707, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2v", + "roundness": { + "type": 3 + }, + "seed": 700920572, + "version": 529, + "versionNonce": 1417373252, + "isDeleted": false, + "boundElements": null, + "updated": 1756414553923, + "link": null, + "locked": false + }, + { + "id": "UHd-JASnTQjamf7Hgt_4T", + "type": "rectangle", + "x": 1230.7657789529137, + "y": 125.91071428571422, + "width": 307.7800180377142, + "height": 508.11959271093707, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2vV", + "roundness": { + "type": 3 + }, + "seed": 979099332, + "version": 632, + "versionNonce": 1456076412, + "isDeleted": false, + "boundElements": null, + "updated": 1756414625332, + "link": null, + "locked": false + }, + { + "id": "UAlcJpzVRJ4QUx1YtSybs", + "type": "rectangle", + "x": 216.48605596497595, + "y": 311, + "width": 257.99999999999994, + "height": 79.5, + "angle": 0, + "strokeColor": "#2f9e44", + "backgroundColor": "#ebfbee", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3H", + "roundness": { + "type": 3 + }, + "seed": 491181052, + "version": 199, + "versionNonce": 1810713284, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "5dvg4PSHdFq6vgjCHchhv" + }, + { + "id": "UYTEl3HNKB9YW1B2YPWTy", + "type": "arrow" + } + ], + "updated": 1756414593355, + "link": null, + "locked": false + }, + { + "id": "5dvg4PSHdFq6vgjCHchhv", + "type": "text", + "x": 304.38605749085485, + "y": 338.25, + "width": 82.19999694824219, + "height": 25, + "angle": 0, + "strokeColor": "#2f9e44", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3HV", + "roundness": null, + "seed": 1584157252, + "version": 155, + "versionNonce": 687821380, + "isDeleted": false, + "boundElements": null, + "updated": 1756414593355, + "link": null, + "locked": false, + "text": "WULPUS", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "UAlcJpzVRJ4QUx1YtSybs", + "originalText": "WULPUS", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "aicTJwpX3HBd6wX1U_set", + "type": "rectangle", + "x": 711.25, + "y": 204.875, + "width": 244, + "height": 301, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "#fff5f5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3J", + "roundness": { + "type": 3 + }, + "seed": 244069572, + "version": 273, + "versionNonce": 1454411772, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "g7pc0dSzVyc2BTLmlVnSH" + }, + { + "id": "tGLmrIuHDjucy9RIeZgk0", + "type": "arrow" + }, + { + "id": "tP2Piw3sYenobd6tqpDke", + "type": "arrow" + }, + { + "id": "By8rkj2BBDVPz_GXWFfD2", + "type": "arrow" + }, + { + "id": "UYTEl3HNKB9YW1B2YPWTy", + "type": "arrow" + } + ], + "updated": 1756414588051, + "link": null, + "locked": false + }, + { + "id": "g7pc0dSzVyc2BTLmlVnSH", + "type": "text", + "x": 785.75, + "y": 330.375, + "width": 95, + "height": 50, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3JV", + "roundness": null, + "seed": 428156740, + "version": 226, + "versionNonce": 1344080124, + "isDeleted": false, + "boundElements": null, + "updated": 1756414475378, + "link": null, + "locked": false, + "text": "FastAPI\nwebserver", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "aicTJwpX3HBd6wX1U_set", + "originalText": "FastAPI\nwebserver", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "jPawIbEJ3ti-Sq1EQ-UYg", + "type": "rectangle", + "x": 1269.9444444444443, + "y": 198.5, + "width": 231.87499999999997, + "height": 308.125, + "angle": 0, + "strokeColor": "#f08c00", + "backgroundColor": "#fff4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3U", + "roundness": { + "type": 3 + }, + "seed": 210590460, + "version": 217, + "versionNonce": 754984900, + "isDeleted": false, + "boundElements": [ + { + "id": "tP2Piw3sYenobd6tqpDke", + "type": "arrow" + }, + { + "id": "By8rkj2BBDVPz_GXWFfD2", + "type": "arrow" + }, + { + "id": "tGLmrIuHDjucy9RIeZgk0", + "type": "arrow" + }, + { + "type": "text", + "id": "S9DgnVr68FP88TdTMS0Ya" + } + ], + "updated": 1756414538207, + "link": null, + "locked": false + }, + { + "id": "S9DgnVr68FP88TdTMS0Ya", + "type": "text", + "x": 1341.6652772691514, + "y": 340.0625, + "width": 88.43333435058594, + "height": 25, + "angle": 0, + "strokeColor": "#f08c00", + "backgroundColor": "#fff4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3V", + "roundness": null, + "seed": 290211324, + "version": 10, + "versionNonce": 559168252, + "isDeleted": false, + "boundElements": null, + "updated": 1756414541155, + "link": null, + "locked": false, + "text": "Frontend", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "jPawIbEJ3ti-Sq1EQ-UYg", + "originalText": "Frontend", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "IdcqPXT68DdIYN97wT6x-", + "type": "text", + "x": 690.7982175404507, + "y": 579.1270427635059, + "width": 288.77465759279767, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3Y", + "roundness": null, + "seed": 673199556, + "version": 146, + "versionNonce": 1342705660, + "isDeleted": false, + "boundElements": null, + "updated": 1756414553923, + "link": null, + "locked": false, + "text": "Python Application", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Python Application", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "5esIhToI6QZoLIqrqHKMV", + "type": "text", + "x": 1240.534095850668, + "y": 579.1270427635059, + "width": 288.77465759279767, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3YV", + "roundness": null, + "seed": 283729788, + "version": 250, + "versionNonce": 1421075836, + "isDeleted": false, + "boundElements": null, + "updated": 1756414562253, + "link": null, + "locked": false, + "text": "Browser", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Browser", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "tGLmrIuHDjucy9RIeZgk0", + "type": "arrow", + "x": 1260.471781201171, + "y": 230.0817419144514, + "width": 298.5279441365715, + "height": 112.76141768656214, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3Z", + "roundness": { + "type": 2 + }, + "seed": 1822283844, + "version": 1881, + "versionNonce": 2002214396, + "isDeleted": false, + "boundElements": [], + "updated": 1756414491315, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -298.5279441365715, + 58.967178284190425 + ], + [ + -7.285090710609666, + 112.76141768656214 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "jPawIbEJ3ti-Sq1EQ-UYg", + "focus": 0.9032954151386535, + "gap": 24.725245945377143 + }, + "endBinding": { + "elementId": "jPawIbEJ3ti-Sq1EQ-UYg", + "focus": -0.08681224372011292, + "gap": 16.75775395388291 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "tP2Piw3sYenobd6tqpDke", + "type": "arrow", + "x": 1249.4087301587304, + "y": 461.625, + "width": 285.21807343442003, + "height": 5.590534355697173, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3d", + "roundness": { + "type": 2 + }, + "seed": 1545679100, + "version": 286, + "versionNonce": 1716279236, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "F9HUJDxWUXFT91cm8B9I1" + } + ], + "updated": 1756414507739, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -118.97086111821886, + -2.775030077020915 + ], + [ + -285.21807343442003, + -5.590534355697173 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "jPawIbEJ3ti-Sq1EQ-UYg", + "focus": -0.7079107505070995, + "gap": 20.535714285713993 + }, + "endBinding": { + "elementId": "aicTJwpX3HBd6wX1U_set", + "focus": 0.6452407783098888, + "gap": 8.940656724310315 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "F9HUJDxWUXFT91cm8B9I1", + "type": "text", + "x": 1023.2039702884736, + "y": 448.05357142857144, + "width": 175.26666259765625, + "height": 50, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3e", + "roundness": null, + "seed": 242752580, + "version": 34, + "versionNonce": 445604860, + "isDeleted": false, + "boundElements": null, + "updated": 1756414452410, + "link": null, + "locked": false, + "text": "HTTP-Requests:\nControl-Commands", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "tP2Piw3sYenobd6tqpDke", + "originalText": "HTTP-Requests:\nControl-Commands", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "By8rkj2BBDVPz_GXWFfD2", + "type": "arrow", + "x": 1252.1146744607227, + "y": 383.33928571428567, + "width": 285.0446427033604, + "height": 5.684341886080802e-14, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3f", + "roundness": { + "type": 2 + }, + "seed": 1566373756, + "version": 266, + "versionNonce": 1638443388, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "U_MbWvQ6P8tlbdHpFXDuX" + } + ], + "updated": 1756414489731, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -285.0446427033604, + 5.684341886080802e-14 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "jPawIbEJ3ti-Sq1EQ-UYg", + "focus": -0.19976818313532244, + "gap": 17.82976998372169 + }, + "endBinding": { + "elementId": "aicTJwpX3HBd6wX1U_set", + "focus": 0.18580920740389203, + "gap": 11.820031757362244 + }, + "startArrowhead": "arrow", + "endArrowhead": null, + "elbowed": false + }, + { + "id": "U_MbWvQ6P8tlbdHpFXDuX", + "type": "text", + "x": 1058.0920645093163, + "y": 358.3392857142857, + "width": 107.63333129882812, + "height": 50, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3g", + "roundness": null, + "seed": 1823297092, + "version": 97, + "versionNonce": 796492924, + "isDeleted": false, + "boundElements": null, + "updated": 1756414452410, + "link": null, + "locked": false, + "text": "Websocket:\nLive Data", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "By8rkj2BBDVPz_GXWFfD2", + "originalText": "Websocket:\nLive Data", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "aD8wO18I7_fn9Tmirltaj", + "type": "text", + "x": 1000.0010034476036, + "y": 276.7335078889831, + "width": 258.73333740234375, + "height": 25, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3k", + "roundness": null, + "seed": 121111036, + "version": 430, + "versionNonce": 1110184260, + "isDeleted": false, + "boundElements": [ + { + "id": "tGLmrIuHDjucy9RIeZgk0", + "type": "arrow" + } + ], + "updated": 1756414452410, + "link": null, + "locked": false, + "text": "HTTP Request of website", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "HTTP Request of website", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "UYTEl3HNKB9YW1B2YPWTy", + "type": "arrow", + "x": 484.4205657155102, + "y": 349.5239647449018, + "width": 219.8943513240872, + "height": 1.8635114518990576, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "#fff4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3n", + "roundness": { + "type": 2 + }, + "seed": 1712324164, + "version": 123, + "versionNonce": 1924452860, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "qibzpqX5KROlu4MDgqob6" + } + ], + "updated": 1756414603883, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 219.8943513240872, + 1.8635114518990576 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "UAlcJpzVRJ4QUx1YtSybs", + "focus": -0.03084365421630684, + "gap": 9.93450975053429 + }, + "endBinding": { + "elementId": "aicTJwpX3HBd6wX1U_set", + "focus": 0.019103670142447363, + "gap": 6.93508296040261 + }, + "startArrowhead": "arrow", + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "qibzpqX5KROlu4MDgqob6", + "type": "text", + "x": 538.6670574147562, + "y": 337.02396474490183, + "width": 131.89999389648438, + "height": 25, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "#fff4e6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3o", + "roundness": null, + "seed": 1835258876, + "version": 4, + "versionNonce": 1563843524, + "isDeleted": false, + "boundElements": null, + "updated": 1756414603883, + "link": null, + "locked": false, + "text": "Bluetooth LE", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "UYTEl3HNKB9YW1B2YPWTy", + "originalText": "Bluetooth LE", + "autoResize": true, + "lineHeight": 1.25 + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": false, + "viewBackgroundColor": "#ffffff", + "lockedMultiSelections": {} + }, + "files": {} +} \ No newline at end of file diff --git a/docs/images/v1_2/WULPUS-GUI Schema.png b/docs/images/v1_2/WULPUS-GUI Schema.png new file mode 100644 index 0000000000000000000000000000000000000000..314c5062d4c2af659fee0965a09e7da0b9cbf0d1 GIT binary patch literal 396798 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