From 4d02028b40e6c00722ac368f31045dbc0672f72f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 22:11:04 +0000 Subject: [PATCH] deploy: 4fb0ae6c3040a4fd1dc3cc58ac3f8e8993eed3d3 --- .nojekyll | 0 api/callbacks.html | 1418 ++++ api/configs.html | 1917 +++++ api/inout.html | 741 ++ api/metadata.html | 1070 +++ api/nc_template.html | 1218 +++ api/serializers.html | 1308 ++++ api/utils.html | 1973 +++++ cli/create_nc_template.html | 729 ++ cli/init.html | 752 ++ cli/netcdfy.html | 787 ++ handlers/geotraces.html | 2853 +++++++ handlers/helcom.html | 6746 +++++++++++++++++ handlers/maris_legacy.html | 3945 ++++++++++ handlers/netcdf_to_csv.html | 3820 ++++++++++ img/logo.png | Bin 0 -> 106866 bytes index.html | 815 ++ robots.txt | 1 + search.json | 844 +++ site_libs/bootstrap/bootstrap-icons.css | 2078 +++++ site_libs/bootstrap/bootstrap-icons.woff | Bin 0 -> 176200 bytes site_libs/bootstrap/bootstrap.min.css | 12 + site_libs/bootstrap/bootstrap.min.js | 7 + site_libs/clipboard/clipboard.min.js | 7 + site_libs/quarto-html/anchor.min.js | 9 + site_libs/quarto-html/popper.min.js | 6 + .../quarto-syntax-highlighting.css | 205 + site_libs/quarto-html/quarto.js | 908 +++ site_libs/quarto-html/tippy.css | 1 + site_libs/quarto-html/tippy.umd.min.js | 2 + site_libs/quarto-nav/headroom.min.js | 7 + site_libs/quarto-nav/quarto-nav.js | 325 + site_libs/quarto-search/autocomplete.umd.js | 3 + site_libs/quarto-search/fuse.min.js | 9 + site_libs/quarto-search/quarto-search.js | 1290 ++++ sitemap.xml | 63 + styles.css | 68 + 37 files changed, 35937 insertions(+) create mode 100644 .nojekyll create mode 100644 api/callbacks.html create mode 100644 api/configs.html create mode 100644 api/inout.html create mode 100644 api/metadata.html create mode 100644 api/nc_template.html create mode 100644 api/serializers.html create mode 100644 api/utils.html create mode 100644 cli/create_nc_template.html create mode 100644 cli/init.html create mode 100644 cli/netcdfy.html create mode 100644 handlers/geotraces.html create mode 100644 handlers/helcom.html create mode 100644 handlers/maris_legacy.html create mode 100644 handlers/netcdf_to_csv.html create mode 100644 img/logo.png create mode 100644 index.html create mode 100644 robots.txt create mode 100644 search.json create mode 100644 site_libs/bootstrap/bootstrap-icons.css create mode 100644 site_libs/bootstrap/bootstrap-icons.woff create mode 100644 site_libs/bootstrap/bootstrap.min.css create mode 100644 site_libs/bootstrap/bootstrap.min.js create mode 100644 site_libs/clipboard/clipboard.min.js create mode 100644 site_libs/quarto-html/anchor.min.js create mode 100644 site_libs/quarto-html/popper.min.js create mode 100644 site_libs/quarto-html/quarto-syntax-highlighting.css create mode 100644 site_libs/quarto-html/quarto.js create mode 100644 site_libs/quarto-html/tippy.css create mode 100644 site_libs/quarto-html/tippy.umd.min.js create mode 100644 site_libs/quarto-nav/headroom.min.js create mode 100644 site_libs/quarto-nav/quarto-nav.js create mode 100644 site_libs/quarto-search/autocomplete.umd.js create mode 100644 site_libs/quarto-search/fuse.min.js create mode 100644 site_libs/quarto-search/quarto-search.js create mode 100644 sitemap.xml create mode 100644 styles.css diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/api/callbacks.html b/api/callbacks.html new file mode 100644 index 0000000..d87bf08 --- /dev/null +++ b/api/callbacks.html @@ -0,0 +1,1418 @@ + + + + + + + + + + +Callbacks – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+ +
+ +
+
+ Callback used in handlers +
+
+ + +
+ + + + +
+ + + +
+ + + +
+
+Exported source +
import copy
+import fastcore.all as fc
+from operator import attrgetter
+from cftime import date2num
+import numpy as np
+import pandas as pd
+from marisco.configs import cfg, cdl_cfg
+from functools import partial 
+from typing import List, Dict, Callable, Tuple
+from pathlib import Path 
+
+from marisco.configs import get_lut, nuc_lut_path
+
+
+
+

Core

+

The Transformer class is designed to facilitate the application of a series of callbacks to a set of dataframes. It provides a structured way to apply transformations (i.e Callback) to the data, with a focus on flexibility and ease of use.

+
+

source

+
+

Callback

+
+
 Callback ()
+
+

Base class for callbacks.

+
+
+Exported source +
class Callback(): 
+    "Base class for callbacks."
+    order = 0
+
+
+
+

source

+
+
+

run_cbs

+
+
 run_cbs (cbs, obj=None)
+
+

Run the callbacks in the order they are specified.

+
+
+Exported source +
def run_cbs(cbs, obj=None):
+    "Run the callbacks in the order they are specified."
+    for cb in sorted(cbs, key=attrgetter('order')):
+        if cb.__doc__: obj.logs.append(cb.__doc__)
+        cb(obj)
+
+
+
+

source

+
+
+

Transformer

+
+
 Transformer (dfs:pandas.core.frame.DataFrame, cbs:list=None,
+              inplace:bool=False)
+
+

Transform the dataframes according to the specified callbacks.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
dfsDataFrameDictionary of DataFrames to transform
cbslistNoneList of callbacks to run
inplaceboolFalseWhether to modify the dataframes in place
+
+
+Exported source +
class Transformer():
+    def __init__(self, 
+                 dfs:pd.DataFrame, # Dictionary of DataFrames to transform
+                 cbs:list=None, # List of callbacks to run
+                 inplace:bool=False # Whether to modify the dataframes in place
+                 ): 
+        "Transform the dataframes according to the specified callbacks."
+        fc.store_attr()
+        self.dfs = dfs if inplace else {k: v.copy() for k, v in dfs.items()}
+        self.logs = []
+            
+    def unique(self, col_name):
+        "Distinct values of a specific column present in all groups."
+        columns = [df.get(col_name) for df in self.dfs.values() if df.get(col_name) is not None]
+        values = np.concatenate(columns) if columns else []
+        return np.unique(values)
+        
+    def __call__(self):
+        "Transform the dataframes according to the specified callbacks."
+        if self.cbs: run_cbs(self.cbs, self)
+        return self.dfs
+
+
+

Below, a few examples of how to use the Transformer class. Let’s define first a test callback that adds 1 to the depth:

+
+
class TestCB(Callback):
+    "A test callback to add 1 to the depth."
+    def __call__(self, tfm):
+        for grp, df in tfm.dfs.items(): 
+            df['depth'] = df['depth'].apply(lambda x: x+1)
+
+

And apply it to the following dataframes:

+
+
dfs = {'biota': pd.DataFrame({'id': [0, 1, 2], 'species': [0, 2, 0], 'depth': [2, 3, 4]}),
+       'seawater': pd.DataFrame({'id': [0, 1, 2], 'depth': [3, 4, 5]})}
+
+tfm = Transformer(dfs, cbs=[TestCB()])
+df_test = tfm()
+
+fc.test_eq(df_test['biota']['depth'].to_list(), [3, 4, 5])
+fc.test_eq(df_test['seawater']['depth'].to_list(), [4, 5, 6])
+
+
+
+
+

Geographical

+

This section gathers callbacks that are used to transform the geographical coordinates.

+
+

source

+
+

SanitizeLonLatCB

+
+
 SanitizeLonLatCB (verbose=False)
+
+

Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude , separator to . separator.

+
+
+Exported source +
class SanitizeLonLatCB(Callback):
+    "Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator."
+    def __init__(self, verbose=False): fc.store_attr()
+    def __call__(self, tfm):
+        for grp, df in tfm.dfs.items():
+            " Convert `,` separator to `.` separator"
+            df['lon'] = [float(str(x).replace(',', '.')) for x in df['lon']]
+            df['lat'] = [float(str(x).replace(',', '.')) for x in df['lat']]
+            
+            # mask zero values
+            mask_zeroes = (df.lon == 0) & (df.lat == 0) 
+            nZeroes = mask_zeroes.sum()
+            if nZeroes and self.verbose: 
+                print(f'The "{grp}" group contains {nZeroes} data points whose (lon, lat) = (0, 0)')
+            
+            # mask gps out of bounds, goob. 
+            mask_goob = (df.lon < -180) | (df.lon > 180) | (df.lat < -90) | (df.lat > 90)
+            nGoob = mask_goob.sum()
+            if nGoob and self.verbose: 
+                print(f'The "{grp}" group contains {nGoob} data points whose lon or lat are unrealistic. Outside -90 to 90 for latitude and -180 to 180 for longitude.')
+                
+            tfm.dfs[grp] = df.loc[~(mask_zeroes | mask_goob)]
+
+
+
+
# Check that measurements located at (0,0) get removed
+dfs = {'biota': pd.DataFrame({'lon': [0, 1, 0], 'lat': [0, 2, 0]})}
+tfm = Transformer(dfs, cbs=[SanitizeLonLatCB()])
+tfm()['biota']
+
+expected = [1., 2.]
+fc.test_eq(tfm()['biota'].iloc[0].to_list(), expected)
+
+
+
# Check that comma decimal separator get replaced by point instead
+dfs = {'biota': pd.DataFrame({'lon': ['45,2'], 'lat': ['43,1']})}
+tfm = Transformer(dfs, cbs=[SanitizeLonLatCB()])
+tfm()['biota']
+
+expected = [45.2, 43.1]
+fc.test_eq(tfm()['biota'].iloc[0].to_list(), expected)
+
+
+
# Check that out of bounds lon or lat get removed
+dfs = {'biota': pd.DataFrame({'lon': [-190, 190, 1, 2, 1.1], 'lat': [1, 2, 91, -91, 2.2]})}
+tfm = Transformer(dfs, cbs=[SanitizeLonLatCB()])
+tfm()['biota']
+
+expected = [1.1, 2.2]
+fc.test_eq(tfm()['biota'].iloc[0].to_list(), expected)
+
+
+
+
+

Add columns

+

This section gathers callbacks that are used to add required columns to the dataframes.

+
+

source

+
+

AddSampleTypeIdColumnCB

+
+
 AddSampleTypeIdColumnCB (cdl_cfg:Callable=<function cdl_cfg>,
+                          col_name:str='samptype_id')
+
+

Base class for callbacks.

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
cdl_cfgCallablecdl_cfgCallable to get the CDL config dictionary
col_namestrsamptype_id
+
+
+Exported source +
class AddSampleTypeIdColumnCB(Callback):
+    def __init__(self, 
+                 cdl_cfg:Callable=cdl_cfg, # Callable to get the CDL config dictionary
+                 col_name:str='samptype_id'
+                 ): 
+        "Add a column with the sample type id as defined in the CDL."
+        fc.store_attr()
+        self.lut = {v['name']: v['id'] for v in cdl_cfg()['grps'].values()}
+        
+    def __call__(self, tfm):
+        for grp, df in tfm.dfs.items(): df[self.col_name] = self.lut[grp]
+
+
+

Let’s test the callback:

+
+
dfs = {v['name']: pd.DataFrame({'col_test': [0, 1, 2]}) for v in CONFIGS_CDL['grps'].values()}
+
+tfm = Transformer(dfs, cbs=[AddSampleTypeIdColumnCB(cdl_cfg=lambda: CONFIGS_CDL)])
+dfs_test = tfm()
+
+for v in CONFIGS_CDL['grps'].values():
+    fc.test_eq(dfs_test[v['name']]['samptype_id'].unique().item(), v['id'])
+
+
+

source

+
+
+

AddNuclideIdColumnCB

+
+
 AddNuclideIdColumnCB (col_value:str, lut_fname_fn:<built-
+                       infunctioncallable>=<function nuc_lut_path>,
+                       col_name:str='nuclide_id')
+
+

Base class for callbacks.

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
col_valuestrColumn name containing the nuclide name
lut_fname_fncallablenuc_lut_pathFunction returning the lut path
col_namestrnuclide_idColumn name to store the nuclide id
+
+
+Exported source +
class AddNuclideIdColumnCB(Callback):
+    def __init__(self, 
+                 col_value:str, # Column name containing the nuclide name
+                 lut_fname_fn:callable=nuc_lut_path, # Function returning the lut path
+                 col_name:str='nuclide_id' # Column name to store the nuclide id
+                 ): 
+        "Add a column with the nuclide id."
+        fc.store_attr()
+        self.lut = get_lut(lut_fname_fn().parent, lut_fname_fn().name, 
+                           key='nc_name', value='nuclide_id', reverse=False)
+        
+    def __call__(self, tfm):
+        for grp, df in tfm.dfs.items(): 
+            df[self.col_name] = df[self.col_value].map(self.lut)
+
+
+
+
dfs = {v['name']: pd.DataFrame({'Nuclide': ['cs137', 'pu239_240_tot']}) for v in CONFIGS_CDL['grps'].values()}
+
+lut_fname_fn = lambda: Path('./files/lut/dbo_nuclide.xlsx')
+
+tfm = Transformer(dfs, cbs=[AddNuclideIdColumnCB(col_value='Nuclide', lut_fname_fn=lut_fname_fn)])
+tfm()['seawater']
+
+expected = [33, 77]
+for grp in tfm.dfs.keys():
+    fc.test_eq(tfm.dfs[grp]['nuclide_id'].to_list(), expected)
+
+
+
+
+

Map & Standardize

+
+

source

+
+

LowerStripNameCB

+
+
 LowerStripNameCB (col_src:str, col_dst:str=None,
+                   fn_transform:Callable=<function <lambda>>)
+
+

Base class for callbacks.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
col_srcstrSource column name e.g. ‘Nuclide’
col_dststrNoneDestination column name
fn_transformCallableTransformation function
+
+
+Exported source +
class LowerStripNameCB(Callback):
+    def __init__(self, 
+                 col_src:str, # Source column name e.g. 'Nuclide'
+                 col_dst:str=None, # Destination column name
+                 fn_transform:Callable=lambda x: x.lower().strip() # Transformation function
+                 ):
+        "Convert values to lowercase and strip any trailing spaces."
+        fc.store_attr()
+        self.__doc__ = f"Convert values from '{col_src}' to lowercase, strip spaces, and store in '{col_dst}'."
+        if not col_dst: self.col_dst = col_src
+        
+    def _safe_transform(self, value):
+        "Ensure value is not NA and apply transformation function."
+        return value if pd.isna(value) else self.fn_transform(str(value))
+            
+    def __call__(self, tfm):
+        for key in tfm.dfs.keys():
+            tfm.dfs[key][self.col_dst] = tfm.dfs[key][self.col_src].apply(self._safe_transform)
+
+
+

Let’s test the callback:

+
+
dfs = {'seawater': pd.DataFrame({'Nuclide': ['CS137', '226RA']})}
+
+tfm = Transformer(dfs, cbs=[LowerStripNameCB(col_src='Nuclide', col_dst='NUCLIDE')])
+fc.test_eq(tfm()['seawater']['NUCLIDE'].to_list(), ['cs137', '226ra'])
+
+
+tfm = Transformer(dfs, cbs=[LowerStripNameCB(col_src='Nuclide')])
+fc.test_eq(tfm()['seawater']['Nuclide'].to_list(), ['cs137', '226ra'])
+
+

The point is when (semi-automatic) remapping names generally:

+
    +
  1. we need first to guess (fuzzy matching or other) the right nuclide name.
  2. +
  3. Then manually check the result and eventually update the lookup table.
  4. +
  5. Finally we can apply the lookup table to the dataframe.
  6. +
+
+
+
+

Change structure

+

Many data providers use a long format (e.g lat, lon, radionuclide, value, unc, ...) to store their data. When encoding as netCDF, it is often required to use a wide format (e.g lat, lon, nuclide1_value, nuclide1_unc, nuclide2_value, nuclide2_unc, ...). The class ReshapeLongToWide is designed to perform this transformation.

+
+

source

+
+

ReshapeLongToWide

+
+
 ReshapeLongToWide (columns=['nuclide'], values=['value'],
+                    num_fill_value=-999, str_fill_value='STR FILL VALUE')
+
+

Base class for callbacks.

+
+
+Exported source +
class ReshapeLongToWide(Callback):
+    def __init__(self, columns=['nuclide'], values=['value'], 
+                 num_fill_value=-999, str_fill_value='STR FILL VALUE'):
+        "Convert data from long to wide with renamed columns."
+        fc.store_attr()
+        self.derived_cols = self._get_derived_cols()
+    
+    def _get_derived_cols(self):
+        "Retrieve all possible derived vars (e.g 'unc', 'dl', ...) from configs."
+        return [value['name'] for value in cdl_cfg()['vars']['suffixes'].values()]
+
+    def renamed_cols(self, cols):
+        "Flatten columns name."
+        return [inner if outer == "value" else f'{inner}{outer}' if inner else outer
+                for outer, inner in cols]
+
+    def _get_unique_fill_value(self, df, idx):
+        "Get a unique fill value for NaN replacement."
+        fill_value = self.num_fill_value
+        while (df[idx] == fill_value).any().any():
+            fill_value -= 1
+        return fill_value
+
+    def _fill_nan_values(self, df, idx):
+        "Fill NaN values in index columns."
+        num_fill_value = self._get_unique_fill_value(df, idx)
+        for col in idx:
+            fill_value = num_fill_value if pd.api.types.is_numeric_dtype(df[col]) else self.str_fill_value
+            df[col] = df[col].fillna(fill_value)
+        return df, num_fill_value
+
+    def pivot(self, df):
+        derived_coi = [col for col in self.derived_cols if col in df.columns]
+        df.index.name = 'org_index'
+        df = df.reset_index()
+        idx = list(set(df.columns) - set(self.columns + derived_coi + self.values))
+        
+        df, num_fill_value = self._fill_nan_values(df, idx)
+
+        pivot_df = df.pivot_table(index=idx,
+                                  columns=self.columns,
+                                  values=self.values + derived_coi,
+                                  fill_value=np.nan,
+                                  aggfunc=lambda x: x).reset_index()
+
+        pivot_df[idx] = pivot_df[idx].replace({self.str_fill_value: np.nan, num_fill_value: np.nan})
+        return pivot_df.set_index('org_index')
+
+    def __call__(self, tfm):
+        for grp in tfm.dfs.keys():
+            tfm.dfs[grp] = self.pivot(tfm.dfs[grp])
+            tfm.dfs[grp].columns = self.renamed_cols(tfm.dfs[grp].columns)
+
+
+
+
dfs_test = fc.load_pickle('./files/pkl/dfs_reshape_test_in.pkl')
+dfs_expected = fc.load_pickle('./files/pkl/dfs_reshape_test_expected.pkl')
+
+tfm = Transformer(dfs_test, cbs=[ReshapeLongToWide()])
+dfs_output = tfm()
+test_dfs(dfs_output, dfs_expected)
+
+
+

source

+
+
+

CompareDfsAndTfmCB

+
+
 CompareDfsAndTfmCB (dfs:Dict[str,pandas.core.frame.DataFrame])
+
+

Base class for callbacks.

+
+
+Exported source +
class CompareDfsAndTfmCB(Callback):
+    def __init__(self, dfs: Dict[str, pd.DataFrame]): 
+        "Create a dataframe of dropped data. Data included in the `dfs` not in the `tfm`."
+        fc.store_attr()
+        
+    def __call__(self, tfm: Transformer) -> None:
+        self._initialize_tfm_attributes(tfm)
+        for grp in tfm.dfs.keys():
+            dropped_df = self._get_dropped_data(grp, tfm)
+            tfm.dfs_dropped[grp] = dropped_df
+            tfm.compare_stats[grp] = self._compute_stats(grp, tfm)
+
+    def _initialize_tfm_attributes(self, tfm: Transformer) -> None:
+        tfm.dfs_dropped = {}
+        tfm.compare_stats = {}
+
+    def _get_dropped_data(self, 
+                          grp: str, # The group key
+                          tfm: Transformer # The transformation object containing `dfs`
+                         ) -> pd.DataFrame: # Dataframe with dropped rows
+        "Get the data that is present in `dfs` but not in `tfm.dfs`."
+        index_diff = self.dfs[grp].index.difference(tfm.dfs[grp].index)
+        return self.dfs[grp].loc[index_diff]
+    
+    def _compute_stats(self, 
+                       grp: str, # The group key
+                       tfm: Transformer # The transformation object containing `dfs`
+                      ) -> Dict[str, int]: # Dictionary with comparison statistics
+        "Compute comparison statistics between `dfs` and `tfm.dfs`."
+        return {
+            'Number of rows in dfs': len(self.dfs[grp].index),
+            'Number of rows in tfm.dfs': len(tfm.dfs[grp].index),
+            'Number of dropped rows': len(tfm.dfs_dropped[grp].index),
+            'Number of rows in tfm.dfs + Number of dropped rows': len(tfm.dfs[grp].index) + len(tfm.dfs_dropped[grp].index)
+        }
+
+
+

CompareDfsAndTfmCB compares the original dataframes to the transformed dataframe. A dictionary of dataframes, tfm.dfs_dropped, is created to include the data present in the original dataset but absent from the transformed data. tfm.compare_stats provides a quick overview of the number of rows in both the original dataframes and the transformed dataframe.

+

For instance:

+
+
dfs_test = {
+    'seawater': pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]}),
+    'sediment': pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]}),
+}
+
+class TestTfmCB(Callback):
+    def __call__(self, tfm):
+        for key in tfm.dfs.keys():
+            df = tfm.dfs[key]
+            drop_idxs = [0, 1] if key == 'seawater' else [0]
+            df.drop(drop_idxs, inplace=True)
+            
+tfm = Transformer(dfs_test, cbs=[
+    TestTfmCB(), 
+    CompareDfsAndTfmCB(dfs_test)], inplace=False)
+
+print(tfm())
+
+fc.test_eq(tfm.compare_stats['seawater']['Number of dropped rows'], 2)
+fc.test_eq(tfm.compare_stats['sediment']['Number of dropped rows'], 1)
+
+
{'seawater':    a  b
+2  3  6, 'sediment':    a  b
+1  2  5
+2  3  6}
+
+
+
+
+
+

Time

+

These callbacks are used to transform the time variable according to netCDF CF standards. For instance, the EncodeTimeCB callback is used to encode the time variable as an integer representing seconds since a reference date as specified in configs.ipynb CONFIGS_CDL dictionary.

+
+

source

+
+

EncodeTimeCB

+
+
 EncodeTimeCB (cfg, verbose=False)
+
+

Encode time as int representing seconds since xxx

+
+
+Exported source +
class EncodeTimeCB(Callback):
+    "Encode time as `int` representing seconds since xxx"    
+    def __init__(self, cfg , verbose=False): fc.store_attr()
+    def __call__(self, tfm): 
+        def format_time(x): 
+            return date2num(x, units=self.cfg['units']['time'])
+        
+        for k in tfm.dfs.keys():
+            # If invalid time entries.
+            if tfm.dfs[k]['time'].isna().any():
+                if self.verbose:
+                    invalid_time_df=tfm.dfs[k][tfm.dfs[k]['time'].isna()]
+                    print (f'{len(invalid_time_df.index)} of {len(tfm.dfs[k].index)} entries for `time` are invalid for {k}.')
+                # Filter nan values
+                tfm.dfs[k] = tfm.dfs[k][tfm.dfs[k]['time'].notna()]
+            
+            tfm.dfs[k]['time'] = tfm.dfs[k]['time'].apply(format_time)
+
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/api/configs.html b/api/configs.html new file mode 100644 index 0000000..918f812 --- /dev/null +++ b/api/configs.html @@ -0,0 +1,1917 @@ + + + + + + + + + + +Configs – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+ + +
+
+ Several dictionaries used to generate .toml configuration files copied under /home/.marisco folder and associated utilities function. These .toml files can be then adapted to your specific needs if required. +
+
+ + +
+ + + + +
+ + + +
+ + + +
+
+Exported source +
from pathlib import Path
+import os
+import re
+from functools import partial
+from typing import Union
+
+from marisco.inout import read_toml, write_toml
+import pandas as pd
+import fastcore.all as fc
+
+
+
+

Configuration files

+
+

source

+
+

base_path

+
+
 base_path ()
+
+
+
+Exported source +
CFG_FNAME = 'configs.toml'
+CDL_FNAME = 'cdl.toml'
+NUCLIDE_LOOKUP_FNAME = 'dbo_nuclide.xlsx'
+MARISCO_CFG_DIRNAME = '.marisco'
+
+
+
+
+Exported source +
def base_path(): return Path.home() / MARISCO_CFG_DIRNAME
+
+
+

By default, we create a folder named .marisco under your home directory that will receive all configuration files as defined in BASE_PATH:

+
+
base_path()
+
+
Path('/Users/franckalbinet/.marisco')
+
+
+
+
+Exported source +
CONFIGS = {
+    'gh': {
+        'owner': 'franckalbinet',
+        'repo': 'marisco'
+    },
+    'names': {
+        'nc_template': 'maris-template.nc'
+    },
+    'dirs': {
+        'lut': str(base_path() / 'lut'), # Look-up tables
+        'cache': str(base_path() / 'cache'), # Cache (e.f WoRMS species)
+        'tmp': str(base_path() / 'tmp')
+    },
+    'paths': {
+        'luts': 'nbs/files/lut'
+    },
+    'units': {
+        'time': 'seconds since 1970-01-01 00:00:00.0'
+    },
+    'zotero': {
+        'api_key': os.getenv('ZOTERO_API_KEY'),
+        'lib_id': '2432820'
+    }
+}
+
+
+

The CONFIGS dictionary defines general settings:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
keyValueDescription
dirs/lut/Users/franckalbinet/.marisco/lutLocation & name of the directory receiving lookup tables.
dirs/cache/Users/franckalbinet/.marisco/cacheLocation & name of the directory receiving cache files such as WoRMS species retrieved.
dirs/tmp/Users/franckalbinet/.marisco/tmpLocation & name of temporary files.
gh/ownerfranckalbinetGitHub account owner.
gh/repomariscoGitHub user used to download specific files (e.g lookup tables) during installation.
names/nc_templatemaris-template.ncName of the MARIS NetCDF4 template.
paths_lutsnbs/files/lutGitHub repository directory name containing lookup tables.
units_timeseconds since 1970-01-01 00:00:00.0Reference date and time used for NetCDF time encoding.
zotero/api_keyyour-zotero-api-keyZotero API key (“ZOTERO_API_KEY” environment variable).
zotero/lib_id2432820Zotero library ID.
+

The main CONFIGS_CDL dictionary, used to generate a NetCDF CDL (Common Data Language) .toml file. This file is then used to generate a template MARIS netcdf file. For further details refers to the configs.ipynb file.

+

Below, the vars/defaults section printed:

+
+

source

+
+
+

cfg

+
+
 cfg ()
+
+
+
+Exported source +
def cfg(): return read_toml(base_path() / CFG_FNAME)
+
+
+
+

source

+
+
+

nuc_lut_path

+
+
 nuc_lut_path ()
+
+
+
+Exported source +
def nuc_lut_path(): return Path(cfg()['dirs']['lut']) / NUCLIDE_LOOKUP_FNAME
+
+
+
+

source

+
+
+

lut_path

+
+
 lut_path ()
+
+
+
+Exported source +
def lut_path(): return Path(cfg()['dirs']['lut'])
+
+
+
+

source

+
+
+

cache_path

+
+
 cache_path ()
+
+
+
+Exported source +
def cache_path(): return Path(cfg()['dirs']['cache'])
+
+
+
+
+Exported source +
CONFIGS_CDL = { 
+    'placeholder': '_to_be_filled_in_',
+    'grps': {
+        'sea': {
+            'name': 'seawater',
+            'id': 1
+        },
+        'bio': {
+            'name': 'biota',
+            'id': 2
+        },
+        'sed': {
+            'name': 'sediment',
+            'id': 3
+        },
+        'sus': {
+            'name': 'suspended-matter',
+            'id': 4
+        }
+    },
+    'global_attrs': {
+        # Do not update keys. Only values if required
+        'id': '', # zotero?
+        'title': '',
+        'summary': '',
+        'keywords': '',
+        'keywords_vocabulary': 'GCMD Science Keywords',
+        'keywords_vocabulary_url': 'https://gcmd.earthdata.nasa.gov/static/kms/',
+        'record': '',
+        'featureType': '',
+        'cdm_data_type': '',
+
+        # Conventions
+        'Conventions': 'CF-1.10 ACDD-1.3',
+
+        # Publisher [ACDD1.3]
+        'publisher_name': 'Paul MCGINNITY, Iolanda OSVATH, Florence DESCROIX-COMANDUCCI',
+        'publisher_email': 'p.mc-ginnity@iaea.org, i.osvath@iaea.org, F.Descroix-Comanducci@iaea.org', 
+        'publisher_url': 'https://maris.iaea.org',
+        'publisher_institution': 'International Atomic Energy Agency - IAEA', 
+
+        # Creator info [ACDD1.3]
+        'creator_name': '',
+        'institution': '',
+        'metadata_link': '',
+        'creator_email': '',
+        'creator_url': '',
+        'references': '',
+        'license': ' '.join(['Without prejudice to the applicable Terms and Conditions', 
+                             '(https://nucleus.iaea.org/Pages/Others/Disclaimer.aspx),',
+                             'I hereby agree that any use of the data will contain appropriate',
+                             'acknowledgement of the data source(s) and the IAEA Marine',
+                             'Radioactivity Information System (MARIS).']),
+        'comment': '',
+        # Dataset info & coordinates [ACDD1.3]
+        #'project': '', # Network long name
+        #'platform': '', # Should be a long / full name
+        'geospatial_lat_min': '', 
+        'geospatial_lon_min': '',
+        'geospatial_lat_max': '',
+        'geospatial_lon_max': '',
+        'geospatial_vertical_min': '',
+        'geospatial_vertical_max': '',
+        'geospatial_bounds': '', # wkt representation
+        'geospatial_bounds_crs': 'EPSG:4326',
+
+        # Time information
+        'time_coverage_start': '',
+        'time_coverage_end': '',
+        #'time_coverage_resolution': '',
+        'local_time_zone': '',
+        'date_created': '',
+        'date_modified': '',
+        #
+        # -- Additional metadata (custom to MARIS)
+        #
+        'publisher_postprocess_logs': ''
+        },
+    'dim': {
+        'name': 'sample',
+        'attrs': {
+            'long_name': 'Sample ID of measurement'
+        },
+        'dtype': 'u8'
+    },
+    'vars': {    
+        'defaults': {
+            'lon': {
+                'name': 'lon',
+                'attrs': {
+                    'long_name': 'Measurement longitude',
+                    'standard_name': 'longitude',
+                    'units': 'degrees_north',
+                    'axis': 'Y',
+                    '_CoordinateAxisType': 'Lon'
+                },
+                'dtype': 'f4'
+            },
+            'lat': {
+                'name': 'lat',
+                'attrs': {
+                    'long_name': 'Measurement latitude',
+                    'standard_name': 'latitude',
+                    'units': 'degrees_east',
+                    'axis': 'X',
+                    '_CoordinateAxisType': 'Lat'
+                },
+                'dtype': 'f4'
+            },
+            'smp_depth': {
+                'name': 'smp_depth',
+                'attrs': {
+                    'long_name': 'Sample depth below seal level',
+                    'standard_name': 'sample_depth_below_sea_floor',
+                    'units': 'm',
+                    'axis': 'Z'
+                },
+                'dtype': 'f4'
+            },
+            'tot_depth': {
+                'name': 'tot_depth',
+                'attrs': {
+                    'long_name': 'Total depth below seal level',
+                    'standard_name': 'total_depth_below_sea_floor',
+                    'units': 'm',
+                    'axis': 'Z'
+                },
+                'dtype': 'f4'
+            },
+            'time': {
+                'name': 'time',
+                'attrs': {
+                    'long_name': 'Time of measurement',
+                    'standard_name': 'time',
+                    'units': 'seconds since 1970-01-01 00:00:00.0',
+                    'time_origin': '1970-01-01 00:00:00',
+                    'time_zone': 'UTC',
+                    'abbreviation': 'Date/Time',
+                    'axis': 'T',
+                    'calendar': 'gregorian'
+                },
+                'dtype': 'u8',
+            },
+            'area': {
+                'name': 'area',
+                'attrs': {
+                    'long_name': 'Marine area/region id',
+                    'standard_name': 'area_id'
+                },
+                'dtype': 'area_t'
+            },
+        },
+        'bio': {
+            'bio_group': {
+                'name': 'bio_group',
+                'attrs': {
+                    'long_name': 'Biota group',
+                    'standard_name': 'biota_group_tbd'
+                },
+                'dtype': 'bio_group_t'
+            },
+            'species': {
+                'name': 'species',
+                'attrs': {  
+                    'long_name': 'Species',
+                    'standard_name': 'species'
+                },
+                'dtype': 'species_t'
+            },
+            'body_part': {
+                'name': 'body_part',
+                'attrs': {
+                    'long_name': 'Body part',
+                    'standard_name': 'body_part_tbd'
+                },
+                'dtype': 'body_part_t' 
+            }
+        },
+        'sed': {
+            'sed_type': {
+                'name': 'sed_type',
+                'attrs': {
+                    'long_name': 'Sediment type',
+                    'standard_name': 'sediment_type_tbd'
+                },
+                'dtype': 'sed_type_t'
+            }
+        },
+        'suffixes':  {
+            'uncertainty': {
+                'name': '_unc',
+                'attrs': {
+                    'long_name': ' uncertainty',
+                    'standard_name': '_uncertainty'
+                },
+                'dtype': 'f4'
+            },
+            'detection_limit': {
+                'name': '_dl',
+                'attrs': {
+                    'long_name': ' detection limit',
+                    'standard_name': '_detection_limit'
+                },
+                'dtype': 'dl_t'
+            },
+            'volume': {
+                'name': '_vol',
+                'attrs': {
+                    'long_name': ' volume',
+                    'standard_name': '_volume'
+                },
+                'dtype': 'f4'
+            },
+            'salinity': {
+                'name': '_sal',
+                'attrs': {
+                    'long_name': ' salinity',
+                    'standard_name': '_sal'
+                },
+                'dtype': 'f4'
+            },
+            'temperature': {
+                'name': '_temp',
+                'attrs': {
+                    'long_name': ' temperature',
+                    'standard_name': '_temp'
+                },
+                'dtype': 'f4'
+            },
+            'filtered': {
+                'name': '_filt',
+                'attrs': {
+                    'long_name': ' filtered',
+                    'standard_name': '_filtered'
+                },
+                'dtype': 'filt_t'
+            },
+            'counting_method': {
+                'name': '_counmet',
+                'attrs': {
+                    'long_name': ' counting method',
+                    'standard_name': '_counting_method'
+                },
+                'dtype': 'counmet_t'
+            },
+            'sampling_method': {
+                'name': '_sampmet',
+                'attrs': {
+                    'long_name': ' sampling method',
+                    'standard_name': '_sampling_method'
+                },
+                'dtype': 'sampmet_t'
+            },
+            'preparation_method': {
+                'name': '_prepmet',
+                'attrs': {
+                    'long_name': ' preparation method',
+                    'standard_name': '_preparation_method'
+                },
+                'dtype': 'prepmet_t'
+            },
+            'unit': {
+                'name': '_unit',
+                'attrs': {
+                    'long_name': ' unit',
+                    'standard_name': '_unit'
+                },
+                'dtype': 'unit_t'
+            }
+        }
+    },
+    'enums': [
+        {
+            'name': 'area_t', 
+            'fname': 'dbo_area.xlsx', 
+            'key': 'displayName', 
+            'value':'areaId'
+        },
+        {
+            'name': 'bio_group_t', 
+            'fname': 'dbo_biogroup.xlsx', 
+            'key': 'biogroup', 
+            'value':'biogroup_id'
+        },
+        {
+            'name': 'body_part_t', 
+            'fname': 'dbo_bodypar.xlsx', 
+            'key': 'bodypar', 
+            'value':'bodypar_id'
+        },
+        {
+            'name': 'species_t', 
+            'fname': 'dbo_species_cleaned.xlsx', 
+            'key': 'species', 
+            'value':'species_id'
+        },
+        {
+            'name': 'sed_type_t', 
+            'fname': 'dbo_sedtype.xlsx', 
+            'key': 'sedtype', 
+            'value':'sedtype_id'
+        },
+        {
+            'name': 'unit_t', 
+            'fname': 'dbo_unit.xlsx', 
+            'key': 'unit_sanitized', 
+            'value':'unit_id'
+        },
+        {
+            'name': 'dl_t', 
+            'fname': 'dbo_detectlimit.xlsx', 
+            'key': 'name_sanitized', 
+            'value':'id'
+        },
+        {
+            'name': 'filt_t', 
+            'fname': 'dbo_filtered.xlsx', 
+            'key': 'name',
+            'value':'id'
+        },
+        {
+            'name': 'counmet_t', 
+            'fname': 'dbo_counmet.xlsx', 
+            'key': 'counmet',
+            'value':'counmet_id'
+        },
+        {
+            'name': 'sampmet_t', 
+            'fname': 'dbo_sampmet.xlsx', 
+            'key': 'sampmet',
+            'value':'sampmet_id'
+        },
+        {
+            'name': 'prepmet_t', 
+            'fname': 'dbo_prepmet.xlsx', 
+            'key': 'prepmet',
+            'value':'prepmet_id'
+        }
+        ]
+}
+
+
+
+
fc.AttrDict(CONFIGS_CDL['vars']['defaults'])
+
+
{ 'area': { 'attrs': { 'long_name': 'Marine area/region id',
+                       'standard_name': 'area_id'},
+            'dtype': 'area_t',
+            'name': 'area'},
+  'lat': { 'attrs': { '_CoordinateAxisType': 'Lat',
+                      'axis': 'X',
+                      'long_name': 'Measurement latitude',
+                      'standard_name': 'latitude',
+                      'units': 'degrees_east'},
+           'dtype': 'f4',
+           'name': 'lat'},
+  'lon': { 'attrs': { '_CoordinateAxisType': 'Lon',
+                      'axis': 'Y',
+                      'long_name': 'Measurement longitude',
+                      'standard_name': 'longitude',
+                      'units': 'degrees_north'},
+           'dtype': 'f4',
+           'name': 'lon'},
+  'smp_depth': { 'attrs': { 'axis': 'Z',
+                            'long_name': 'Sample depth below seal level',
+                            'standard_name': 'sample_depth_below_sea_floor',
+                            'units': 'm'},
+                 'dtype': 'f4',
+                 'name': 'smp_depth'},
+  'time': { 'attrs': { 'abbreviation': 'Date/Time',
+                       'axis': 'T',
+                       'calendar': 'gregorian',
+                       'long_name': 'Time of measurement',
+                       'standard_name': 'time',
+                       'time_origin': '1970-01-01 00:00:00',
+                       'time_zone': 'UTC',
+                       'units': 'seconds since 1970-01-01 00:00:00.0'},
+            'dtype': 'u8',
+            'name': 'time'},
+  'tot_depth': { 'attrs': { 'axis': 'Z',
+                            'long_name': 'Total depth below seal level',
+                            'standard_name': 'total_depth_below_sea_floor',
+                            'units': 'm'},
+                 'dtype': 'f4',
+                 'name': 'tot_depth'}}
+
+
+
+
write_toml(Path('./files') / CDL_FNAME, CONFIGS_CDL)
+
+
Creating files/cdl.toml
+
+
+
+

source

+
+
+

cdl_cfg

+
+
 cdl_cfg ()
+
+
+
+Exported source +
def cdl_cfg(): return read_toml(base_path() / CDL_FNAME)
+
+
+
+

source

+
+
+

species_lut_path

+
+
 species_lut_path ()
+
+
+
+Exported source +
def species_lut_path():
+    src_dir = lut_path()
+    fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'species_t'][0]['fname']
+    return src_dir / fname
+
+
+
+

source

+
+
+

bodyparts_lut_path

+
+
 bodyparts_lut_path ()
+
+
+
+Exported source +
def bodyparts_lut_path():
+    src_dir = lut_path()
+    fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'body_part_t'][0]['fname']
+    return src_dir / fname
+
+
+
+

source

+
+
+

biogroup_lut_path

+
+
 biogroup_lut_path ()
+
+
+
+Exported source +
def biogroup_lut_path():
+    src_dir = lut_path()
+    fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'bio_group_t'][0]['fname']
+    return src_dir / fname
+
+
+
+

source

+
+
+

sediments_lut_path

+
+
 sediments_lut_path ()
+
+
+
+Exported source +
def sediments_lut_path():
+    src_dir = lut_path()
+    fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'sed_type_t'][0]['fname']
+    return src_dir / fname
+
+
+
+

source

+
+
+

unit_lut_path

+
+
 unit_lut_path ()
+
+
+
+Exported source +
def unit_lut_path():
+    src_dir = lut_path()
+    fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'unit_t'][0]['fname']
+    return src_dir / fname
+
+
+
+

source

+
+
+

detection_limit_lut_path

+
+
 detection_limit_lut_path ()
+
+
+
+Exported source +
def detection_limit_lut_path():
+    src_dir = lut_path()
+    fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'dl_t'][0]['fname']
+    return src_dir / fname
+
+
+
+

source

+
+
+

filtered_lut_path

+
+
 filtered_lut_path ()
+
+
+
+Exported source +
def filtered_lut_path():
+    src_dir = lut_path()
+    fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'filt_t'][0]['fname']
+    return src_dir / fname
+
+
+
+

source

+
+
+

area_lut_path

+
+
 area_lut_path ()
+
+
+
+Exported source +
def area_lut_path():
+    src_dir = lut_path()
+    fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'area_t'][0]['fname']
+    return src_dir / fname
+
+
+
+
+
+

Utilities function

+
+

source

+
+

name2grp

+
+
 name2grp (name:str, cdl:dict)
+
+ + + + + + + + + + + + + + + + + + + + +
TypeDetails
namestrName of the group
cdldictCDL configuration
+
+
+Exported source +
NETCDF_TO_PYTHON_TYPE = {
+    'u8': int,
+    'f4': float
+    }
+
+
+
+
+Exported source +
def name2grp(
+    name:str, # Name of the group
+    cdl:dict, # CDL configuration
+    ):
+    # Reverse `cdl.toml` config group dict so that group config key can be retrieve based on its name
+    return {v['name']:k  for k, v in cdl['grps'].items()}[name]
+
+
+

Example:

+
+
name2grp('seawater', cdl=CONFIGS_CDL)
+
+
'sea'
+
+
+
+

source

+
+
+

nc_tpl_name

+
+
 nc_tpl_name ()
+
+
+
+Exported source +
def nc_tpl_name():
+    p = base_path()
+    return read_toml(p / 'configs.toml')['names']['nc_template']
+
+
+
+

source

+
+
+

nc_tpl_path

+
+
 nc_tpl_path ()
+
+

Return the name of the MARIS NetCDF template as defined in configs.toml

+
+
+Exported source +
def nc_tpl_path():
+    "Return the name of the MARIS NetCDF template as defined in `configs.toml`"
+    p = base_path()
+    return p / read_toml(p / 'configs.toml')['names']['nc_template']
+
+
+
+
+
+

Enumeration types

+

Enumeration types are used to avoid using strings as NetCDF4 variable values. Instead, enumeration types (lookup tables) such as {'Crustaceans': 2, 'Echinoderms': 3, ...} are prepended to the NetCDF file template and associated ids (integers) are used as values.

+
+

source

+
+

sanitize

+
+
 sanitize (s:Union[str,float])
+
+

*Sanitize dictionary key to comply with NetCDF enumeration type:

+
    +
  • remove (, ), ., /, -
    +
  • +
  • strip the string*
  • +
+ + + + + + + + + + + + + + + + + + + + +
TypeDetails
sUnionString to sanitize
ReturnsstrSanitized string
+
+
+Exported source +
def sanitize(s:Union[str, float] # String to sanitize
+            ) -> str: # Sanitized string
+    """
+    Sanitize dictionary key to comply with NetCDF enumeration type: 
+    
+        - remove `(`, `)`, `.`, `/`, `-`  
+        - strip the string
+    """
+    if isinstance(s, str):
+        s = re.sub(r'[().]', '', s)
+        return re.sub(r'[/-]', ' ', s).strip()
+    elif pd.isna(s):  # This covers np.nan, None, and pandas NaT
+        return s
+    else:
+        return str(s).strip()
+
+
+

For example:

+
+
fc.test_eq(sanitize('key (sanitized)'), 'key sanitized')
+fc.test_eq(sanitize('key san.itized'), 'key sanitized')
+fc.test_eq(sanitize('key-sanitized'), 'key sanitized')
+fc.test_eq(sanitize('key/sanitized'), 'key sanitized')
+
+

NetCDF4 enumeration type seems to not accept keys containing non alphanumeric characters like parentheses, dots, slash, … As a result, MARIS lookup table needs to be sanitized.

+
+

source

+
+
+

get_lut

+
+
 get_lut (src_dir:str, fname:str, key:str, value:str,
+          do_sanitize:bool=True, reverse:bool=False)
+
+

Convert MARIS db lookup table excel file to dictionary {'name': id, ...} or {id: name, ...} if reverse is True.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
src_dirstrDirectory containing lookup tables
fnamestrExcel file lookup table name
keystrExcel file column name to be used as dict keys
valuestrExcel file column name to be used as dict values
do_sanitizeboolTrueSanitization required?
reverseboolFalseReverse lookup table (value, key)
ReturnsdictMARIS lookup table (key, value)
+
+
+Exported source +
def get_lut(src_dir:str, # Directory containing lookup tables
+            fname:str, # Excel file lookup table name
+            key:str, # Excel file column name to be used as dict keys 
+            value:str, # Excel file column name to be used as dict values 
+            do_sanitize:bool=True, # Sanitization required?
+            reverse:bool=False # Reverse lookup table (value, key)
+            ) -> dict: # MARIS lookup table (key, value)
+    "Convert MARIS db lookup table excel file to dictionary `{'name': id, ...}` or `{id: name, ...}` if `reverse` is True."
+    fname = Path(src_dir) / fname
+    df = pd.read_excel(fname, usecols=[key, value]).dropna(subset=value)
+    df[value] = df[value].astype('int')
+    df = df.set_index(key)
+    lut = df[value].to_dict()
+    if do_sanitize: lut = {sanitize(k): v for k, v in lut.items()}
+    return {v: k for k,v in lut.items()} if reverse else lut
+
+
+

For example:

+
+
lut_src_dir = './files/lut'
+get_lut(lut_src_dir, 'dbo_biogroup.xlsx', key='biogroup', value='biogroup_id', reverse=False)
+
+
{'Not applicable': -1,
+ 'Not available': 0,
+ 'Birds': 1,
+ 'Crustaceans': 2,
+ 'Echinoderms': 3,
+ 'Fish': 4,
+ 'Mammals': 5,
+ 'Molluscs': 6,
+ 'Others': 7,
+ 'Plankton': 8,
+ 'Polychaete worms': 9,
+ 'Reptile': 10,
+ 'Seaweeds and plants': 11,
+ 'Cephalopods': 12,
+ 'Gastropods': 13,
+ 'Bivalves': 14}
+
+
+
+

source

+
+
+

Enums

+
+
 Enums (lut_src_dir:str, cdl_enums:dict)
+
+

Return dictionaries of MARIS NetCDF’s enumeration types

+
+
+Exported source +
class Enums():
+    "Return dictionaries of MARIS NetCDF's enumeration types"
+    def __init__(self, 
+               lut_src_dir:str,
+               cdl_enums:dict
+               ):
+        fc.store_attr()
+        self.types = self.lookup()
+        
+    def filter(self, name, values):
+        return {name: id for name, id in self.types[name].items() if id in values}
+    
+    def lookup(self):
+        types = {}
+        for enum in self.cdl_enums:
+            name, fname, key, value = enum.values()
+            lut = get_lut(self.lut_src_dir, fname, key=key, value=value)
+            types[name] = lut
+        return types
+
+
+
+
lut_src_dir_test = './files/lut'
+cdl_enums_test = read_toml('./files/cdl.toml')['enums']
+
+enums = Enums(lut_src_dir=lut_src_dir_test, 
+              cdl_enums=cdl_enums_test)
+
+
+
enums.types['dl_t']
+
+
{'Not applicable': -1,
+ 'Not available': 0,
+ 'Detected value': 1,
+ 'Detection limit': 2,
+ 'Not detected': 3,
+ 'Derived': 4}
+
+
+
+
enums.types['unit_t']
+
+
{'Not applicable': -1,
+ 'NOT AVAILABLE': 0,
+ 'Bq per m3': 1,
+ 'Bq per m2': 2,
+ 'Bq per kg': 3,
+ 'Bq per kgd': 4,
+ 'Bq per kgw': 5,
+ 'kg per kg': 6,
+ 'TU': 7,
+ 'DELTA per mill': 8,
+ 'atom per kg': 9,
+ 'atom per kgd': 10,
+ 'atom per kgw': 11,
+ 'atom per l': 12,
+ 'Bq per kgC': 13}
+
+
+
+
# {f'{var}_t': enums.subset('species_t', tfm.unique(var) for var in ['species']}
+
+
+
# subset = {}
+# for var, values in [('species', [21,   50,   59,   84]),
+#                     ('area', [2, 3])]:
+#     # values = tfm.unique(var)
+#     type_name = f'{var}_t'
+#     subset[type_name] = enums.filter(type_name, [21,   50,   59,   84])
+
+
+

source

+
+
+

get_enum_dicts

+
+
 get_enum_dicts (lut_src_dir:str, cdl_enums:dict, **kwargs)
+
+

Return a dict of NetCDF enumeration types

+
+
+Exported source +
def get_enum_dicts(
+    lut_src_dir:str,
+    cdl_enums:dict,
+    **kwargs
+    ):
+    "Return a dict of NetCDF enumeration types"
+    enum_types = {}
+    for enum in cdl_enums:
+        name, fname, key, value = enum.values()
+        lut = get_lut(lut_src_dir, fname, key=key, value=value, **kwargs)
+        enum_types[name] = lut
+        
+    return enum_types
+
+
+

For example:

+
+
lut_src_dir_test = './files/lut'
+cdl_enums_test = read_toml('./files/cdl.toml')['enums']
+
+enums = get_enum_dicts(lut_src_dir=lut_src_dir_test, 
+                       cdl_enums=cdl_enums_test)
+enums.keys()
+
+
dict_keys(['area_t', 'bio_group_t', 'body_part_t', 'species_t', 'sed_type_t', 'unit_t', 'dl_t', 'filt_t', 'counmet_t', 'sampmet_t', 'prepmet_t'])
+
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/api/inout.html b/api/inout.html new file mode 100644 index 0000000..6220a03 --- /dev/null +++ b/api/inout.html @@ -0,0 +1,741 @@ + + + + + + + + + + +Input/Output – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Input/Output

+
+ +
+
+ Files reader and writer +
+
+ + +
+ + + + +
+ + + +
+ + + +
+

source

+
+

write_toml

+
+
 write_toml (fname, cfg)
+
+
+

source

+
+
+

read_toml

+
+
 read_toml (fname)
+
+ + +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/api/metadata.html b/api/metadata.html new file mode 100644 index 0000000..7ea80eb --- /dev/null +++ b/api/metadata.html @@ -0,0 +1,1070 @@ + + + + + + + + + + +Metadata – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+ + +
+
+ Various utilities to populate NetCDF global attributes as well as ISO13195 metadata. +
+
+ + +
+ + + + +
+ + + +
+ + + +
+

source

+
+

GlobAttrsFeeder

+
+
 GlobAttrsFeeder (dfs:dict, cbs:list=[], logs:list=[])
+
+

Produce NetCDF global attributes as specified by the callbacks.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
dfsdictDictionary of NetCDF group DataFrames
cbslist[]Callbacks
logslist[]List of preprocessing steps taken
+
+
+Exported source +
import pandas as pd
+import fastcore.all as fc
+from cftime import num2date
+from pyzotero import zotero, zotero_errors
+import json
+
+from marisco.utils import get_bbox 
+from marisco.callbacks import run_cbs, Callback, CompareDfsAndTfmCB
+
+
+
+
+Exported source +
class GlobAttrsFeeder:
+    "Produce NetCDF global attributes as specified by the callbacks."
+    def __init__(self, 
+                 dfs:dict, # Dictionary of NetCDF group DataFrames
+                 cbs:list=[], # Callbacks
+                 logs:list=[] # List of preprocessing steps taken
+                 ): 
+        fc.store_attr()
+        self.attrs = {}
+        
+    def callback(self):
+        run_cbs(self.cbs, self)
+        
+    def __call__(self):
+        self.callback()
+        return self.attrs
+
+
+
+

source

+
+
+

BboxCB

+
+
 BboxCB ()
+
+

Compute dataset geographical bounding box

+
+
+Exported source +
class BboxCB(Callback):
+    "Compute dataset geographical bounding box"
+    def __call__(self, obj):
+        bbox = get_bbox(pd.concat(obj.dfs)) 
+        lon_min, lon_max, lat_min, lat_max = [str(bound) for bound in bbox.bounds]
+        obj.attrs.update({
+            'geospatial_lat_min': lat_min, 
+            'geospatial_lat_max': lat_max,
+            'geospatial_lon_min': lon_min,
+            'geospatial_lon_max': lon_max,
+            'geospatial_bounds': bbox.wkt})
+
+
+
+

source

+
+
+

DepthRangeCB

+
+
 DepthRangeCB (depth_col='depth')
+
+

Compute depth values range

+
+
+Exported source +
class DepthRangeCB(Callback):
+    "Compute depth values range"
+    def __init__(self, depth_col='depth'): fc.store_attr()
+    def __call__(self, obj):
+        depths = pd.concat(obj.dfs).get(self.depth_col, default=pd.Series([]))
+        if not depths.empty:
+            max_depth, min_depth = depths.max(), depths.min()
+            obj.attrs.update({
+                'geospatial_vertical_max': '0' if min_depth == 0 else str(-min_depth),
+                'geospatial_vertical_min': str(-max_depth)})
+
+
+
+

source

+
+
+

TimeRangeCB

+
+
 TimeRangeCB (cfg)
+
+

Compute time values range

+
+
+Exported source +
class TimeRangeCB(Callback):
+    "Compute time values range"
+    def __init__(self, cfg): fc.store_attr()
+    def __call__(self, obj):
+        time = pd.concat(obj.dfs)['time']
+        start, end = [num2date(t, units=self.cfg['units']['time']).isoformat() 
+                      for t in (time.min(), time.max())]
+        obj.attrs.update({
+            'time_coverage_start': start,
+            'time_coverage_end': end})
+
+
+
+

source

+
+
+

ZoteroItem

+
+
 ZoteroItem (item_id, cfg)
+
+

Initialize self. See help(type(self)) for accurate signature.

+
+
+Exported source +
class ZoteroItem:
+    def __init__(self, item_id, cfg):
+        self.cfg = cfg
+        self.item = self.getItem(item_id)
+    
+    def exist(self): return self.item != None
+    
+    def getItem(self, item_id):
+        zot = zotero.Zotero(self.cfg['lib_id'], 'group', self.cfg['api_key'])
+        try:
+            return zot.item(item_id)
+        except zotero_errors.ResourceNotFound:
+            print(f'Item {item_id} does not exist in Zotero library')
+            return None
+            
+    def title(self):
+        return self.item['data']['title']
+    
+    def summary(self):
+        return self.item['data']['abstractNote']
+    
+    def creator_name(self):
+        # creators = [f'{c["creatorType"]}: {c["name"]}' for c in self.item['data']['creators']]
+        # return '; '.join(creators)
+        return json.dumps(self.item['data']['creators'])
+            
+    def __repr__(self):
+        return json.dumps(self.item, indent=4)
+
+
+
+

source

+
+
+

ZoteroCB

+
+
 ZoteroCB (itemId, cfg)
+
+

Retrieve Zotero metadata.

+
+
+Exported source +
# TBD: put it in callback module
+class ZoteroCB(Callback):
+    "Retrieve Zotero metadata."
+    def __init__(self, itemId, cfg): fc.store_attr()
+    def __call__(self, obj):
+        item = ZoteroItem(self.itemId, self.cfg['zotero'])
+        if item.exist(): 
+            for attr in ['title', 'summary', 'creator_name']:
+                obj.attrs[attr] = getattr(item, attr)()
+
+
+
+
from marisco.configs import cfg
+
+GlobAttrsFeeder(None, cbs=[
+    ZoteroCB('26VMZZ2Q', cfg=cfg())
+    ])()
+
+
{'title': 'Environmental database - Helsinki Commission Monitoring of Radioactive Substances',
+ 'summary': 'MORS Environment database has been used to collate data resulting from monitoring of environmental radioactivity in the Baltic Sea based on HELCOM Recommendation 26/3.\n\nThe database is structured according to HELCOM Guidelines on Monitoring of Radioactive Substances (https://www.helcom.fi/wp-content/uploads/2019/08/Guidelines-for-Monitoring-of-Radioactive-Substances.pdf), which specifies reporting format, database structure, data types and obligatory parameters used for reporting data under Recommendation 26/3.\n\nThe database is updated and quality assured annually by HELCOM MORS EG.',
+ 'creator_name': '[{"creatorType": "author", "name": "HELCOM MORS"}]'}
+
+
+
+
GlobAttrsFeeder(None, cbs=[
+    ZoteroCB('3W354SQG', cfg=cfg())
+    ])()
+
+
{'title': 'Radioactivity Monitoring of the Irish Marine Environment 1991 and 1992',
+ 'summary': '',
+ 'creator_name': '[{"creatorType": "author", "firstName": "A.", "lastName": "McGarry"}, {"creatorType": "author", "firstName": "S.", "lastName": "Lyons"}, {"creatorType": "author", "firstName": "C.", "lastName": "McEnri"}, {"creatorType": "author", "firstName": "T.", "lastName": "Ryan"}, {"creatorType": "author", "firstName": "M.", "lastName": "O\'Colmain"}, {"creatorType": "author", "firstName": "J.D.", "lastName": "Cunningham"}]'}
+
+
+
+
GlobAttrsFeeder(None, cbs=[
+    ZoteroCB('x', cfg=cfg())
+    ])()
+
+
Item x does not exist in Zotero library
+
+
+
{}
+
+
+
+

source

+
+
+

KeyValuePairCB

+
+
 KeyValuePairCB (k, v)
+
+

Base class for callbacks.

+
+
+Exported source +
class KeyValuePairCB(Callback):
+    def __init__(self, k, v): fc.store_attr()
+    def __call__(self, obj): obj.attrs[self.k] = self.v
+
+
+
+
+

How to use

+
+
dfs = pd.read_pickle('../files/pkl/dfs_test.pkl')
+
+
+
kw = ['oceanography', 'Earth Science > Oceans > Ocean Chemistry> Radionuclides',
+      'Earth Science > Human Dimensions > Environmental Impacts > Nuclear Radiation Exposure',
+      'Earth Science > Oceans > Ocean Chemistry > Ocean Tracers, Earth Science > Oceans > Marine Sediments',
+      'Earth Science > Oceans > Ocean Chemistry, Earth Science > Oceans > Sea Ice > Isotopes',
+      'Earth Science > Oceans > Water Quality > Ocean Contaminants',
+      'Earth Science > Biological Classification > Animals/Vertebrates > Fish',
+      'Earth Science > Biosphere > Ecosystems > Marine Ecosystems',
+      'Earth Science > Biological Classification > Animals/Invertebrates > Mollusks',
+      'Earth Science > Biological Classification > Animals/Invertebrates > Arthropods > Crustaceans',
+      'Earth Science > Biological Classification > Plants > Macroalgae (Seaweeds)']
+
+
+
feed = GlobAttrsFeeder(dfs, cbs=[
+    BboxCB(),
+    DepthRangeCB(),
+    TimeRangeCB(cfg=CONFIGS),
+    ZoteroCB('26VMZZ2Q', cfg=CONFIGS),
+    KeyValuePairCB('keywords', ', '.join(kw))
+    ])
+
+attrs = feed(); attrs
+
+
{'geospatial_lat_min': '29.05',
+ 'geospatial_lat_max': '65.35',
+ 'geospatial_lon_min': '9.6333',
+ 'geospatial_lon_max': '54.0',
+ 'geospatial_bounds': 'POLYGON ((9.6333 54, 29.05 54, 29.05 65.35, 9.6333 65.35, 9.6333 54))',
+ 'geospatial_vertical_max': '0',
+ 'geospatial_vertical_min': '-248.0',
+ 'time_coverage_start': '1984-01-10T00:00:00',
+ 'time_coverage_end': '1987-06-28T00:00:00',
+ 'title': 'Environmental database - Helsinki Commission Monitoring of Radioactive Substances',
+ 'summary': 'MORS Environment database has been used to collate data resulting from monitoring of environmental radioactivity in the Baltic Sea based on HELCOM Recommendation 26/3.\n\nThe database is structured according to HELCOM Guidelines on Monitoring of Radioactive Substances (https://www.helcom.fi/wp-content/uploads/2019/08/Guidelines-for-Monitoring-of-Radioactive-Substances.pdf), which specifies reporting format, database structure, data types and obligatory parameters used for reporting data under Recommendation 26/3.\n\nThe database is updated and quality assured annually by HELCOM MORS EG.',
+ 'creator_name': '[{"creatorType": "author", "name": "HELCOM MORS"}]',
+ 'keywords': 'oceanography, Earth Science > Oceans > Ocean Chemistry> Radionuclides, Earth Science > Human Dimensions > Environmental Impacts > Nuclear Radiation Exposure, Earth Science > Oceans > Ocean Chemistry > Ocean Tracers, Earth Science > Oceans > Marine Sediments, Earth Science > Oceans > Ocean Chemistry, Earth Science > Oceans > Sea Ice > Isotopes, Earth Science > Oceans > Water Quality > Ocean Contaminants, Earth Science > Biological Classification > Animals/Vertebrates > Fish, Earth Science > Biosphere > Ecosystems > Marine Ecosystems, Earth Science > Biological Classification > Animals/Invertebrates > Mollusks, Earth Science > Biological Classification > Animals/Invertebrates > Arthropods > Crustaceans, Earth Science > Biological Classification > Plants > Macroalgae (Seaweeds)'}
+
+
+ + +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/api/nc_template.html b/api/nc_template.html new file mode 100644 index 0000000..c5ce0e8 --- /dev/null +++ b/api/nc_template.html @@ -0,0 +1,1218 @@ + + + + + + + + + + +NetCDF Template – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

NetCDF Template

+
+ +
+
+ Creation of MARIS NetCDF template based on “pseudo” Common Data Language .toml config file. +
+
+ + +
+ + + + +
+ + + +
+ + + +
+

NetCDF template generator

+

Generate a NetCDF4 template from the configurable CDL.toml file, itself generated in /api/configs.ipynb.

+
+

source

+
+

NCTemplater

+
+
 NCTemplater (cdl:Dict, nuclide_vars_fname:str, tpl_fname:str,
+              enum_dicts:Dict, verbose=False)
+
+

MARIS NetCDF template generator.

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
cdlDict“Pseudo CDL” (.toml)
nuclide_vars_fnamestrFile name and path of MARIS nuclide lookup table containing variable names
tpl_fnamestrFile name and path of NetCDF4 file to be generated
enum_dictsDictMARIS NetCDF enumeration types
verboseboolFalse
+

For example, provided the configuration cdl.toml below, the templater gets access, among others, to its dim definiton section:

+
+
cdl_test = read_toml('./files/cdl.toml')
+lut_src_dir_test = './files/lut'
+cdl_enums_test = read_toml('./files/cdl.toml')['enums']
+enums = get_enum_dicts(lut_src_dir=lut_src_dir_test, 
+                       cdl_enums=cdl_enums_test)
+
+
+templater = NCTemplater(cdl=cdl_test,
+                        nuclide_vars_fname='./files/lut/dbo_nuclide.xlsx', 
+                        tpl_fname='./files/nc/test.nc',
+                        enum_dicts=enums)
+
+expected = {'name': 'sample', 
+            'dtype': 'u8', 
+            'attrs': {'long_name': 'Sample ID of measurement'}
+            }
+
+fc.test_eq(templater.dim, expected)
+
+
+
for k, v in enums['species_t'].items():
+    if v == 5: break
+    print(k, v)
+
+
Not applicable -1
+NOT AVAILABLE 0
+Aristeus antennatus 1
+Apostichopus 2
+Saccharina japonica var religiosa 3
+Siganus fuscescens 4
+
+
+
+

source

+
+
+

NCTemplater.nuclide_vars

+
+
 NCTemplater.nuclide_vars (col_varnames:str='nc_name',
+                           col_stdnames:str='nusymbol', dtype:str='f4')
+
+

Return the name of the radionuclide variables analysed.

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
col_varnamesstrnc_nameColumn name in the Excel lookup file containing the NetCDF variable names
col_stdnamesstrnusymbolColumn name Excel lookup file containing the NetCDF standard names
dtypestrf4Default data type
ReturnslistList of nuclide variables (including their names and attributes)
+

For example, to retrieve the NetCDF nuclide names and associated attributes:

+
+
templater = NCTemplater(cdl=cdl_test,
+                        nuclide_vars_fname='./files/lut/dbo_nuclide.xlsx', 
+                        tpl_fname='./files/nc/test.nc',
+                        enum_dicts=enums)
+expected = [
+  {'name': 'h3', 'attrs': {'long_name': 'Tritium 3', 'standard_name': '3H'}, 'dtype': 'f4'},
+  {'name': 'be7', 'attrs': {'long_name': 'Beryllium 7', 'standard_name': '7Be'}, 'dtype': 'f4'}
+  ]
+
+fc.test_eq(templater.nuclide_vars()[:2], expected)
+
+
+

source

+
+
+

NCTemplater.derive

+
+
 NCTemplater.derive (nuclide:dict, suffix:dict)
+
+

Derive NetCDF nuclide-dependent variable names & attributes as defined in CDL.

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDetails
nuclidedictNuclide variable name and associated netcdf attributes
suffixdictNaming rules as described in CDL (e.g _unc)
ReturnsdictDerived variable name and associated attributes
+

For example, among others, the cdl.toml file defines the naming convention on variable names deriving from nuclides (e.g h3_unc for measurement uncertainty on the h3 nuclide variable).

+
+
templater = NCTemplater(cdl=cdl_test,
+                        nuclide_vars_fname='./files/lut/dbo_nuclide.xlsx', 
+                        tpl_fname='./files/nc/test.nc',
+                        enum_dicts=enums)
+
+

Here is below the defined Tritium NetCDF variable as specified in the .cdl file:

+
+
templater.nuclide_vars()[0]
+
+
{'name': 'h3',
+ 'dtype': 'f4',
+ 'attrs': {'long_name': 'Tritium 3', 'standard_name': '3H'}}
+
+
+
+
# Example of suffix defined in the .cdl file
+suffix = {
+    'name': '_unc',
+    'attrs': {
+        'long_name': ' uncertainty',
+        'standard_name': '_uncertainty'
+        },
+    'dtype': 'f4'
+    }
+
+# And what we expect
+expected = {
+    'name': 'h3_unc',
+    'attrs': {
+        'long_name': 'Tritium 3 uncertainty',
+        'standard_name': '3H_uncertainty'
+        },
+    'dtype': 'f4'
+    }
+
+fc.test_eq(templater.derive(templater.nuclide_vars()[0], suffix=suffix), expected)
+
+
+

source

+
+
+

NCTemplater.create_enum_types

+
+
 NCTemplater.create_enum_types ()
+
+

Create enumeration types

+
+

source

+
+
+

NCTemplater.create_groups

+
+
 NCTemplater.create_groups ()
+
+

Create NetCDF groups

+
+

source

+
+
+

NCTemplater.create_variables

+
+
 NCTemplater.create_variables (grp:netCDF4._netCDF4.Group)
+
+

Create variables

+ + + + + + + + + + + + + + + +
TypeDetails
grpGroupNetCDF group
+
+

source

+
+
+

NCTemplater.create_default_variables

+
+
 NCTemplater.create_default_variables (grp:netCDF4._netCDF4.Group)
+
+

Create Default variables

+ + + + + + + + + + + + + + + +
TypeDetails
grpGroupNetCDF group
+
+

source

+
+
+

NCTemplater.create_group_specific_variables

+
+
 NCTemplater.create_group_specific_variables (grp:netCDF4._netCDF4.Group)
+
+

Create group specific variables

+ + + + + + + + + + + + + + + +
TypeDetails
grpGroupNetCDF group
+
+

source

+
+
+

NCTemplater.create_analyte_variables

+
+
 NCTemplater.create_analyte_variables (grp:netCDF4._netCDF4.Group)
+
+

Create analyte variables and dependent one as uncertainty, detection limit, …

+ + + + + + + + + + + + + + + +
TypeDetails
grpGroupNetCDF group
+
+

source

+
+
+

NCTemplater.create_variable

+
+
 NCTemplater.create_variable (grp:netCDF4._netCDF4.Group, var:Dict)
+
+

Create NetCDF variable with proper types (standard and enums)

+ +++++ + + + + + + + + + + + + + + + + + + + +
TypeDetails
grpGroupNetCDF group
varDictVariable specificiation dict with name, dtype and attrs keys
+
+
# Troubleshooting na values
+# from netCDF4 import Dataset
+# import numpy as np
+
+# with Dataset(''./files/nc/test-na-values.nc', 'w', format='NETCDF4') as nc:
+#     sample = nc.createDimension("sample", 4)
+
+#     enum_dict = {'Not applicable': -1, 'Not available': 0, 'Bq per m3': 1, 'Bq per kg': 2}
+#     # unit_type = nc.createEnumType(np.uint8,'unit_t',enum_dict)
+#     unit_type = nc.createEnumType(np.int_,'unit_t',enum_dict)
+
+#     meas_var = nc.createVariable('measurement', 'f4', 'sample')
+#     unit_var = nc.createVariable('unit', unit_type, 'sample',
+#                                  fill_value=-1
+#                                 #   fill_value=enum_dict['Not available']
+#                                 )
+
+#     meas_var[:] = [1.1, 2.1, 3.1, np.nan]
+#     unit_var[:] = [enum_dict[k] for k in ['Bq per m3', 'Bq per kg', 'Bq per kg']] + [-1]
+#     print(unit_var)
+
+
+

source

+
+
+

NCTemplater.generate

+
+
 NCTemplater.generate ()
+
+

Generate CDL

+

So in summary, to produce a template MARIS NetCDF:

+
+
templater = NCTemplater(cdl=cdl_test,
+                        nuclide_vars_fname='./files/lut/dbo_nuclide.xlsx', 
+                        tpl_fname='./files/nc/template-test.nc',
+                        enum_dicts=enums, 
+                        verbose=True)
+
+templater.generate()
+
+
Creating area_t enumeration type
+Creating bio_group_t enumeration type
+Creating body_part_t enumeration type
+Creating species_t enumeration type
+Creating sed_type_t enumeration type
+Creating unit_t enumeration type
+Creating dl_t enumeration type
+Creating filt_t enumeration type
+Creating counmet_t enumeration type
+Creating sampmet_t enumeration type
+Creating prepmet_t enumeration type
+
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/api/serializers.html b/api/serializers.html new file mode 100644 index 0000000..11077eb --- /dev/null +++ b/api/serializers.html @@ -0,0 +1,1308 @@ + + + + + + + + + + +Serializers – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+ +
+ +
+
+ Various utilities to encode MARIS dataset as NetCDF, csv, … formats. +
+
+ + +
+ + + + +
+ + + +
+ + + +
+
+
+
The autoreload extension is already loaded. To reload it, use:
+  %reload_ext autoreload
+
+
+
+

NetCDF encoder

+
+

source

+
+

NetCDFEncoder

+
+
 NetCDFEncoder (dfs:dict[pandas.core.frame.DataFrame], src_fname:str,
+                dest_fname:str, global_attrs:Dict, enums_xtra:Dict={},
+                verbose:bool=False)
+
+

MARIS NetCDF encoder.

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
dfsdictdict of Dataframes to encode with group name as key {‘sediment’: df_sed, …}
src_fnamestrFile name and path to the MARIS CDL template
dest_fnamestrName of output file to produce
global_attrsDictGlobal attributes
enums_xtraDict{}Enumeration types to overwrite
verboseboolFalsePrint currently written NetCDF group and variable names
+
+
+Exported source +
class NetCDFEncoder:
+    "MARIS NetCDF encoder."
+    def __init__(self, 
+                 dfs:dict[pd.DataFrame], # dict of Dataframes to encode with group name as key {'sediment': df_sed, ...}
+                 src_fname:str, # File name and path to the MARIS CDL template
+                 dest_fname:str, # Name of output file to produce
+                 global_attrs:Dict, # Global attributes
+                 enums_xtra:Dict={}, # Enumeration types to overwrite
+                 verbose:bool=False, # Print currently written NetCDF group and variable names
+                 ):
+        store_attr()
+        self.enum_types = {}
+
+
+
+
df_seawater = pd.DataFrame({
+    'sample': [0, 1, 5], 
+    'lon': [141, 142, 143], 
+    'lat': [37.3, 38.3, 39.3], 
+    'time': [1234, 1235, 1236], 
+    'i131': [1, 1.5, 2],
+    'i131_dl': [0, 1, 2], 
+    'i131_unit': [1, 1, 2],
+    'species': [134, 136, 137]
+    })
+
+df_biota = pd.DataFrame({
+    'sample': [0, 1], 
+    'lon': [141, 142], 
+    'lat': [37.3, 38.3], 
+    'time': [1234, 1235], 
+    'i131': [1, 1.5],
+    'i131_dl': [0, 1], 
+    'i131_unit': [1, 1],
+    'species': [134, 136]
+    })
+
+dfs = {'seawater': df_seawater, 'biota': df_biota}
+attrs = {'id': '123', 'title': 'Test title', 'summary': 'Summary test'}
+src = './files/nc/template-test.nc'
+dest = './files/nc/encoding-test.nc'
+enums_xtra = {
+    'species_t': {'Aristeus antennatus': 134, 'Apostichopus': 136}
+    }
+
+
+

source

+
+
+

NetCDFEncoder.copy_global_attributes

+
+
 NetCDFEncoder.copy_global_attributes ()
+
+

Update NetCDF template global attributes as specified by global_attrs argument.

+
+
+Exported source +
@patch 
+def copy_global_attributes(self:NetCDFEncoder):
+    "Update NetCDF template global attributes as specified by `global_attrs` argument."
+    self.dest.setncatts(self.src.__dict__)
+    for k, v in self.global_attrs.items(): self.dest.setncattr(k, v)
+
+
+
+

source

+
+
+

NetCDFEncoder.copy_dimensions

+
+
 NetCDFEncoder.copy_dimensions ()
+
+
+
+Exported source +
@patch
+def copy_dimensions(self:NetCDFEncoder):
+    for name, dimension in self.src.dimensions.items():
+        self.dest.createDimension(name, (len(dimension) if not dimension.isunlimited() else None))
+
+
+
+

source

+
+
+

NetCDFEncoder.process_groups

+
+
 NetCDFEncoder.process_groups ()
+
+
+
+Exported source +
@patch
+def process_groups(self:NetCDFEncoder):
+    for grp_name, df in self.dfs.items():
+        self.process_group(grp_name, df)
+
+
+
+

source

+
+
+

NetCDFEncoder.process_group

+
+
 NetCDFEncoder.process_group (group_name, df)
+
+
+
+Exported source +
@patch
+def process_group(self:NetCDFEncoder, group_name, df):
+    group_dest = self.dest.createGroup(group_name)
+    # Set the dimensions for each group
+    group_dest.createDimension(group_name, len(df.index))    
+    self.copy_variables(group_name, df, group_dest)
+
+
+
+

source

+
+
+

NetCDFEncoder.copy_variables

+
+
 NetCDFEncoder.copy_variables (group_name, df, group_dest)
+
+
+
+Exported source +
@patch
+def copy_variables(self:NetCDFEncoder, group_name, df, group_dest):
+    for var_name, var_src in self.src.groups[group_name].variables.items():
+        if var_name in df.reset_index().columns: 
+            self.copy_variable(var_name, var_src, df, group_dest)
+
+
+
+

source

+
+
+

NetCDFEncoder.copy_variable

+
+
 NetCDFEncoder.copy_variable (var_name, var_src, df, group_dest)
+
+
+
+Exported source +
@patch
+def copy_variable(self:NetCDFEncoder, var_name, var_src, df, group_dest):
+    dtype_name = var_src.datatype.name
+    enums_src = self.src.enumtypes
+    if self.verbose: 
+        print(80*'-')
+        print(f'Group: {group_dest.name}, Variable: {var_name}')
+    # If the type of the var is an enum (meaning present in the template src) then create it
+    if dtype_name in enums_src: self.copy_enum_type(dtype_name) 
+    self._create_and_copy_variable(var_name, var_src, df, group_dest, dtype_name)
+    self.copy_variable_attributes(var_name, var_src, group_dest)
+
+
+
+

source

+
+
+

NetCDFEncoder.sanitize_if_enum_and_nan

+
+
 NetCDFEncoder.sanitize_if_enum_and_nan (values, fill_value=-1)
+
+
+
+Exported source +
@patch
+def _create_and_copy_variable(self:NetCDFEncoder, var_name, var_src, df, group_dest, dtype_name):
+    variable_type = self.enum_types.get(dtype_name, var_src.datatype)
+    # Use the group_dest dimensions
+    group_dest.createVariable(var_name, variable_type, group_dest.dimensions, compression='zlib', complevel=9)            
+    isNotEnum = type(variable_type) != netCDF4._netCDF4.EnumType
+    values = df[var_name].values
+    group_dest[var_name][:] = values if isNotEnum else self.sanitize_if_enum_and_nan(values)
+
+
+
+
+Exported source +
@patch
+def sanitize_if_enum_and_nan(self:NetCDFEncoder, values, fill_value=-1):
+    values[np.isnan(values)] = int(fill_value)
+    values = values.astype(int)
+    return values
+
+
+
+

source

+
+
+

NetCDFEncoder.copy_enum_type

+
+
 NetCDFEncoder.copy_enum_type (dtype_name)
+
+
+
+Exported source +
@patch
+def copy_enum_type(self:NetCDFEncoder, dtype_name):
+    # if enum type not already created
+    if dtype_name not in self.enum_types:
+        enum_info = self.src.enumtypes[dtype_name]
+        # If a subset of an enum is defined in enums_xtra (typically for the lengthy species_t)
+        if enum_info.name in self.enums_xtra:
+            # add "not applicable"
+            enum_info.enum_dict = self.enums_xtra[enum_info.name]
+            enum_info.enum_dict['Not applicable'] = -1 # TBD
+        self.enum_types[dtype_name] = self.dest.createEnumType(enum_info.dtype, 
+                                                               enum_info.name, 
+                                                               enum_info.enum_dict)
+
+
+
+

source

+
+
+

NetCDFEncoder.copy_variable_attributes

+
+
 NetCDFEncoder.copy_variable_attributes (var_name, var_src, group_dest)
+
+
+
+Exported source +
@patch
+def copy_variable_attributes(self:NetCDFEncoder, var_name, var_src, group_dest):
+    group_dest[var_name].setncatts(var_src.__dict__)
+
+
+
+
# DEPRECATED
+@patch
+def cast_verbose_rf(self:NetCDFEncoder, 
+                    df, 
+                    col):
+    """
+    Try to cast df column to numeric type:
+        - Silently coerce to nan if not possible
+        - But log when it failed
+    """
+    n_before = sum(df.reset_index()[col].notna())
+    df_after = pd.to_numeric(df.reset_index()[col], errors='coerce', downcast=None)
+    n_after = sum(df_after.notna())
+    if n_before != n_after: print(f'Failed to convert type of {col} in {n_before - n_after} occurences')
+    return df_after
+
+
+

source

+
+
+

NetCDFEncoder.encode

+
+
 NetCDFEncoder.encode ()
+
+

Encode MARIS NetCDF based on template and dataframes.

+
+
+Exported source +
@patch
+def encode(self:NetCDFEncoder):
+    "Encode MARIS NetCDF based on template and dataframes."
+    with Dataset(self.src_fname, format='NETCDF4') as self.src, Dataset(self.dest_fname, 'w', format='NETCDF4') as self.dest:
+        self.copy_global_attributes()
+        self.copy_dimensions()
+        self.process_groups()
+
+
+
+
encoder = NetCDFEncoder(dfs, src_fname=src, dest_fname=dest, 
+                        global_attrs=attrs, enums_xtra=enums_xtra, verbose=False)
+encoder.encode()
+
+
+
# Test that global attributes are copied
+with Dataset(dest, 'r', format='NETCDF4') as nc:
+    for k, v in {'id': '123', 'title': 'Test title', 'summary': 'Summary test'}.items():
+        fc.test_eq(getattr(nc, k), v)
+
+
+
# Test that dimension is `sample` and unlimited
+with Dataset(dest, 'r', format='NETCDF4') as nc:
+    fc.test_eq('sample' in nc.dimensions, True)
+    fc.test_eq(nc.dimensions['sample'].isunlimited(), True)
+
+
+
# Test that groups are created
+with Dataset(dest, 'r', format='NETCDF4') as nc:
+    fc.test_eq(nc.groups.keys(), ['seawater', 'biota'])
+
+
+
# Test that groups are created
+with Dataset(dest, 'r', format='NETCDF4') as nc:
+    fc.test_eq(nc.groups.keys(), ['seawater', 'biota'])
+
+
+
# Test that correct variables are created in groups
+with Dataset(dest, 'r', format='NETCDF4') as nc:
+    fc.test_eq(nc['biota'].variables.keys(), 
+               ['sample', 'lon', 'lat', 'time', 'species', 'i131', 'i131_dl', 'i131_unit'])
+    
+    fc.test_eq(nc['seawater'].variables.keys(), 
+               ['sample', 'lon', 'lat', 'time', 'i131', 'i131_dl', 'i131_unit'])
+
+
+
# Test that correct variables are created in groups
+with Dataset(dest, 'r', format='NETCDF4') as nc:
+    print(nc.dimensions.items())
+    print(nc['biota'].dimensions.items())
+    print(nc['seawater'].dimensions.items())
+
+
dict_items([('sample', <class 'netCDF4._netCDF4.Dimension'> (unlimited): name = 'sample', size = 0)])
+dict_items([('biota', <class 'netCDF4._netCDF4.Dimension'>: name = 'biota', size = 2)])
+dict_items([('seawater', <class 'netCDF4._netCDF4.Dimension'>: name = 'seawater', size = 3)])
+
+
+
+
+
+

OpenRefine CSV encoder

+
+

source

+
+

OpenRefineCsvEncoder

+
+
 OpenRefineCsvEncoder (dfs:dict[pandas.core.frame.DataFrame],
+                       dest_fname:str, ref_id=-1, verbose:bool=False)
+
+

OpenRefine CSV from NetCDF.

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
dfsdictdict of Dataframes to encode with group name as key {‘sediment’: df_sed, …}
dest_fnamestrName of output file to produce
ref_idint-1ref_id to include
verboseboolFalsePrint
+
+
+Exported source +
class OpenRefineCsvEncoder:
+    "OpenRefine CSV from NetCDF."
+    def __init__(self, 
+                 dfs:dict[pd.DataFrame], # dict of Dataframes to encode with group name as key {'sediment': df_sed, ...}
+                 dest_fname:str, # Name of output file to produce
+                 ref_id = -1, # ref_id to include 
+                 verbose:bool=False, # Print 
+                 ):
+        store_attr()
+
+
+
+

source

+
+
+

OpenRefineCsvEncoder.process_groups_to_csv

+
+
 OpenRefineCsvEncoder.process_groups_to_csv ()
+
+
+
+Exported source +
@patch
+def process_groups_to_csv(self:OpenRefineCsvEncoder):
+    for grp_name, df in self.dfs.items():
+        # include ref_id
+        if self.ref_id != -1:
+            df['ref_id'] = self.ref_id
+        self.process_group_to_csv(grp_name, df)
+
+
+
+

source

+
+
+

OpenRefineCsvEncoder.process_group_to_csv

+
+
 OpenRefineCsvEncoder.process_group_to_csv (group_name, df)
+
+
+
+Exported source +
@patch
+def process_group_to_csv(self:OpenRefineCsvEncoder, group_name, df):
+    filename, file_extension=os.path.splitext(self.dest_fname)
+    path = filename + '_' + group_name + file_extension
+    df.to_csv( path_or_buf= path, sep=',', index=False)
+
+
+
+

source

+
+
+

OpenRefineCsvEncoder.encode

+
+
 OpenRefineCsvEncoder.encode ()
+
+

Encode OpenRefine CSV based on dataframes from NetCDF.

+
+
+Exported source +
@patch
+def encode(self:OpenRefineCsvEncoder):
+    "Encode OpenRefine CSV based on dataframes from NetCDF."
+    # Include ref_id
+    
+    # Process to csv
+    self.process_groups_to_csv()
+
+
+
+
dest = '../files/csv/encoding-test.csv'
+
+encoder = OpenRefineCsvEncoder(dfs,  dest_fname=dest)
+encoder.encode()
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/api/utils.html b/api/utils.html new file mode 100644 index 0000000..ebb59eb --- /dev/null +++ b/api/utils.html @@ -0,0 +1,1973 @@ + + + + + + + + + + +Utilities – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+ +
+ +
+
+ Various utilities +
+
+ + +
+ + + + +
+ + + +
+ + + +
+
import pandas as pd
+
+
+

Core

+

Abstracting some common operations.

+
+

source

+
+

get_unique_across_dfs

+
+
 get_unique_across_dfs (dfs:dict, col_name:str='NUCLIDE',
+                        as_df:bool=False, include_nchars:bool=False)
+
+

Get a list of unique column values across dataframes.

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
dfsdictDictionary of dataframes
col_namestrNUCLIDEColumn name to extract unique values from
as_dfboolFalseReturn a DataFrame of unique values
include_ncharsboolFalseAdd a column with the number of characters in the value
ReturnslistReturns a list of unique column values across dataframes
+
+
+Exported source +
def get_unique_across_dfs(dfs:dict,  # Dictionary of dataframes
+                          col_name:str='NUCLIDE', # Column name to extract unique values from
+                          as_df:bool=False, # Return a DataFrame of unique values
+                          include_nchars:bool=False # Add a column with the number of characters in the value
+                          ) -> list: # Returns a list of unique column values across dataframes
+    "Get a list of unique column values across dataframes."
+    unique_values = list(set().union(*(df[col_name].unique() for df in dfs.values() if col_name in df.columns)))
+    if not as_df:
+        return unique_values
+    else:
+        df_uniques = pd.DataFrame(unique_values, columns=['value']).reset_index()
+        if include_nchars: df_uniques['n_chars'] = df_uniques['value'].str.len()
+        return df_uniques
+
+
+

Example of use:

+
+
dfs_test = {'seawater': pd.DataFrame({'NUCLIDE': ['cs137', 'cs134_137_tot', 'cs134_137_tot']}),
+            'biota': pd.DataFrame({'NUCLIDE': ['cs137', 'cs134', 'cs134_137_tot']}),
+            'sediment': pd.DataFrame({'NUCLIDE': ['cs134_137_tot', 'cs134_137_tot', 'cs134_137_tot']})}
+
+fc.test_eq(set(get_unique_across_dfs(dfs_test, col_name='NUCLIDE')), 
+           set(['cs134', 'cs137', 'cs134_137_tot']))
+
+

What if the column name is not in one of the dataframe?

+
+
dfs_test = {'seawater': pd.DataFrame({'NUCLIDE': ['cs137', 'cs134_137_tot', 'cs134_137_tot']}),
+            'biota': pd.DataFrame({'NUCLIDE': ['cs137', 'cs134', 'cs134_137_tot']}),
+            'sediment': pd.DataFrame({'NONUCLIDE': ['cs134_137_tot', 'cs134_137_tot', 'cs134_137_tot']})}
+
+fc.test_eq(set(get_unique_across_dfs(dfs_test, col_name='NUCLIDE')), 
+           set(['cs134', 'cs137', 'cs134_137_tot']))
+
+
+
get_unique_across_dfs(dfs_test, col_name='NUCLIDE', as_df=True, include_nchars=True)
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
indexvaluen_chars
00cs1375
11cs134_137_tot13
22cs1345
+ +
+
+
+
+

source

+
+
+

Remapper

+
+
 Remapper (provider_lut_df:pandas.core.frame.DataFrame,
+           maris_lut_fn:<built-infunctioncallable>, maris_col_id:str,
+           maris_col_name:str, provider_col_to_match:str,
+           provider_col_key, fname_cache)
+
+

Remap a data provider lookup table to a MARIS lookup table using fuzzy matching.

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDetails
provider_lut_dfDataFrameData provider lookup table to be remapped
maris_lut_fncallableFunction that returns the MARIS lookup table path
maris_col_idstrMARIS lookup table column name for the id
maris_col_namestrMARIS lookup table column name for the name
provider_col_to_matchstrData provider lookup table column name for the name to match
provider_col_keyData provider lookup table column name for the key
fname_cacheCache file name
+
+
+Exported source +
class Remapper():
+    def __init__(self,
+                 provider_lut_df:pd.DataFrame, # Data provider lookup table to be remapped
+                 maris_lut_fn:callable, # Function that returns the MARIS lookup table path
+                 maris_col_id:str, # MARIS lookup table column name for the id
+                 maris_col_name:str, # MARIS lookup table column name for the name
+                 provider_col_to_match:str, # Data provider lookup table column name for the name to match
+                 provider_col_key, # Data provider lookup table column name for the key
+                 fname_cache  # Cache file name
+                 ):
+        "Remap a data provider lookup table to a MARIS lookup table using fuzzy matching."
+        fc.store_attr()
+        self.cache_file = cache_path() / fname_cache
+        self.maris_lut = maris_lut_fn()
+        self.lut = {}
+
+    def generate_lookup_table(self, 
+                              fixes={}, # Lookup table fixes
+                              as_df=True, # Whether to return a DataFrame
+                              overwrite=True):
+        "Generate a lookup table from a data provider lookup table to a MARIS lookup table using fuzzy matching."
+        self.fixes = fixes
+        self.as_df = as_df
+        if overwrite or not self.cache_file.exists():
+            self._create_lookup_table()
+            fc.save_pickle(self.cache_file, self.lut)
+        else:
+            self.lut = fc.load_pickle(self.cache_file)
+
+        return self._format_output()
+
+    def _create_lookup_table(self):
+        df = self.provider_lut_df
+        for _, row in tqdm(df.iterrows(), total=len(df), desc="Processing"): 
+            # print(row[self.provider_col_to_match])
+            self._process_row(row)
+
+    def _process_row(self, row):
+        value_to_match = row[self.provider_col_to_match]
+        if isinstance(value_to_match, str):  # Only process if value is a string
+            name_to_match = self.fixes.get(value_to_match, value_to_match)
+            
+            result = match_maris_lut(self.maris_lut, name_to_match, self.maris_col_id, self.maris_col_name).iloc[0]
+            match = Match(result[self.maris_col_id], result[self.maris_col_name], 
+                          value_to_match, result['score'])
+            self.lut[row[self.provider_col_key]] = match
+        else:
+            # Handle non-string values (e.g., NaN)
+            self.lut[row[self.provider_col_key]] = Match(-1, "Unknown", value_to_match, 0)
+            
+    def select_match(self, match_score_threshold:int=1):
+        self.lut = {k: v for k, v in self.lut.items() if v.match_score >= match_score_threshold}
+        return self._format_output()
+
+    def _format_output(self):
+        if not self.as_df: return self.lut
+        df_lut = pd.DataFrame.from_dict(self.lut, orient='index', 
+                                        columns=['matched_maris_name', 'source_name', 'match_score'])
+        df_lut.index.name = 'source_key'
+        return df_lut.sort_values(by='match_score', ascending=False)
+
+
+
+
+
+

Validation

+
+

source

+
+

has_valid_varname

+
+
 has_valid_varname (var_names:list, cdl_path:str, group=None)
+
+

Check that proposed variable names are in MARIS CDL

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
var_nameslistvariable names
cdl_pathstrPath to MARIS CDL file (point of truth)
groupNoneTypeNoneCheck if the variable names is contained in the group
+
+
+Exported source +
def has_valid_varname(
+    var_names:list, # variable names
+    cdl_path:str, # Path to MARIS CDL file (point of truth)
+    group = None, # Check if the variable names is contained in the group
+):
+    "Check that proposed variable names are in MARIS CDL"
+    has_valid = True
+    with Dataset(cdl_path) as nc:
+        cdl_vars={}
+        all_vars=[]
+        # get variable names in CDL 
+        for grp in nc.groups.values():
+            # Create a list of var for each group
+            vars = list(grp.variables.keys())
+            cdl_vars[grp.name] = vars
+            all_vars.extend(vars)
+        
+    if group != None:
+        allowed_vars= cdl_vars[group]
+    else: 
+        # get unique 
+        allowed_vars = list(set(all_vars))
+        
+    for name in var_names:
+        if name not in allowed_vars:
+            has_valid = False
+            if group != None:
+                print(f'"{name}" variable name not found in group "{group}" of MARIS CDL')
+            else:
+                print(f'"{name}" variable name not found in MARIS CDL')
+    return has_valid
+
+
+
+
VARNAMES = ['lat', 'lon']
+test_eq(has_valid_varname(VARNAMES, './files/nc/maris-cdl.nc'), True)
+
+
+
VARNAMES = ['ba140_invalid', 'ba140_dl']
+test_eq(has_valid_varname(VARNAMES, './files/nc/maris-cdl.nc'), False)
+
+
"ba140_invalid" variable name not found in MARIS CDL
+
+
+
+
+
+

Geoprocessing

+
+

source

+
+

get_bbox

+
+
 get_bbox (df, coord_cols=('lon', 'lat'))
+
+
+
+Exported source +
def get_bbox(df,
+             coord_cols=('lon', 'lat')
+            ):
+    x, y = coord_cols        
+    arr = [(row[x], row[y]) for _, row in df.iterrows()]
+    return MultiPoint(arr).envelope
+
+
+
+
df = pd.DataFrame({'lon': np.linspace(-10, 5, 20), 'lat':  np.linspace(40, 50, 20)})
+bbox = get_bbox(df);
+
+
+
# To get `lon_min`, `lon_max`, `lat_min`, `lat_max`
+bbox.bounds
+
+
(-10.0, 40.0, 5.0, 50.0)
+
+
+
+
# And its Well-Know Text representation
+bbox.wkt
+
+
'POLYGON ((-10 40, 5 40, 5 50, -10 50, -10 40))'
+
+
+
+
# If unique (lon, lat)
+df = pd.DataFrame({'lon': [0, 0], 'lat':  [1, 1]})
+bbox = get_bbox(df);
+
+
+
bbox.bounds
+
+
(0.0, 1.0, 0.0, 1.0)
+
+
+
+
+
+

Downloaders

+
+

source

+
+

download_file

+
+
 download_file (owner, repo, src_dir, dest_dir, fname)
+
+
+
+Exported source +
def download_files_in_folder(owner:str, 
+                             repo:str, 
+                             src_dir:str, 
+                             dest_dir:str
+                             ):
+    "Make a GET request to the GitHub API to get the contents of the folder"
+    url = f"https://api.github.com/repos/{owner}/{repo}/contents/{src_dir}"
+    response = requests.get(url)
+
+    if response.status_code == 200:
+        contents = response.json()
+
+        # Iterate over the files and download them
+        for item in contents:
+            if item["type"] == "file":
+                fname = item["name"]
+                download_file(owner, repo, src_dir, dest_dir, fname)
+    else:
+        print(f"Error: {response.status_code}")
+
+def download_file(owner, repo, src_dir, dest_dir, fname):
+    # Make a GET request to the GitHub API to get the raw file contents
+    url = f"https://raw.githubusercontent.com/{owner}/{repo}/master/{src_dir}/{fname}"
+    response = requests.get(url)
+
+    if response.status_code == 200:
+        # Save the file locally
+        with open(Path(dest_dir) / fname, "wb") as file:
+            file.write(response.content)
+        print(f"{fname} downloaded successfully.")
+    else:
+        print(f"Error: {response.status_code}")
+
+
+
+

source

+
+
+

download_files_in_folder

+
+
 download_files_in_folder (owner:str, repo:str, src_dir:str, dest_dir:str)
+
+

Make a GET request to the GitHub API to get the contents of the folder

+
+
+
+

WorRMS

+

The World Register of Marine Species (WorMS) is an authoritative classification and catalogue of marine names. It provides a REST API (among others) allowing to “fuzzy” match any species name you might encounter in marine data sources names againt their own database. There are several types of matches as described here.

+
+

source

+
+

match_worms

+
+
 match_worms (name:str)
+
+

Lookup name in WoRMS (fuzzy match)

+ + + + + + + + + + + + + + + +
TypeDetails
namestrName of species to look up in WoRMS
+
+
+Exported source +
def match_worms(
+    name:str # Name of species to look up in WoRMS
+    ):
+    "Lookup `name` in WoRMS (fuzzy match)"
+    url = 'https://www.marinespecies.org/rest/AphiaRecordsByMatchNames'
+    params = {
+        'scientificnames[]': [name],
+        'marine_only': 'true'
+    }
+    headers = {
+        'accept': 'application/json'
+    }
+    
+    response = requests.get(url, params=params, headers=headers)
+    
+    # Check if the request was successful (status code 200)
+    if response.status_code == 200:
+        data = response.json()
+        return data
+    else:
+        return -1
+
+
+

For instance:

+
+
match_worms('Aristeus antennatus')
+
+
[[{'AphiaID': 107083,
+   'url': 'https://www.marinespecies.org/aphia.php?p=taxdetails&id=107083',
+   'scientificname': 'Aristeus antennatus',
+   'authority': '(Risso, 1816)',
+   'status': 'accepted',
+   'unacceptreason': None,
+   'taxonRankID': 220,
+   'rank': 'Species',
+   'valid_AphiaID': 107083,
+   'valid_name': 'Aristeus antennatus',
+   'valid_authority': '(Risso, 1816)',
+   'parentNameUsageID': 106807,
+   'kingdom': 'Animalia',
+   'phylum': 'Arthropoda',
+   'class': 'Malacostraca',
+   'order': 'Decapoda',
+   'family': 'Aristeidae',
+   'genus': 'Aristeus',
+   'citation': 'DecaNet eds. (2024). DecaNet. Aristeus antennatus (Risso, 1816). Accessed through: World Register of Marine Species at: https://www.marinespecies.org/aphia.php?p=taxdetails&id=107083 on 2024-06-10',
+   'lsid': 'urn:lsid:marinespecies.org:taxname:107083',
+   'isMarine': 1,
+   'isBrackish': 0,
+   'isFreshwater': 0,
+   'isTerrestrial': 0,
+   'isExtinct': 0,
+   'match_type': 'exact',
+   'modified': '2022-08-24T09:48:14.813Z'}]]
+
+
+
+
# open dbo_species
+#from tqdm import tqdm
+#results = []
+#species = pd.read_excel(species_lut_path()).species
+#for i, name in tqdm(enumerate(species), total=len(species)):
+#    if i > 1:
+#        worms_match = match_worms(name)
+#        if worms_match != -1:
+#            results.append(worms_match[0][0])
+
+
+
# np.unique(np.array([result['phylum'] for result in results]))
+
+
+
#len(maris_worms_matches)
+
+
+
#maris_worms_matches = fc.load_pickle('./files/pkl/maris-worms-matches.pkl')
+
+
+
#np.unique(np.array([result['phylum'] for result in maris_worms_matches]))
+
+
+
#len([result for result in maris_worms_matches if result['status'] == 'accepted'])
+
+
+
+
+

Fuzzy matching for MARIS Lookup Tables

+

Using https://jamesturk.github.io/jellyfish fuzzy matching distance metrics.

+
+

source

+
+

Match

+
+
 Match (matched_id:int, matched_maris_name:str, source_name:str,
+        match_score:int)
+
+
+
+Exported source +
@dataclass
+class Match:
+    matched_id: int
+    matched_maris_name: str
+    source_name: str
+    match_score: int
+
+
+
+

source

+
+
+

match_maris_lut

+
+
 match_maris_lut (lut_path:str, data_provider_name:str, maris_id:str,
+                  maris_name:str, dist_fn:collections.abc.Callable=<built-
+                  in function levenshtein_distance>, nresults:int=10)
+
+

Fuzzy matching data provider and MARIS lookup tables (e.g biota species, sediments, …).

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
lut_pathstrPath to MARIS species authoritative species look-up table
data_provider_namestrName of data provider nomenclature item to look up
maris_idstrId of MARIS lookup table nomenclature item to match
maris_namestrName of MARIS lookup table nomenclature item to match
dist_fnCallablelevenshtein_distanceDistance function
nresultsint10Maximum number of results to return
ReturnsDataFrame
+
+
+Exported source +
def match_maris_lut(
+    lut_path: str, # Path to MARIS species authoritative species look-up table
+    data_provider_name: str, # Name of data provider nomenclature item to look up 
+    maris_id: str, # Id of MARIS lookup table nomenclature item to match
+    maris_name: str, # Name of MARIS lookup table nomenclature item to match
+    dist_fn: Callable = jf.levenshtein_distance, # Distance function
+    nresults: int = 10 # Maximum number of results to return
+) -> pd.DataFrame:
+    "Fuzzy matching data provider and MARIS lookup tables (e.g biota species, sediments, ...)."
+    df = pd.read_excel(lut_path)
+    df = df.dropna(subset=[maris_name])
+    df = df.astype({maris_id: 'int'})
+    df['score'] = df[maris_name].str.lower().apply(lambda x: dist_fn(data_provider_name.lower(), x))
+    df = df.sort_values(by='score', ascending=True)[:nresults]
+    return df[[maris_id, maris_name, 'score']]
+
+
+

Below an example trying to match the name “PLANKTON” with dbo_species_cleaned.xlsx MARIS biota species lookup table:

+
+
lut_fname = '../files/lut/dbo_species_cleaned.xlsx'
+match_maris_lut(lut_fname, data_provider_name='PLANKTON', 
+                maris_id='species_id', maris_name='species')
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
species_idspeciesscore
281280Plankton0
696695Zooplankton3
633632Palaemon4
697696Phytoplankton5
812811Chanos5
160159Neuston5
234233Penaeus6
14581457Lamnidae6
14381437Labrus6
15271526Favites6
+ +
+
+
+

Below an example trying to match the name “GLACIAL” with dbo_sedtype.xlsx MARIS sediment lookup table:

+
+
# sediments_lut_path()
+lut_fname = '../files/lut/dbo_sedtype.xlsx'
+match_maris_lut(lut_fname, data_provider_name='GLACIAL', 
+                maris_id='sedtype_id', maris_name='sedtype')
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
sedtype_idsedtypescore
2625Glacial0
32Gravel4
21Clay5
5150Glacial clay5
43Marsh6
76Sand6
1312Silt6
1514Sludge6
2726Soft7
5251Soft clay7
+ +
+
+
+
+
lut_fname = '../files/lut/dbo_nuclide.xlsx'
+match_maris_lut(lut_fname, data_provider_name='CS-137', 
+                maris_id='nuclide_id', maris_name='nc_name')
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
nuclide_idnc_namescore
3133cs1371
3031cs1342
99102cs1362
2930cs1272
111114ce1393
109112sb1273
87co574
2829i1314
7174cm2434
9093sn117m4
+ +
+
+
+
+
+
+

Geoprocessing

+
+

source

+
+

get_bbox

+
+
 get_bbox (df, coord_cols=('lon', 'lat'))
+
+
+
df = pd.DataFrame({'lon': np.linspace(-10, 5, 20), 'lat':  np.linspace(40, 50, 20)})
+bbox = get_bbox(df);
+
+
+
# To get `lon_min`, `lon_max`, `lat_min`, `lat_max`
+bbox.bounds
+
+
(-10.0, 40.0, 5.0, 50.0)
+
+
+
+
# And its Well-Know Text representation
+bbox.wkt
+
+
'POLYGON ((-10 40, 5 40, 5 50, -10 50, -10 40))'
+
+
+
+
# If unique (lon, lat)
+df = pd.DataFrame({'lon': [0, 0], 'lat':  [1, 1]})
+bbox = get_bbox(df);
+
+
+
bbox.bounds
+
+
(0.0, 1.0, 0.0, 1.0)
+
+
+
+
+
+

Downloaders

+
+

source

+
+

download_file

+
+
 download_file (owner, repo, src_dir, dest_dir, fname)
+
+
+

source

+
+
+

download_files_in_folder

+
+
 download_files_in_folder (owner:str, repo:str, src_dir:str, dest_dir:str)
+
+

Make a GET request to the GitHub API to get the contents of the folder

+
+
+
+

WorRMS

+

The World Register of Marine Species (WorMS) is an authoritative classification and catalogue of marine names. It provides a REST API (among others) allowing to “fuzzy” match any species name you might encounter in marine data sources names againt their own database. There are several types of matches as described here.

+
+

source

+
+

match_worms

+
+
 match_worms (name:str)
+
+

Lookup name in WoRMS (fuzzy match)

+ + + + + + + + + + + + + + + +
TypeDetails
namestrName of species to look up in WoRMS
+

For instance:

+
+
match_worms('Aristeus antennatus')
+
+
[[{'AphiaID': 107083,
+   'url': 'https://www.marinespecies.org/aphia.php?p=taxdetails&id=107083',
+   'scientificname': 'Aristeus antennatus',
+   'authority': '(Risso, 1816)',
+   'status': 'accepted',
+   'unacceptreason': None,
+   'taxonRankID': 220,
+   'rank': 'Species',
+   'valid_AphiaID': 107083,
+   'valid_name': 'Aristeus antennatus',
+   'valid_authority': '(Risso, 1816)',
+   'parentNameUsageID': 106807,
+   'kingdom': 'Animalia',
+   'phylum': 'Arthropoda',
+   'class': 'Malacostraca',
+   'order': 'Decapoda',
+   'family': 'Aristeidae',
+   'genus': 'Aristeus',
+   'citation': 'DecaNet eds. (2024). DecaNet. Aristeus antennatus (Risso, 1816). Accessed through: World Register of Marine Species at: https://www.marinespecies.org/aphia.php?p=taxdetails&id=107083 on 2024-06-10',
+   'lsid': 'urn:lsid:marinespecies.org:taxname:107083',
+   'isMarine': 1,
+   'isBrackish': 0,
+   'isFreshwater': 0,
+   'isTerrestrial': 0,
+   'isExtinct': 0,
+   'match_type': 'exact',
+   'modified': '2022-08-24T09:48:14.813Z'}]]
+
+
+
+
# open dbo_species
+#from tqdm import tqdm
+#results = []
+#species = pd.read_excel(species_lut_path()).species
+#for i, name in tqdm(enumerate(species), total=len(species)):
+#    if i > 1:
+#        worms_match = match_worms(name)
+#        if worms_match != -1:
+#            results.append(worms_match[0][0])
+
+
+
# np.unique(np.array([result['phylum'] for result in results]))
+
+
array(['Annelida', 'Arthropoda', 'Bryozoa', 'Chaetognatha', 'Charophyta',
+       'Chlorophyta', 'Chordata', 'Cnidaria', 'Ctenophora',
+       'Echinodermata', 'Mollusca', 'Myzozoa', 'Ochrophyta', 'Porifera',
+       'Rhodophyta', 'Tracheophyta'], dtype='<U13')
+
+
+
+
#len(maris_worms_matches)
+
+
+
#maris_worms_matches = fc.load_pickle('./files/pkl/maris-worms-matches.pkl')
+
+
+
#np.unique(np.array([result['phylum'] for result in maris_worms_matches]))
+
+
+
#len([result for result in maris_worms_matches if result['status'] == 'accepted'])
+
+
+
#match_maris_sediment('GLACIAL')
+
+
+
+
+

Test

+
+

source

+
+

test_dfs

+
+
 test_dfs (dfs1:dict, dfs2:dict)
+
+

Compare two dictionaries of DataFrames for equality (also ensuring that columns are in the same order).

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDetails
dfs1dictFirst dictionary of DataFrames to compare
dfs2dictSecond dictionary of DataFrames to compare
ReturnsNoneIt raises an AssertionError if the DataFrames are not equal
+
+
+Exported source +
def test_dfs(
+    dfs1:dict, # First dictionary of DataFrames to compare 
+    dfs2:dict # Second dictionary of DataFrames to compare
+    ) -> None: # It raises an `AssertionError` if the DataFrames are not equal
+    "Compare two dictionaries of DataFrames for equality (also ensuring that columns are in the same order)."
+    for grp in dfs1.keys():
+        df1, df2 = (df.sort_index() for df in (dfs1[grp], dfs2[grp]))
+        fc.test_eq(df1, df2.reindex(columns=df1.columns))
+
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/cli/create_nc_template.html b/cli/create_nc_template.html new file mode 100644 index 0000000..8bd808b --- /dev/null +++ b/cli/create_nc_template.html @@ -0,0 +1,729 @@ + + + + + + + + + +create_nc_template – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ + + + + +
+

source

+
+

main

+
+
 main (verbose:bool=False)
+
+

Create MARIS NetCDF template, optionally in verbose mode

+ + + + + + + + + + + + + + + + + +
TypeDefaultDetails
verboseboolFalseVerbose
+ + +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/cli/init.html b/cli/init.html new file mode 100644 index 0000000..fe95bcf --- /dev/null +++ b/cli/init.html @@ -0,0 +1,752 @@ + + + + + + + + + +init – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ + + + + +
+
+
+
The autoreload extension is already loaded. To reload it, use:
+  %reload_ext autoreload
+
+
+
+

source

+
+

main

+
+
 main ()
+
+

Create configuration files & download lookup tables

+ + +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/cli/netcdfy.html b/cli/netcdfy.html new file mode 100644 index 0000000..8435dc2 --- /dev/null +++ b/cli/netcdfy.html @@ -0,0 +1,787 @@ + + + + + + + + + +netcdfy – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ + + + + +
+
+
+
The autoreload extension is already loaded. To reload it, use:
+  %reload_ext autoreload
+
+
+
+

source

+
+

import_handler

+
+
 import_handler (handler_name, fn_name='encode')
+
+
+

source

+
+
+

main

+
+
 main (handler_name:str, src:str, dest:str)
+
+

Encode MARIS dataset as NetCDF

+ + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDetails
handler_namestrHandler’s name (e.g helcom, …)
srcstrPath to dataset to encode
deststrPath to converted NetCDF4
+ + +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/handlers/geotraces.html b/handlers/geotraces.html new file mode 100644 index 0000000..3b0bdfa --- /dev/null +++ b/handlers/geotraces.html @@ -0,0 +1,2853 @@ + + + + + + + + + + +Geotraces – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Geotraces

+
+ +
+
+ Data pipeline (handler) to convert BODC Geotraces seawater dataset +
+
+ + +
+ + + + +
+ + + +
+ + + +

TODO & QUESTIONS:

+ +
+

Packages import

+
+
+
+
The autoreload extension is already loaded. To reload it, use:
+  %reload_ext autoreload
+
+
+
+
pd.set_option('display.max_rows', 100)
+
+
+
import warnings
+warnings.filterwarnings('ignore')
+
+
+
+

Input and output file names

+
+
+

Load data

+
+
df = pd.read_csv(fname_in)
+df.head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CruiseStation:METAVAR:INDEXED_TEXTTypeyyyy-mm-ddThh:mm:ss.sssLongitude [degrees_east]Latitude [degrees_north]Bot. Depth [m]Operator's Cruise Name:METAVAR:INDEXED_TEXTShip Name:METAVAR:INDEXED_TEXTPeriod:METAVAR:INDEXED_TEXT...QV:SEADATANET.581Co_CELL_CONC_BOTTLE [amol/cell]QV:SEADATANET.582Ni_CELL_CONC_BOTTLE [amol/cell]QV:SEADATANET.583Cu_CELL_CONC_BOTTLE [amol/cell]QV:SEADATANET.584Zn_CELL_CONC_BOTTLE [amol/cell]QV:SEADATANET.585QV:ODV:SAMPLE
0GA010B2014-05-17T22:29:00349.2999938.43294854.0GEOVIDEPourquoi pas?15/05/2014 - 30/06/2014...9NaN9NaN9NaN9NaN91
1GA010B2014-05-17T22:29:00349.2999938.43294854.0GEOVIDEPourquoi pas?15/05/2014 - 30/06/2014...9NaN9NaN9NaN9NaN91
2GA010B2014-05-17T22:29:00349.2999938.43294854.0GEOVIDEPourquoi pas?15/05/2014 - 30/06/2014...9NaN9NaN9NaN9NaN91
3GA010B2014-05-17T22:29:00349.2999938.43294854.0GEOVIDEPourquoi pas?15/05/2014 - 30/06/2014...9NaN9NaN9NaN9NaN91
4GA010B2014-05-17T22:29:00349.2999938.43294854.0GEOVIDEPourquoi pas?15/05/2014 - 30/06/2014...9NaN9NaN9NaN9NaN91
+ +

5 rows × 1188 columns

+
+
+
+
+
def find_print_col(s, cols, lower=True):
+    cols = cols if not lower else [col.lower() for col in cols]
+    for col in cols:
+        if s in col: print(col)
+
+find_print_col('sal', df.columns)
+find_print_col('tmp', df.columns)
+find_print_col('oxy', df.columns)
+find_print_col('U_236_238', df.columns, lower=False)
+
+
ctdsal_d_conc_sensor [pss-78]
+salinity_d_conc_bottle
+salinity_d_conc_pump
+salinity_d_conc_fish
+salinity_d_conc_uway
+salinity_d_conc_boat_pump
+ctdtmp_t_value_sensor [deg c]
+oxygen_d_conc_bottle [umol/kg]
+ctdoxy_d_conc_sensor [umol/kg]
+U_236_238_T_RATIO_BOTTLE [per 10^12]
+
+
+
+
+

Data transformation pipeline

+
+

Select columns of interest

+
+
# U_236_238
+# Done: Th_232, I_129, Ac_227
+
+
+

source

+
+
+

SelectColsOfInterestCB

+
+
 SelectColsOfInterestCB (common_coi, nuclides_pattern)
+
+

Select columns of interest.

+
+
df = pd.read_csv(fname_in)
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern)
+])
+
+
+
df_test = tfm()
+df_test.head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
yyyy-mm-ddThh:mm:ss.sssLongitude [degrees_east]Latitude [degrees_north]Bot. Depth [m]DEPTH [m]TRITIUM_D_CONC_BOTTLE [TU]Cs_137_D_CONC_BOTTLE [uBq/kg]I_129_D_CONC_BOTTLE [atoms/kg]Np_237_D_CONC_BOTTLE [uBq/kg]Pu_239_D_CONC_BOTTLE [uBq/kg]...Th_230_TP_CONC_PUMP [uBq/kg]Th_230_SPT_CONC_PUMP [uBq/kg]Th_230_LPT_CONC_PUMP [uBq/kg]Th_232_TP_CONC_PUMP [pmol/kg]Th_232_SPT_CONC_PUMP [pmol/kg]Th_232_LPT_CONC_PUMP [pmol/kg]Th_234_SPT_CONC_PUMP [mBq/kg]Th_234_LPT_CONC_PUMP [mBq/kg]Po_210_TP_CONC_UWAY [mBq/kg]Pb_210_TP_CONC_UWAY [mBq/kg]
02014-05-17T22:29:00349.2999938.43294854.02957.1NaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
12014-05-17T22:29:00349.2999938.43294854.02957.2NaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
22014-05-17T22:29:00349.2999938.43294854.02957.2NaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
32014-05-17T22:29:00349.2999938.43294854.02957.2NaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
42014-05-17T22:29:00349.2999938.43294854.02957.2NaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
+ +

5 rows × 85 columns

+
+
+
+
+
+

Reshape: wide to long

+

So that we can extract information such as sample methodology, filtering status, units included in Geotraces nuclides name.

+
+

source

+
+
+

WideToLongCB

+
+
 WideToLongCB (common_coi, nuclides_pattern, var_name='nuclide',
+               value_name='value')
+
+

Get Geotraces nuclide names as values not column names to extract contained information (unit, sampling method, …).

+
+
df = pd.read_csv(fname_in)
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern),
+    WideToLongCB(common_coi, nuclides_pattern)
+])
+
+df_test = tfm()
+df_test.shape
+
+
(26745, 7)
+
+
+
+
+

Extract

+
+

Unit

+
+

source

+
+
+
+

ExtractUnitCB

+
+
 ExtractUnitCB (var_name='nuclide')
+
+

Extract units from nuclide names.

+
+
df = pd.read_csv(fname_in)
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern),
+    WideToLongCB(common_coi, nuclides_pattern),
+    ExtractUnitCB()
+])
+
+df_test = tfm()
+df_test.head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
yyyy-mm-ddThh:mm:ss.sssLongitude [degrees_east]Latitude [degrees_north]Bot. Depth [m]DEPTH [m]nuclidevalue_unit
92232010-10-17T00:13:29350.3379238.32712827.017.8TRITIUM_D_CONC_BOTTLE [TU]0.733TU
92312010-10-17T00:13:29350.3379238.32712827.034.7TRITIUM_D_CONC_BOTTLE [TU]0.696TU
92372010-10-17T00:13:29350.3379238.32712827.067.5TRITIUM_D_CONC_BOTTLE [TU]0.718TU
92442010-10-17T00:13:29350.3379238.32712827.091.9TRITIUM_D_CONC_BOTTLE [TU]0.709TU
92562010-10-17T00:13:29350.3379238.32712827.0136.6TRITIUM_D_CONC_BOTTLE [TU]0.692TU
+ +
+
+
+
+

Filtering status

+
+
#\export
+phase = {
+    'D': {'filt': 1, 'group': 'seawater'},
+    'T': {'filt': 2, 'group': 'seawater'},
+    'TP': {'filt': 1, 'group': 'suspended-matter'}, 
+    'LPT': {'filt': 1, 'group': 'suspended-matter'},
+    'SPT': {'filt': 1, 'group': 'suspended-matter'}}
+
+
+

source

+
+
+
+

ExtractFilteringStatusCB

+
+
 ExtractFilteringStatusCB (phase, var_name='nuclide')
+
+

Extract filtering status from nuclide names.

+
+
df = pd.read_csv(fname_in)
+
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern),
+    WideToLongCB(common_coi, nuclides_pattern),
+    ExtractUnitCB(),
+    ExtractFilteringStatusCB(phase)
+])
+
+df_test = tfm()
+df_test.head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
yyyy-mm-ddThh:mm:ss.sssLongitude [degrees_east]Latitude [degrees_north]Bot. Depth [m]DEPTH [m]nuclidevalue_unit_filtgroup
92232010-10-17T00:13:29350.3379238.32712827.017.8TRITIUM_D_CONC_BOTTLE [TU]0.733TU1seawater
92312010-10-17T00:13:29350.3379238.32712827.034.7TRITIUM_D_CONC_BOTTLE [TU]0.696TU1seawater
92372010-10-17T00:13:29350.3379238.32712827.067.5TRITIUM_D_CONC_BOTTLE [TU]0.718TU1seawater
92442010-10-17T00:13:29350.3379238.32712827.091.9TRITIUM_D_CONC_BOTTLE [TU]0.709TU1seawater
92562010-10-17T00:13:29350.3379238.32712827.0136.6TRITIUM_D_CONC_BOTTLE [TU]0.692TU1seawater
+ +
+
+
+
+

Sampling method

+
+
#\export
+# To be validated
+smp_method = {
+    'BOTTLE': 1,
+    'FISH': 18,
+    'PUMP': 14,
+    'UWAY': 24}
+
+
+

source

+
+
+
+

ExtractSamplingMethodCB

+
+
 ExtractSamplingMethodCB (smp_method, var_name='nuclide')
+
+

Extract sampling method from nuclide names.

+
+
df = pd.read_csv(fname_in)
+
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern),
+    WideToLongCB(common_coi, nuclides_pattern),
+    ExtractUnitCB(),
+    ExtractFilteringStatusCB(phase),
+    ExtractSamplingMethodCB(smp_method)
+])
+
+df_test = tfm()
+df_test.head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
yyyy-mm-ddThh:mm:ss.sssLongitude [degrees_east]Latitude [degrees_north]Bot. Depth [m]DEPTH [m]nuclidevalue_unit_filtgroup_sampmet
92232010-10-17T00:13:29350.3379238.32712827.017.8TRITIUM_D_CONC_BOTTLE [TU]0.733TU1seawater1
92312010-10-17T00:13:29350.3379238.32712827.034.7TRITIUM_D_CONC_BOTTLE [TU]0.696TU1seawater1
92372010-10-17T00:13:29350.3379238.32712827.067.5TRITIUM_D_CONC_BOTTLE [TU]0.718TU1seawater1
92442010-10-17T00:13:29350.3379238.32712827.091.9TRITIUM_D_CONC_BOTTLE [TU]0.709TU1seawater1
92562010-10-17T00:13:29350.3379238.32712827.0136.6TRITIUM_D_CONC_BOTTLE [TU]0.692TU1seawater1
+ +
+
+
+
+
+

Remap to MARIS nuclide names

+
+
#\export
+nuclides_name = {'TRITIUM': 'h3', 'Pu_239_Pu_240': 'pu239_240_tot'}
+
+
+

source

+
+
+

RenameNuclideCB

+
+
 RenameNuclideCB (nuclides_name, var_name='nuclide')
+
+

Remap nuclides name to MARIS standard.

+
+
df = pd.read_csv(fname_in)
+
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern),
+    WideToLongCB(common_coi, nuclides_pattern),
+    ExtractUnitCB(),
+    ExtractFilteringStatusCB(phase),
+    ExtractSamplingMethodCB(smp_method),
+    RenameNuclideCB(nuclides_name)
+])
+
+df_test = tfm()
+df_test.head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
yyyy-mm-ddThh:mm:ss.sssLongitude [degrees_east]Latitude [degrees_north]Bot. Depth [m]DEPTH [m]nuclidevalue_unit_filtgroup_sampmet
92232010-10-17T00:13:29350.3379238.32712827.017.8h30.733TU1seawater1
92312010-10-17T00:13:29350.3379238.32712827.034.7h30.696TU1seawater1
92372010-10-17T00:13:29350.3379238.32712827.067.5h30.718TU1seawater1
92442010-10-17T00:13:29350.3379238.32712827.091.9h30.709TU1seawater1
92562010-10-17T00:13:29350.3379238.32712827.0136.6h30.692TU1seawater1
+ +
+
+
+
+
df_test.nuclide.unique()
+
+
array(['h3', 'cs137', 'i129', 'np237', 'pu239', 'pu239_240_tot', 'pu240',
+       'u236', 'pa231', 'pb210', 'po210', 'ra224', 'ra226', 'ra228',
+       'th230', 'th232', 'th234', 'ac227', 'be7', 'ra223', 'th228'],
+      dtype=object)
+
+
+
+
+

Standardize unit

+
+
#\export
+units_lut = {
+    'TU': {'id': 7, 'factor': 1},
+    'uBq/kg': {'id': 3, 'factor': 1e-6},
+    'atoms/kg': {'id': 9, 'factor': 1},
+    'mBq/kg': {'id': 3, 'factor': 1e-3}}
+
+
+

source

+
+
+

StandardizeUnitCB

+
+
 StandardizeUnitCB (units_lut, var_name='value')
+
+

Remap unit to MARIS standard ones and apply conversion where needed.

+
+
df = pd.read_csv(fname_in)
+
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern),
+    WideToLongCB(common_coi, nuclides_pattern),
+    ExtractUnitCB(),
+    ExtractFilteringStatusCB(phase),
+    ExtractSamplingMethodCB(smp_method),
+    RenameNuclideCB(nuclides_name),
+    StandardizeUnitCB(units_lut)
+])
+
+df_test = tfm()
+print(df_test.head())
+print(df_test.columns)
+
+
     yyyy-mm-ddThh:mm:ss.sss  Longitude [degrees_east]  \
+9223     2010-10-17T00:13:29                 350.33792   
+9231     2010-10-17T00:13:29                 350.33792   
+9237     2010-10-17T00:13:29                 350.33792   
+9244     2010-10-17T00:13:29                 350.33792   
+9256     2010-10-17T00:13:29                 350.33792   
+
+      Latitude [degrees_north]  Bot. Depth [m]  DEPTH [m] nuclide  value  \
+9223                   38.3271          2827.0       17.8      h3  0.733   
+9231                   38.3271          2827.0       34.7      h3  0.696   
+9237                   38.3271          2827.0       67.5      h3  0.718   
+9244                   38.3271          2827.0       91.9      h3  0.709   
+9256                   38.3271          2827.0      136.6      h3  0.692   
+
+      _unit  _filt     group  _sampmet  
+9223    7.0      1  seawater         1  
+9231    7.0      1  seawater         1  
+9237    7.0      1  seawater         1  
+9244    7.0      1  seawater         1  
+9256    7.0      1  seawater         1  
+Index(['yyyy-mm-ddThh:mm:ss.sss', 'Longitude [degrees_east]',
+       'Latitude [degrees_north]', 'Bot. Depth [m]', 'DEPTH [m]', 'nuclide',
+       'value', '_unit', '_filt', 'group', '_sampmet'],
+      dtype='object')
+
+
+
+
+

Rename common columns

+
+

source

+
+
+

renaming_rules

+
+
 renaming_rules ()
+
+
+

source

+
+
+

RenameColumnCB

+
+
 RenameColumnCB (renaming_rules=<function renaming_rules>)
+
+

Renaming variables to MARIS standard names.

+
+
df = pd.read_csv(fname_in)
+
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern),
+    WideToLongCB(common_coi, nuclides_pattern),
+    ExtractUnitCB(),
+    ExtractFilteringStatusCB(phase),
+    ExtractSamplingMethodCB(smp_method),
+    RenameNuclideCB(nuclides_name),
+    StandardizeUnitCB(units_lut),
+    RenameColumnCB(renaming_rules)
+])
+
+df_test = tfm()
+df_test.head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
timelonlattot_depthsmp_depthnuclidevalue_unit_filtgroup_sampmet
92232010-10-17T00:13:29350.3379238.32712827.017.8h30.7337.01seawater1
92312010-10-17T00:13:29350.3379238.32712827.034.7h30.6967.01seawater1
92372010-10-17T00:13:29350.3379238.32712827.067.5h30.7187.01seawater1
92442010-10-17T00:13:29350.3379238.32712827.091.9h30.7097.01seawater1
92562010-10-17T00:13:29350.3379238.32712827.0136.6h30.6927.01seawater1
+ +
+
+
+
+
+

Unshift longitudes

+
+

source

+
+
+

UnshiftLongitudeCB

+
+
 UnshiftLongitudeCB ()
+
+

Longitudes are coded between 0 and 360 in Geotraces. We rescale it between -180 and 180 instead.

+
+
df = pd.read_csv(fname_in)
+
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern),
+    WideToLongCB(common_coi, nuclides_pattern),
+    ExtractUnitCB(),
+    ExtractFilteringStatusCB(phase),
+    ExtractSamplingMethodCB(smp_method),
+    RenameNuclideCB(nuclides_name),
+    StandardizeUnitCB(units_lut),
+    RenameColumnCB(renaming_rules),
+    UnshiftLongitudeCB()
+])
+
+df_test = tfm()
+df_test.head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
timelonlattot_depthsmp_depthnuclidevalue_unit_filtgroup_sampmet
92232010-10-17T00:13:29170.3379238.32712827.017.8h30.7337.01seawater1
92312010-10-17T00:13:29170.3379238.32712827.034.7h30.6967.01seawater1
92372010-10-17T00:13:29170.3379238.32712827.067.5h30.7187.01seawater1
92442010-10-17T00:13:29170.3379238.32712827.091.9h30.7097.01seawater1
92562010-10-17T00:13:29170.3379238.32712827.0136.6h30.6927.01seawater1
+ +
+
+
+
+
+

Dispatch to groups

+
+

source

+
+
+

DispatchToGroupCB

+
+
 DispatchToGroupCB (group_name='group')
+
+

Convert to a dictionary of dataframe with sample type (seawater,…) as keys.

+
+
df = pd.read_csv(fname_in)
+
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern),
+    WideToLongCB(common_coi, nuclides_pattern),
+    ExtractUnitCB(),
+    ExtractFilteringStatusCB(phase),
+    ExtractSamplingMethodCB(smp_method),
+    RenameNuclideCB(nuclides_name),
+    StandardizeUnitCB(units_lut),
+    RenameColumnCB(renaming_rules),
+    UnshiftLongitudeCB(),
+    DispatchToGroupCB()
+])
+
+tfm()
+
+
{'seawater':                         time        lon      lat  tot_depth  smp_depth  \
+ 9223     2010-10-17T00:13:29  170.33792  38.3271     2827.0       17.8   
+ 9231     2010-10-17T00:13:29  170.33792  38.3271     2827.0       34.7   
+ 9237     2010-10-17T00:13:29  170.33792  38.3271     2827.0       67.5   
+ 9244     2010-10-17T00:13:29  170.33792  38.3271     2827.0       91.9   
+ 9256     2010-10-17T00:13:29  170.33792  38.3271     2827.0      136.6   
+ ...                      ...        ...      ...        ...        ...   
+ 6173855  2015-09-04T09:15:18    3.25999  88.4058     3960.0        5.0   
+ 6173858  2015-09-04T09:15:18    3.25999  88.4058     3960.0       20.0   
+ 6174035  2015-09-07T14:20:39  -90.74920  89.9809     4229.0        0.5   
+ 6174038  2015-09-07T14:20:39  -90.74920  89.9809     4229.0        1.5   
+ 6174041  2015-09-07T14:20:39  -90.74920  89.9809     4229.0        5.0   
+ 
+         nuclide   value  _unit  _filt  _sampmet  
+ 9223         h3  0.7330    7.0      1         1  
+ 9231         h3  0.6960    7.0      1         1  
+ 9237         h3  0.7180    7.0      1         1  
+ 9244         h3  0.7090    7.0      1         1  
+ 9256         h3  0.6920    7.0      1         1  
+ ...         ...     ...    ...    ...       ...  
+ 6173855   th234  0.0294    3.0      2        14  
+ 6173858   th234  0.0347    3.0      2        14  
+ 6174035   th234  0.0279    3.0      2        14  
+ 6174038   th234  0.0282    3.0      2        14  
+ 6174041   th234  0.0323    3.0      2        14  
+ 
+ [19139 rows x 10 columns],
+ 'suspended-matter':                         time        lon      lat  tot_depth  smp_depth  \
+ 6260008  2008-02-13T21:05:05 -171.00616 -42.3413     4569.0       24.8   
+ 6260022  2008-02-13T21:05:05 -171.00616 -42.3413     4569.0      100.2   
+ 6260033  2008-02-13T21:05:05 -171.00616 -42.3413     4569.0      200.3   
+ 6260044  2008-02-13T21:05:05 -171.00616 -42.3413     4569.0      500.1   
+ 6260049  2008-02-13T21:05:05 -171.00616 -42.3413     4569.0      741.4   
+ ...                      ...        ...      ...        ...        ...   
+ 8378864  2007-09-22T11:19:17  -56.58100  77.3723     1124.0        7.0   
+ 8379044  2007-09-23T00:28:00  -57.12800  76.8946       94.0        7.0   
+ 8379071  2007-09-23T10:28:16  -57.85300  76.1809       75.0        7.0   
+ 8379153  2007-09-23T18:58:30  -58.23000  75.7056       65.0        7.0   
+ 8379186  2007-09-23T23:55:04  -58.63800  75.2003       49.0        7.0   
+ 
+         nuclide     value  _unit  _filt  _sampmet  
+ 6260008   po210  0.000091    3.0      1         1  
+ 6260022   po210  0.000029    3.0      1         1  
+ 6260033   po210  0.000017    3.0      1         1  
+ 6260044   po210  0.000040    3.0      1         1  
+ 6260049   po210  0.000047    3.0      1         1  
+ ...         ...       ...    ...    ...       ...  
+ 8378864   pb210  0.000213    3.0      1        24  
+ 8379044   pb210  0.000201    3.0      1        24  
+ 8379071   pb210  0.000394    3.0      1        24  
+ 8379153   pb210  0.000212    3.0      1        24  
+ 8379186   pb210  0.000077    3.0      1        24  
+ 
+ [7606 rows x 10 columns]}
+
+
+
+
+

Rehape: long to wide

+
+

source

+
+
+

ReshapeLongToWide

+
+
 ReshapeLongToWide (columns='nuclide', values=['value'])
+
+

Convert data from long to wide with renamed columns.

+
+
df = pd.read_csv(fname_in)
+
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern),
+    WideToLongCB(common_coi, nuclides_pattern),
+    ExtractUnitCB(),
+    ExtractFilteringStatusCB(phase),
+    ExtractSamplingMethodCB(smp_method),
+    RenameNuclideCB(nuclides_name),
+    StandardizeUnitCB(units_lut),
+    RenameColumnCB(renaming_rules),
+    UnshiftLongitudeCB(),
+    DispatchToGroupCB(),
+    ReshapeLongToWide()
+])
+
+dfs_test = tfm()['seawater']
+print('shape: ', dfs_test.shape)
+print('columns: ', dfs_test.columns)
+dfs_test.head()
+
+
shape:  (19139, 88)
+columns:  Index(['lat', 'lon', 'time', 'sample', 'tot_depth', 'smp_depth', 'ac227_filt',
+       'be7_filt', 'cs137_filt', 'h3_filt', 'i129_filt', 'np237_filt',
+       'pa231_filt', 'pb210_filt', 'po210_filt', 'pu239_filt',
+       'pu239_240_tot_filt', 'pu240_filt', 'ra223_filt', 'ra224_filt',
+       'ra226_filt', 'ra228_filt', 'th228_filt', 'th230_filt', 'th232_filt',
+       'th234_filt', 'u236_filt', 'ac227_sampmet', 'be7_sampmet',
+       'cs137_sampmet', 'h3_sampmet', 'i129_sampmet', 'np237_sampmet',
+       'pa231_sampmet', 'pb210_sampmet', 'po210_sampmet', 'pu239_sampmet',
+       'pu239_240_tot_sampmet', 'pu240_sampmet', 'ra223_sampmet',
+       'ra224_sampmet', 'ra226_sampmet', 'ra228_sampmet', 'th228_sampmet',
+       'th230_sampmet', 'th232_sampmet', 'th234_sampmet', 'u236_sampmet',
+       'ac227_unit', 'be7_unit', 'cs137_unit', 'h3_unit', 'i129_unit',
+       'np237_unit', 'pa231_unit', 'pb210_unit', 'po210_unit', 'pu239_unit',
+       'pu239_240_tot_unit', 'pu240_unit', 'ra223_unit', 'ra224_unit',
+       'ra226_unit', 'ra228_unit', 'th228_unit', 'th230_unit', 'th234_unit',
+       'u236_unit', 'ac227', 'be7', 'cs137', 'h3', 'i129', 'np237', 'pa231',
+       'pb210', 'po210', 'pu239', 'pu239_240_tot', 'pu240', 'ra223', 'ra224',
+       'ra226', 'ra228', 'th228', 'th230', 'th234', 'u236'],
+      dtype='object')
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
latlontimesampletot_depthsmp_depthac227_filtbe7_filtcs137_filth3_filt...pu239_240_totpu240ra223ra224ra226ra228th228th230th234u236
0-70.5744171.87722008-03-05T13:57:451306733136.09.7NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1-70.5744171.87722008-03-05T13:57:451306747136.0135.6NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2-70.5744171.87722008-03-05T13:57:452150069136.09.7NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaN0.000002NaNNaN
3-70.5744171.87722008-03-05T13:57:452150083136.0135.6NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaN0.000003NaNNaN
4-70.5744171.87722008-03-05T13:57:452360903136.09.7NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
+ +

5 rows × 88 columns

+
+
+
+
+
+

Parse time

+
+

source

+
+
+

ParseTimeCB

+
+
 ParseTimeCB ()
+
+

Base class for callbacks.

+
+
df = pd.read_csv(fname_in)
+
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern),
+    WideToLongCB(common_coi, nuclides_pattern),
+    ExtractUnitCB(),
+    ExtractFilteringStatusCB(phase),
+    ExtractSamplingMethodCB(smp_method),
+    RenameNuclideCB(nuclides_name),
+    StandardizeUnitCB(units_lut),
+    RenameColumnCB(renaming_rules),
+    UnshiftLongitudeCB(),
+    DispatchToGroupCB(),
+    ReshapeLongToWide(),
+    ParseTimeCB()
+])
+
+print('time data type: ', tfm()['seawater'].time.dtype)
+
+
time data type:  datetime64[ns]
+
+
+
+
+

Encode time (seconds since …)

+
+
df = pd.read_csv(fname_in)
+
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern),
+    WideToLongCB(common_coi, nuclides_pattern),
+    ExtractUnitCB(),
+    ExtractFilteringStatusCB(phase),
+    ExtractSamplingMethodCB(smp_method),
+    RenameNuclideCB(nuclides_name),
+    StandardizeUnitCB(units_lut),
+    RenameColumnCB(renaming_rules),
+    UnshiftLongitudeCB(),
+    DispatchToGroupCB(),
+    ReshapeLongToWide(),
+    ParseTimeCB(),
+    EncodeTimeCB(cfg())
+])
+
+dfs_test = tfm()['seawater']
+dfs_test.head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
latlontimesampletot_depthsmp_depthac227_filtbe7_filtcs137_filth3_filt...pu239_240_totpu240ra223ra224ra226ra228th228th230th234u236
0-70.5744171.877212047254651306733136.09.7NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1-70.5744171.877212047254651306747136.0135.6NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2-70.5744171.877212047254652150069136.09.7NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaN0.000002NaNNaN
3-70.5744171.877212047254652150083136.0135.6NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaN0.000003NaNNaN
4-70.5744171.877212047254652360903136.09.7NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
+ +

5 rows × 88 columns

+
+
+
+
+
+

Sanitize coordinates

+
+
df = pd.read_csv(fname_in)
+
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern),
+    WideToLongCB(common_coi, nuclides_pattern),
+    ExtractUnitCB(),
+    ExtractFilteringStatusCB(phase),
+    ExtractSamplingMethodCB(smp_method),
+    RenameNuclideCB(nuclides_name),
+    StandardizeUnitCB(units_lut),
+    RenameColumnCB(renaming_rules),
+    UnshiftLongitudeCB(),
+    DispatchToGroupCB(),
+    ReshapeLongToWide(),
+    ParseTimeCB(),
+    EncodeTimeCB(cfg()),
+    SanitizeLonLatCB()
+])
+dfs_test = tfm()['seawater']
+dfs_test.head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
latlontimesampletot_depthsmp_depthac227_filtbe7_filtcs137_filth3_filt...pu239_240_totpu240ra223ra224ra226ra228th228th230th234u236
0-70.5744171.877212047254651306733136.09.7NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1-70.5744171.877212047254651306747136.0135.6NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2-70.5744171.877212047254652150069136.09.7NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaN0.000002NaNNaN
3-70.5744171.877212047254652150083136.0135.6NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaN0.000003NaNNaN
4-70.5744171.877212047254652360903136.09.7NaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
+ +

5 rows × 88 columns

+
+
+
+
+
+
+

NetCDF encoder

+
+

Example change logs

+
+
df = pd.read_csv(fname_in)
+
+tfm = Transformer(df, cbs=[
+    SelectColsOfInterestCB(common_coi, nuclides_pattern),
+    WideToLongCB(common_coi, nuclides_pattern),
+    ExtractUnitCB(),
+    ExtractFilteringStatusCB(phase),
+    ExtractSamplingMethodCB(smp_method),
+    RenameNuclideCB(nuclides_name),
+    StandardizeUnitCB(units_lut),
+    RenameColumnCB(renaming_rules),
+    UnshiftLongitudeCB(),
+    DispatchToGroupCB(),
+    ReshapeLongToWide(),
+    ParseTimeCB(),
+    EncodeTimeCB(cfg()),
+    SanitizeLonLatCB()
+])
+
+tfm();
+
+
+
tfm.logs
+
+
['Select columns of interest.',
+ '\n    Get Geotraces nuclide names as values not column names \n    to extract contained information (unit, sampling method, ...).\n    ',
+ '\n    Extract units from nuclide names.\n    ',
+ '\n    Extract filtering status from nuclide names.\n    ',
+ '\n    Extract sampling method from nuclide names.\n    ',
+ '\n    Remap nuclides name to MARIS standard.\n    ',
+ '\n    Remap unit to MARIS standard ones and apply conversion where needed.\n    ',
+ 'Renaming variables to MARIS standard names.',
+ 'Longitudes are coded between 0 and 360 in Geotraces. We rescale it between -180 and 180 instead.',
+ 'Convert to a dictionary of dataframe with sample type (seawater,...) as keys.',
+ 'Convert data from long to wide with renamed columns.',
+ 'Encode time as `int` representing seconds since xxx',
+ 'Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator.']
+
+
+
+
+

Feed global attributes

+
+

source

+
+
+

get_attrs

+
+
 get_attrs (tfm, zotero_key, kw=['oceanography', 'Earth Science > Oceans >
+            Ocean Chemistry> Radionuclides', 'Earth Science > Human
+            Dimensions > Environmental Impacts > Nuclear Radiation
+            Exposure', 'Earth Science > Oceans > Ocean Chemistry > Ocean
+            Tracers, Earth Science > Oceans > Marine Sediments', 'Earth
+            Science > Oceans > Ocean Chemistry, Earth Science > Oceans >
+            Sea Ice > Isotopes', 'Earth Science > Oceans > Water Quality >
+            Ocean Contaminants', 'Earth Science > Biological
+            Classification > Animals/Vertebrates > Fish', 'Earth Science >
+            Biosphere > Ecosystems > Marine Ecosystems', 'Earth Science >
+            Biological Classification > Animals/Invertebrates > Mollusks',
+            'Earth Science > Biological Classification >
+            Animals/Invertebrates > Arthropods > Crustaceans', 'Earth
+            Science > Biological Classification > Plants > Macroalgae
+            (Seaweeds)'])
+
+
+
zotero_metadata = get_attrs(tfm, zotero_key='97UIMEXN', kw=kw)
+print('Keys: ', zotero_metadata.keys())
+print('Title: ', zotero_metadata['title'])
+
+
Keys:  dict_keys(['geospatial_lat_min', 'geospatial_lat_max', 'geospatial_lon_min', 'geospatial_lon_max', 'geospatial_bounds', 'time_coverage_start', 'time_coverage_end', 'title', 'summary', 'creator_name', 'keywords', 'publisher_postprocess_logs'])
+Title:  The GEOTRACES Intermediate Data Product 2017
+
+
+
+
+

Encoding

+
+

source

+
+
+

encode

+
+
 encode (fname_in, fname_out, nc_tpl_path, **kwargs)
+
+
+
encode(fname_in, fname_out, nc_tpl_path(), verbose=False)
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/handlers/helcom.html b/handlers/helcom.html new file mode 100644 index 0000000..5327c43 --- /dev/null +++ b/handlers/helcom.html @@ -0,0 +1,6746 @@ + + + + + + + + + +HELCOM – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+ + + + +
+ + + + +
+ + + +
+ + + +
+

This data pipeline, known as a “handler” in Marisco terminology, is designed to clean, standardize, and encode HELCOM data into NetCDF format. The handler processes raw HELCOM data, applying various transformations and lookups to align it with MARIS data standards.

+
+

Key functions of this handler:

+ +

This handler is a crucial component in the Marisco data processing workflow, ensuring HELCOM data is properly integrated into the MARIS database.

+

Note: Additionally, an optional encoder (pipeline) is provided below to process data into a .csv format compatible with the MARIS master database. This feature is maintained for legacy purposes, as data ingestion was previously performed using OpenRefine.

+
+
+
+ +
+
+Tip +
+
+
+

For new MARIS users, please refer to Understanding MARIS Data Formats (NetCDF and Open Refine) for detailed information.

+
+
+

The present notebook pretends to be an instance of Literate Programming in the sense that it is a narrative that includes code snippets that are interspersed with explanations. When a function or a class needs to be exported in a dedicated python module (in our case marisco/handlers/helcom.py) the code snippet is added to the module using #| exports as provided by the wonderful nbdev library.

+
+

Configuration & file paths

+
    +
  • fname_in: path to the folder containing the HELCOM data in CSV format. The path can be defined as a relative path.

  • +
  • fname_out_nc: path and filename for the NetCDF output.The path can be defined as a relative path.

  • +
  • fname_out_csv: path and filename for the Open Refine csv output.The path can be defined as a relative path.

  • +
  • Zotero key: used to retrieve attributes related to the dataset from Zotero. The MARIS datasets include a library available on Zotero.

  • +
  • ref_id: refers to the location in Archive of the Zotero library.

  • +
+
+
+Exported source +
fname_in = '../../_data/accdb/mors/csv'
+fname_out_nc = '../../_data/output/100-HELCOM-MORS-2024.nc'
+fname_out_csv = '../../_data/output/100-HELCOM-MORS-2024.csv'
+zotero_key ='26VMZZ2Q' # HELCOM MORS zotero key
+ref_id = 100 # HELCOM MORS reference id as defined by MARIS
+
+
+
+
+

Load data

+

Helcom MORS (Monitoring of Radioactive Substances in the Baltic Sea) data is provided as a Microsoft Access database. Mdbtools can be used to convert the tables of the Microsoft Access database to .csv files on Unix-like OS.

+

Example steps:

+
    +
  1. Download data

  2. +
  3. Install mdbtools via VScode Terminal:

    +
    sudo apt-get -y install mdbtools
  4. +
  5. Install unzip via VScode Terminal:

    +
    sudo apt-get -y install unzip
  6. +
  7. In VS Code terminal (for instance), navigate to the marisco data folder:

    +
    cd /home/marisco/downloads/marisco/_data/accdb/mors_19840101_20211231
  8. +
  9. Unzip MORS_ENVIRONMENT.zip:

    +
    unzip MORS_ENVIRONMENT.zip 
  10. +
  11. Run preprocess.sh to generate the required data files:

    +
    ./preprocess.sh MORS_ENVIRONMENT.zip
  12. +
  13. Content of preprocess.sh script:

    +
    #!/bin/bash
    +
    +# Example of use: ./preprocess.sh MORS_ENVIRONMENT.zip
    +unzip $1
    +dbname=$(ls *.accdb)
    +mkdir csv
    +for table in $(mdb-tables -1 "$dbname"); do
    +    echo "Export table $table"
    +    mdb-export "$dbname" "$table" > "csv/$table.csv"
    +done
    +

    Once converted to .csv files, the data is ready to be loaded into a dictionary of dataframes.

  14. +
+
+

source

+
+

load_data

+
+
 load_data (src_dir:str|pathlib.Path, smp_types:list=[('SEA', 'seawater'),
+            ('SED', 'sediment'), ('BIO', 'biota')])
+
+

Load HELCOM data and return the data in a dictionary of dataframes with the dictionary key as the sample type.

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
src_dirstr | pathlib.PathThe directory where the source CSV files are located
smp_typeslist[(‘SEA’, ‘seawater’), (‘SED’, ‘sediment’), (‘BIO’, ‘biota’)]A list of tuples, each containing the file prefix and the corresponding sample type name
ReturnsDictA dictionary with sample types as keys and their corresponding dataframes as values
+
+
+Exported source +
default_smp_types = [('SEA', 'seawater'), ('SED', 'sediment'), ('BIO', 'biota')]
+
+
+
+
+Exported source +
def load_data(src_dir:str|Path, # The directory where the source CSV files are located
+              smp_types:list=default_smp_types # A list of tuples, each containing the file prefix and the corresponding sample type name
+             ) -> Dict[str, pd.DataFrame]: # A dictionary with sample types as keys and their corresponding dataframes as values
+    "Load HELCOM data and return the data in a dictionary of dataframes with the dictionary key as the sample type."
+    src_path = Path(src_dir)
+    
+    def load_and_merge(file_prefix: str) -> pd.DataFrame:
+        try:
+            df_meas = pd.read_csv(src_path / f'{file_prefix}02.csv')
+            df_smp = pd.read_csv(src_path / f'{file_prefix}01.csv')
+            return pd.merge(df_meas, df_smp, on='KEY', how='left')
+        except FileNotFoundError as e:
+            print(f"Error loading files for {file_prefix}: {e}")
+            return pd.DataFrame()  # Return an empty DataFrame if files are not found
+    
+    return {smp_type: load_and_merge(file_prefix) for file_prefix, smp_type in smp_types}
+
+
+

dfs is a dictionary of dataframes created from the Helcom dataset located at the path fname_in. The data to be included in each dataframe is sorted by sample type. Each dictionary is defined with a key equal to the sample type.

+
+
dfs = load_data(fname_in)
+
+#|eval: false
+dfs = load_data(fname_in)
+print('keys/sample types: ', dfs.keys())
+
+for key in dfs.keys():
+    print(f'{key} columns: ', dfs[key].columns)
+
+
keys/sample types:  dict_keys(['seawater', 'sediment', 'biota'])
+seawater columns:  Index(['KEY', 'NUCLIDE', 'METHOD', '< VALUE_Bq/m³', 'VALUE_Bq/m³', 'ERROR%_m³',
+       'DATE_OF_ENTRY_x', 'COUNTRY', 'LABORATORY', 'SEQUENCE', 'DATE', 'YEAR',
+       'MONTH', 'DAY', 'STATION', 'LATITUDE (ddmmmm)', 'LATITUDE (dddddd)',
+       'LONGITUDE (ddmmmm)', 'LONGITUDE (dddddd)', 'TDEPTH', 'SDEPTH', 'SALIN',
+       'TTEMP', 'FILT', 'MORS_SUBBASIN', 'HELCOM_SUBBASIN', 'DATE_OF_ENTRY_y'],
+      dtype='object')
+sediment columns:  Index(['KEY', 'NUCLIDE', 'METHOD', '< VALUE_Bq/kg', 'VALUE_Bq/kg', 'ERROR%_kg',
+       '< VALUE_Bq/m²', 'VALUE_Bq/m²', 'ERROR%_m²', 'DATE_OF_ENTRY_x',
+       'COUNTRY', 'LABORATORY', 'SEQUENCE', 'DATE', 'YEAR', 'MONTH', 'DAY',
+       'STATION', 'LATITUDE (ddmmmm)', 'LATITUDE (dddddd)',
+       'LONGITUDE (ddmmmm)', 'LONGITUDE (dddddd)', 'DEVICE', 'TDEPTH',
+       'UPPSLI', 'LOWSLI', 'AREA', 'SEDI', 'OXIC', 'DW%', 'LOI%',
+       'MORS_SUBBASIN', 'HELCOM_SUBBASIN', 'SUM_LINK', 'DATE_OF_ENTRY_y'],
+      dtype='object')
+biota columns:  Index(['KEY', 'NUCLIDE', 'METHOD', '< VALUE_Bq/kg', 'VALUE_Bq/kg', 'BASIS',
+       'ERROR%', 'NUMBER', 'DATE_OF_ENTRY_x', 'COUNTRY', 'LABORATORY',
+       'SEQUENCE', 'DATE', 'YEAR', 'MONTH', 'DAY', 'STATION',
+       'LATITUDE ddmmmm', 'LATITUDE dddddd', 'LONGITUDE ddmmmm',
+       'LONGITUDE dddddd', 'SDEPTH', 'RUBIN', 'BIOTATYPE', 'TISSUE', 'NO',
+       'LENGTH', 'WEIGHT', 'DW%', 'LOI%', 'MORS_SUBBASIN', 'HELCOM_SUBBASIN',
+       'DATE_OF_ENTRY_y'],
+      dtype='object')
+
+
+
+
+
+

Add sample type column

+

The sample type (seawater, biota, sediment, …) as defined in the configs.ipynb are encoded group names in netCDF produced. Addition of sample type ids into individual dataframes is done using the AddSampleTypeIdColumnCB callback for legacy purposes (i.e. Open Refine output).

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[AddSampleTypeIdColumnCB(),
+                            CompareDfsAndTfmCB(dfs)
+                            ])
+
+print(tfm()['seawater'][['KEY', 'samptype_id']].head())
+print(pd.DataFrame.from_dict(tfm.compare_stats) , '\n')
+
+
            KEY  samptype_id
+0  WKRIL2012003            1
+1  WKRIL2012004            1
+2  WKRIL2012005            1
+3  WKRIL2012006            1
+4  WKRIL2012007            1
+                                                    seawater  sediment  biota
+Number of rows in dfs                                  21216     39817  15827
+Number of rows in tfm.dfs                              21216     39817  15827
+Number of dropped rows                                     0         0      0
+Number of rows in tfm.dfs + Number of dropped rows     21216     39817  15827 
+
+
+
+
+
+

Normalize nuclide names

+
+

Lower & strip nuclide names

+
+
+
+ +
+
+Tip +
+
+
+

FEEDBACK TO DATA PROVIDER: Some nuclide names contain one or multiple trailing spaces.

+
+
+

This is demonstrated below for the NUCLIDE column:

+
+
df = get_unique_across_dfs(load_data(fname_in), 'NUCLIDE', as_df=True, include_nchars=True)
+df['stripped_chars'] = df['value'].str.strip().str.replace(' ', '').str.len()
+print(df[df['n_chars'] != df['stripped_chars']])
+
+
    index      value  n_chars  stripped_chars
+1       1   PU238           8               5
+15     15     SR90          6               4
+21     21  CS137            9               5
+42     42   SR90            8               4
+56     56   CO60            8               4
+57     57      SR90         5               4
+58     58   CS134           8               5
+60     60   CS137           8               5
+68     68   K40             8               3
+71     71     CS137         6               5
+73     73   AM241           8               5
+92     92    SR90           7               4
+93     93    TC99           7               4
+
+
+

To fix this issue, we use the LowerStripNameCB callback. For each dataframe in the dictionary of dataframes, it corrects the nuclide name by converting it lowercase, striping any leading or trailing whitespace(s) and ensuring the number comes before letters (e.g. 137cs).

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[LowerStripNameCB(col_src='NUCLIDE')])
+
+for key in tfm().keys():
+    print(f'{key} nuclides: ')
+    print(tfm()[key]['NUCLIDE'].unique())
+
+
seawater nuclides: 
+['cs137' 'sr90' 'h3' 'cs134' 'pu238' 'pu239240' 'am241' 'cm242' 'cm244'
+ 'tc99' 'k40' 'ru103' 'sr89' 'sb125' 'nb95' 'ru106' 'zr95' 'ag110m'
+ 'cm243244' 'ba140' 'ce144' 'u234' 'u238' 'co60' 'pu239' 'pb210' 'po210'
+ 'np237' 'pu240' 'mn54']
+sediment nuclides: 
+['ra226' 'cs137' 'ra228' 'k40' 'sr90' 'cs134137' 'cs134' 'pu239240'
+ 'pu238' 'co60' 'ru103' 'ru106' 'sb125' 'ag110m' 'ce144' 'am241' 'be7'
+ 'th228' 'pb210' 'co58' 'mn54' 'zr95' 'ba140' 'po210' 'ra224' 'nb95'
+ 'pu238240' 'pu241' 'pu239' 'eu155' 'ir192' 'th232' 'cd109' 'sb124' 'zn65'
+ 'th234' 'tl208' 'pb212' 'pb214' 'bi214' 'ac228' 'ra223' 'u235' 'bi212']
+biota nuclides: 
+['cs134' 'k40' 'co60' 'cs137' 'sr90' 'ag108m' 'mn54' 'co58' 'ag110m'
+ 'zn65' 'sb125' 'pu239240' 'ru106' 'be7' 'ce144' 'pb210' 'po210' 'sb124'
+ 'sr89' 'zr95' 'te129m' 'ru103' 'nb95' 'ce141' 'la140' 'i131' 'ba140'
+ 'pu238' 'u235' 'bi214' 'pb214' 'pb212' 'tl208' 'ac228' 'ra223' 'eu155'
+ 'ra226' 'gd153' 'sn113' 'fe59' 'tc99' 'co57' 'sn117m' 'eu152' 'sc46'
+ 'rb86' 'ra224' 'th232' 'cs134137' 'am241' 'ra228' 'th228' 'k-40' 'cs138'
+ 'cs139' 'cs140' 'cs141' 'cs142' 'cs143' 'cs144' 'cs145' 'cs146']
+
+
+
+
+

Remap nuclide names to MARIS data formats

+

We below map nuclide names used by HELCOM to the MARIS standard nuclide names.

+

Remapping data provider nomenclatures into MARIS standards is one recurrent operation and is done in a semi-automated manner according to the following pattern:

+
    +
  1. Inspect data provider nomenclature:
  2. +
  3. Match automatically against MARIS nomenclature (using a fuzzy matching algorithm);
  4. +
  5. Fix potential mismatches;
  6. +
  7. Apply the lookup table to the dataframe.
  8. +
+

As now on, we will use this pattern to remap the HELCOM data provider nomenclatures into MARIS standards and name it for the sake of brevity IMFA (Inspect, Match, Fix, Apply).

+

The unique values of the data provider nuclide names. The get_unique_across_dfs is a utility function allowing to retrieve unique values of a specific column across all dataframes (please remind that we have one dataframe per sample type - biota, …).

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[LowerStripNameCB(col_src='NUCLIDE')])
+dfs_output = tfm()
+
+get_unique_across_dfs(dfs_output, col_name='NUCLIDE', as_df=True).head(5)
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
indexvalue
00th228
11sc46
22cs142
33cs137
44zn65
+ +
+
+
+

Let’s now create an instance of a fuzzy matching algorithm Remapper:

+
+
remapper = Remapper(provider_lut_df=get_unique_across_dfs(dfs_output, col_name='NUCLIDE', as_df=True),
+                    maris_lut_fn=nuc_lut_path,
+                    maris_col_id='nuclide_id',
+                    maris_col_name='nc_name',
+                    provider_col_to_match='value',
+                    provider_col_key='value',
+                    fname_cache='nuclides_helcom.pkl')
+
+

And try to match HELCOM to MARIS nuclide names as automatically as possible. The match_score column allows to assess the results:

+
+
remapper.generate_lookup_table(as_df=True)
+remapper.select_match(match_score_threshold=1)
+
+
Processing: 100%|██████████| 77/77 [00:01<00:00, 46.82it/s]
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
matched_maris_namesource_namematch_score
source_key
cm243244cm244cm2432443
cs134137cs137cs1341373
pu238240pu240pu2382403
pu239240pu240pu2392403
cs142ce144cs1422
cs143cs127cs1432
cs145cs136cs1452
cs144ce144cs1441
cs146cs136cs1461
k-40k40k-401
cs141ce141cs1411
cs139ce139cs1391
cs138cs137cs1381
cs140ce140cs1401
+ +
+
+
+

We then manually inspect the remaining unmatched names and create a fixes table to map them to the correct MARIS standards:

+
+
+Exported source +
fixes_nuclide_names = {
+    'cs134137': 'cs134_137_tot',
+    'cm243244': 'cm243_244_tot',
+    'pu239240': 'pu239_240_tot',
+    'pu238240': 'pu238_240_tot',
+    'cs143': 'cs137',
+    'cs145': 'cs137',
+    'cs142': 'cs137',
+    'cs141': 'cs137',
+    'cs144': 'cs137',
+    'k-40': 'k40',
+    'cs140': 'cs137',
+    'cs146': 'cs137',
+    'cs139': 'cs137',
+    'cs138': 'cs137'
+    }
+
+
+

Let’s try to match again but this time we use the fixes_nuclide_names to map the nuclide names to the MARIS standards:

+
+
remapper.generate_lookup_table(as_df=True, fixes=fixes_nuclide_names)
+fc.test_eq(len(remapper.select_match(match_score_threshold=1)), 0)
+
+
Processing: 100%|██████████| 77/77 [00:01<00:00, 51.25it/s]
+
+
+

Test passes! We can now create a callback RemapNuclideNameCB to remap the nuclide names. Note that we pass overwrite=False to the Remapper constructor to now use the cached version.

+
+

source

+
+
+

RemapNuclideNameCB

+
+
 RemapNuclideNameCB (fn_lut:Callable)
+
+

Base class for callbacks.

+ +++++ + + + + + + + + + + + + + + +
TypeDetails
fn_lutCallableFunction that returns the lookup table dictionary
+
+
+Exported source +
# Create a lookup table for nuclide names
+lut_nuclides = lambda df: Remapper(provider_lut_df=df,
+                                   maris_lut_fn=nuc_lut_path,
+                                   maris_col_id='nuclide_id',
+                                   maris_col_name='nc_name',
+                                   provider_col_to_match='value',
+                                   provider_col_key='value',
+                                   fname_cache='nuclides_helcom.pkl').generate_lookup_table(fixes=fixes_nuclide_names, 
+                                                                                            as_df=False, overwrite=False)
+
+
+
+
+Exported source +
class RemapNuclideNameCB(Callback):
+    def __init__(self, 
+                 fn_lut:Callable # Function that returns the lookup table dictionary
+                ):
+        "Remap data provider nuclide names to MARIS nuclide names."
+        fc.store_attr()
+
+    def __call__(self, tfm):
+        df_uniques = get_unique_across_dfs(tfm.dfs, col_name='NUCLIDE', as_df=True)
+        lut = {k: v.matched_maris_name for k, v in self.fn_lut(df_uniques).items()}    
+        for k in tfm.dfs.keys():
+            tfm.dfs[k]['NUCLIDE'] = tfm.dfs[k]['NUCLIDE'].replace(lut)
+
+
+

Let’s see it in action, along with the RemapRdnNameCB callback:

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[LowerStripNameCB(col_src='NUCLIDE'),
+                            RemapNuclideNameCB(lut_nuclides)
+                            ])
+dfs_out = tfm()
+
+# For instance
+dfs_out['biota'].NUCLIDE.unique()
+
+
array(['cs134', 'k40', 'co60', 'cs137', 'sr90', 'ag108m', 'mn54', 'co58',
+       'ag110m', 'zn65', 'sb125', 'pu239_240_tot', 'ru106', 'be7',
+       'ce144', 'pb210', 'po210', 'sb124', 'sr89', 'zr95', 'te129m',
+       'ru103', 'nb95', 'ce141', 'la140', 'i131', 'ba140', 'pu238',
+       'u235', 'bi214', 'pb214', 'pb212', 'tl208', 'ac228', 'ra223',
+       'eu155', 'ra226', 'gd153', 'sn113', 'fe59', 'tc99', 'co57',
+       'sn117m', 'eu152', 'sc46', 'rb86', 'ra224', 'th232',
+       'cs134_137_tot', 'am241', 'ra228', 'th228'], dtype=object)
+
+
+
+
+

Add Nuclide Id column

+

The nuclide_id column is added to the dataframe for legacy reasons (again Open Refine output).

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[LowerStripNameCB(col_src='NUCLIDE'),
+                            RemapNuclideNameCB(lut_nuclides),
+                            AddNuclideIdColumnCB(col_value='NUCLIDE')
+                            ])
+dfs_out = tfm()
+
+# For instance
+dfs_out['biota'][['NUCLIDE', 'nuclide_id']]
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NUCLIDEnuclide_id
0cs13431
1k404
2co609
3cs13733
4cs13431
.........
15822k404
15823cs13733
15824be72
15825k404
15826cs13733
+ +

15827 rows × 2 columns

+
+
+
+
+
+
+

Standardize Time

+
+

Parse time

+

Create a callback that remaps the time format in the dictionary of dataframes (i.e. %m/%d/%y %H:%M:%S):

+

Comment (FA): TO BE REFACTORED

+
+

source

+
+
+

ParseTimeCB

+
+
 ParseTimeCB ()
+
+

Parse the time column in the dataframe.

+
+
+Exported source +
class ParseTimeCB(Callback):
+    "Parse the time column in the dataframe."
+    def __init__(self): fc.store_attr()
+            
+    def __call__(self, 
+                 tfm # The transformer object containing DataFrames
+                ):
+        for grp in tfm.dfs.keys():
+            df = tfm.dfs[grp]
+            self._process_dates(df)
+            self._define_beg_period(df)
+
+    def _process_dates(self, 
+                       df:pd.DataFrame # DataFrame containing the `DATE`, `YEAR`, `MONTH`, and `DAY` columns
+                      ):
+        "Process and correct date and time information in the DataFrame."
+        df['time'] = pd.to_datetime(df['DATE'], format='%m/%d/%y %H:%M:%S')
+        # if 'DATE' column is nan, get 'time' from 'YEAR','MONTH' and 'DAY' column. 
+        # if 'DAY' or 'MONTH' is 0 then set it to 1. 
+        df.loc[df["DAY"] == 0, "DAY"] = 1
+        df.loc[df["MONTH"] == 0, "MONTH"] = 1
+        
+        # if 'DAY' and 'MONTH' is nan but YEAR is not nan then set 'DAY' and 'MONTH' both to 1. 
+        condition = (df["DAY"].isna()) & (df["MONTH"].isna()) & (df["YEAR"].notna())
+        df.loc[condition, "DAY"] = 1
+        df.loc[condition, "MONTH"] = 1
+        
+        condition = df['DATE'].isna() # if 'DATE' is nan. 
+        df['time']  = np.where(condition,
+                                            # 'coerce', then invalid parsing will be set as NaT. NaT will result if the number of days are not valid for the month.
+                                        pd.to_datetime(df[['YEAR', 'MONTH', 'DAY']], format='%y%m%d', errors='coerce'),  
+                                        pd.to_datetime(df['DATE'], format='%m/%d/%y %H:%M:%S'))
+        
+    def _define_beg_period(self, 
+                           df: pd.DataFrame # DataFrame containing the `time` column
+                          ):
+        "Create a standardized date representation for Open Refine."
+        df['begperiod'] = df['time']
+
+
+

Apply the transformer for callbacks ParseTimeCB. Then, print the begperiod and time data for seawater.

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[ParseTimeCB(),
+                            CompareDfsAndTfmCB(dfs)
+                            ])
+tfm()
+print(pd.DataFrame.from_dict(tfm.compare_stats) , '\n')
+print(tfm.dfs['seawater'][['begperiod','time']])
+
+
                                                    seawater  sediment  biota
+Number of rows in dfs                                  21216     39817  15827
+Number of rows in tfm.dfs                              21216     39817  15827
+Number of dropped rows                                     0         0      0
+Number of rows in tfm.dfs + Number of dropped rows     21216     39817  15827 
+
+       begperiod       time
+0     2012-05-23 2012-05-23
+1     2012-05-23 2012-05-23
+2     2012-06-17 2012-06-17
+3     2012-05-24 2012-05-24
+4     2012-05-24 2012-05-24
+...          ...        ...
+21211 2021-10-15 2021-10-15
+21212 2021-11-04 2021-11-04
+21213 2021-10-15 2021-10-15
+21214 2021-05-17 2021-05-17
+21215 2021-05-13 2021-05-13
+
+[21216 rows x 2 columns]
+
+
+
+
+

Encode time

+

Seconds since …

+

EncodeTimeCB converts the HELCOM time format to the MARIS NetCDF time format.

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[ParseTimeCB(),
+                            EncodeTimeCB(cfg(), verbose=True),
+                            CompareDfsAndTfmCB(dfs)
+                            ])
+tfm()
+print(pd.DataFrame.from_dict(tfm.compare_stats) , '\n')
+
+
8 of 21216 entries for `time` are invalid for seawater.
+1 of 39817 entries for `time` are invalid for sediment.
+                                                    seawater  sediment  biota
+Number of rows in dfs                                  21216     39817  15827
+Number of rows in tfm.dfs                              21208     39816  15827
+Number of dropped rows                                     8         1      0
+Number of rows in tfm.dfs + Number of dropped rows     21216     39817  15827 
+
+
+
+
+
+
+

Sanitize value

+
+
+Exported source +
# Columns of interest
+coi_val = {'seawater' : {'val': 'VALUE_Bq/m³'},
+           'biota':  {'val': 'VALUE_Bq/kg'},
+           'sediment': {'val': 'VALUE_Bq/kg'}}
+
+
+

Comment (FA): Those lines can be simplified I think:

+
value_col = self.coi.get(grp, {}).get('val')
+if value_col and value_col in df.columns:
+
+

source

+
+

SanitizeValue

+
+
 SanitizeValue (coi:dict)
+
+

Sanitize value by removing blank entries and ensuring the ‘value’ column is retained.

+ +++++ + + + + + + + + + + + + + + +
TypeDetails
coidictDictionary containing column names for values based on group
+
+
+Exported source +
class SanitizeValue(Callback):
+    "Sanitize value by removing blank entries and ensuring the 'value' column is retained."
+    def __init__(self, 
+                 coi:dict # Dictionary containing column names for values based on group
+                ):
+        fc.store_attr()
+
+    def __call__(self, 
+                 tfm # The transformer object containing DataFrames
+                ):
+        "Sanitize the DataFrames in the transformer by removing rows with blank values in specified columns."
+        for grp in tfm.dfs.keys():
+            self._sanitize_dataframe(tfm.dfs[grp], grp)
+
+    def _sanitize_dataframe(self, 
+                            df:pd.DataFrame, # DataFrame to sanitize
+                            grp:str # Group name to determine column names
+                           ):
+        "Remove rows where specified value columns are blank and ensure the 'value' column is included."
+        value_col = self.coi.get(grp, {}).get('val')
+        if value_col and value_col in df.columns:
+            df.dropna(subset=[value_col], inplace=True)
+            # Ensure 'value' column is retained
+            if 'value' not in df.columns:
+                df['value'] = df[value_col]
+
+
+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[SanitizeValue(coi_val),
+                            CompareDfsAndTfmCB(dfs)
+                            ])
+
+tfm()
+print(pd.DataFrame.from_dict(tfm.compare_stats) , '\n')
+
+
                                                    seawater  sediment  biota
+Number of rows in dfs                                  21216     39817  15827
+Number of rows in tfm.dfs                              21122     39532  15798
+Number of dropped rows                                    94       285     29
+Number of rows in tfm.dfs + Number of dropped rows     21216     39817  15827 
+
+
+
+
+
+
+

Normalize uncertainty

+

Function unc_rel2stan converts uncertainty from relative uncertainty to standard uncertainty.

+
+

source

+
+

unc_rel2stan

+
+
 unc_rel2stan (df:pandas.core.frame.DataFrame, meas_col:str, unc_col:str)
+
+

Convert relative uncertainty to absolute uncertainty.

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDetails
dfDataFrameDataFrame containing measurement and uncertainty columns
meas_colstrName of the column with measurement values
unc_colstrName of the column with relative uncertainty values (percentages)
ReturnsSeriesSeries with calculated absolute uncertainties
+
+
+Exported source +
def unc_rel2stan(
+    df:pd.DataFrame, # DataFrame containing measurement and uncertainty columns
+    meas_col:str, # Name of the column with measurement values
+    unc_col:str # Name of the column with relative uncertainty values (percentages)
+) -> pd.Series: # Series with calculated absolute uncertainties
+    "Convert relative uncertainty to absolute uncertainty."
+    return df.apply(lambda row: row[unc_col] * row[meas_col] / 100, axis=1)
+
+
+

For each sample type in the Helcom dataset, the uncertainty is given as a relative uncertainty. The column names for both the value and the uncertainty vary by sample type. The coi_units_unc dictionary defines the column names for the Value and Uncertainty for each sample type.

+
+
+Exported source +
# Columns of interest
+coi_units_unc = [('seawater', 'VALUE_Bq/m³', 'ERROR%_m³'),
+                 ('biota', 'VALUE_Bq/kg', 'ERROR%'),
+                 ('sediment', 'VALUE_Bq/kg', 'ERROR%_kg')]
+
+
+

NormalizeUncCB callback normalizes the uncertainty by converting from relative uncertainty to standard uncertainty.

+
+

source

+
+
+

NormalizeUncCB

+
+
 NormalizeUncCB (fn_convert_unc:Callable=<function unc_rel2stan>,
+                 coi:List=[('seawater', 'VALUE_Bq/m³', 'ERROR%_m³'),
+                 ('biota', 'VALUE_Bq/kg', 'ERROR%'), ('sediment',
+                 'VALUE_Bq/kg', 'ERROR%_kg')])
+
+

Convert from relative error % to uncertainty of activity unit.

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
fn_convert_uncCallableunc_rel2stanFunction converting relative uncertainty to absolute uncertainty
coiList[(‘seawater’, ‘VALUE_Bq/m³’, ’ERROR%_m³’), (‘biota’, ‘VALUE_Bq/kg’, ‘ERROR%’), (‘sediment’, ‘VALUE_Bq/kg’, ’ERROR%_kg’)]List of columns of interest
+
+
+Exported source +
class NormalizeUncCB(Callback):
+    "Convert from relative error % to uncertainty of activity unit."
+    def __init__(self, 
+                 fn_convert_unc:Callable=unc_rel2stan, # Function converting relative uncertainty to absolute uncertainty
+                 coi:List=coi_units_unc # List of columns of interest
+                ):
+        fc.store_attr()
+    
+    def __call__(self, tfm):
+        for grp, val, unc in self.coi:
+            if grp in tfm.dfs:
+                df = tfm.dfs[grp]
+                df['uncertainty'] = self.fn_convert_unc(df, val, unc)
+
+
+

Apply the transformer for callback NormalizeUncCB(). Then, print the value (i.e. activity per unit ) and standard uncertainty for each sample type.

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[NormalizeUncCB(),
+                            SanitizeValue(coi_val)])
+
+print(tfm()['seawater'][['value', 'uncertainty']][:5])
+print(tfm()['biota'][['value', 'uncertainty']][:5])
+print(tfm()['sediment'][['value', 'uncertainty']][:5])
+
+
   value  uncertainty
+0    5.3        1.696
+1   19.9        3.980
+2   25.5        5.100
+3   17.0        4.930
+4   22.2        3.996
+        value  uncertainty
+0    0.010140          NaN
+1  135.300000     4.830210
+2    0.013980          NaN
+3    4.338000     0.150962
+4    0.009614          NaN
+   value  uncertainty
+0   35.0         9.10
+1   36.0         7.92
+2   38.0         9.12
+3   36.0         9.00
+4   30.0         6.90
+
+
+
+
+
+

Remap Biota species

+

We follow in the next following processing steps the same approach as for remapping of nuclide names above.

+

Let’s inspect the RUBIN_NAME.csv file provided by HELCOM describing the biota species nomenclature.

+
+
pd.read_csv(Path(fname_in) / 'RUBIN_NAME.csv').head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RUBIN_IDRUBINSCIENTIFIC NAMEENGLISH NAME
011ABRA BRAABRAMIS BRAMABREAM
112ANGU ANGANGUILLA ANGUILLAEEL
213ARCT ISLARCTICA ISLANDICAISLAND CYPRINE
314ASTE RUBASTERIAS RUBENSCOMMON STARFISH
415CARD EDUCARDIUM EDULECOCKLE
+ +
+
+
+

We try to remap the SCIENTIFIC NAME column to the species column of the MARIS nomenclature, again using a Remapper object:

+
+
remapper = Remapper(provider_lut_df=pd.read_csv(Path(fname_in) / 'RUBIN_NAME.csv'),
+                    maris_lut_fn=species_lut_path,
+                    maris_col_id='species_id',
+                    maris_col_name='species',
+                    provider_col_to_match='SCIENTIFIC NAME',
+                    provider_col_key='RUBIN',
+                    fname_cache='species_helcom.pkl'
+                    )
+
+remapper.generate_lookup_table(as_df=True)
+remapper.select_match(match_score_threshold=1)
+
+
Processing: 100%|██████████| 46/46 [00:07<00:00,  5.95it/s]
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
matched_maris_namesource_namematch_score
source_key
STIZ LUCSander luciopercaSTIZOSTEDION LUCIOPERCA10
LAMI SACLaminaria japonicaLAMINARIA SACCHARINA7
CARD EDUCardiidaeCARDIUM EDULE6
ENCH CIMEchinodermataENCHINODERMATA CIM5
PSET MAXPinctada maximaPSETTA MAXIMA5
MACO BALMacoma balthicaMACOMA BALTICA1
STUC PECStuckenia pectinataSTUCKENIA PECTINATE1
+ +
+
+
+

We fix below some of the entries that are not properly matched by the Remapper object:

+
+
+Exported source +
fixes_biota_species = {
+    'CARDIUM EDULE': 'Cerastoderma edule',
+    'LAMINARIA SACCHARINA': 'Saccharina latissima',
+    'PSETTA MAXIMA': 'Scophthalmus maximus',
+    'STIZOSTEDION LUCIOPERCA': 'Sander luciopercas'}
+
+
+

And give it an another try:

+
+
remapper.generate_lookup_table(fixes=fixes_biota_species)
+remapper.select_match(match_score_threshold=1)
+
+
Processing: 100%|██████████| 46/46 [00:07<00:00,  6.23it/s]
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
matched_maris_namesource_namematch_score
source_key
ENCH CIMEchinodermataENCHINODERMATA CIM5
MACO BALMacoma balthicaMACOMA BALTICA1
STIZ LUCSander luciopercaSTIZOSTEDION LUCIOPERCA1
STUC PECStuckenia pectinataSTUCKENIA PECTINATE1
+ +
+
+
+

Visual inspection of the remaining unperfectly matched entries seem acceptable to proceed.

+

We now define a callback to apply the lookup table to the biota dataframe.

+
+

source

+
+

RemapBiotaSpeciesCB

+
+
 RemapBiotaSpeciesCB (fn_lut:Callable)
+
+

Biota species standardized to MARIS format.

+ +++++ + + + + + + + + + + + + + + +
TypeDetails
fn_lutCallableFunction that returns the lookup table dictionary
+
+
+Exported source +
class RemapBiotaSpeciesCB(Callback):
+    "Biota species standardized to MARIS format."
+    def __init__(self, 
+                 fn_lut:Callable # Function that returns the lookup table dictionary
+                ):
+        fc.store_attr()
+
+    def __call__(self, tfm):
+        "Remap biota species names in the DataFrame using the lookup table and print unmatched RUBIN values."
+        lut = self.fn_lut()
+        tfm.dfs['biota']['species'] = tfm.dfs['biota']['RUBIN'].apply(lambda x: self._get_species(x, lut))
+
+    def _get_species(self, 
+                     rubin_value:str, # The RUBIN value from the DataFrame
+                     lut:dict # The lookup table dictionary
+                    ):
+        "Get the matched_id from the lookup table and print RUBIN if the matched_id is -1."
+        match = lut.get(rubin_value.strip(), Match(-1, None, None, None))
+        if match.matched_id == -1:
+            self.print_unmatched_rubin(rubin_value)
+        return match.matched_id
+
+    def print_unmatched_rubin(self, 
+                              rubin_value: str # The RUBIN value from the DataFrame
+                             ):
+        "Print the RUBIN value if the matched_id is -1."
+        print(f"Unmatched RUBIN: {rubin_value}")
+
+
+

Let’s see it in action, along with the RemapBiotaSpeciesCB callback:

+
+
+Exported source +
lut_biota = lambda: Remapper(provider_lut_df=pd.read_csv(Path(fname_in) / 'RUBIN_NAME.csv'),
+                             maris_lut_fn=species_lut_path,
+                             maris_col_id='species_id',
+                             maris_col_name='species',
+                             provider_col_to_match='SCIENTIFIC NAME',
+                             provider_col_key='RUBIN',
+                             fname_cache='species_helcom.pkl'
+                             ).generate_lookup_table(fixes=fixes_biota_species, as_df=False, overwrite=False)
+
+
+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[RemapBiotaSpeciesCB(lut_biota)])
+
+# For instance:
+print(tfm()['biota']['species'].unique())
+
+
[  99  243   50  139  270  192  191  284   84  269  122   96  287  279
+  278  288  286  244  129  275  271  285  283  247  120   59  280  274
+  273  290  289  272  277  276   21  282  110  281  245  704 1524  703
+ 1611  621   60]
+
+
+
+
+
+

Remap Biota tissues

+

Let’s inspect the TISSUE.csv file provided by HELCOM describing the tissue nomenclature. Biota tissue is known as body part in the maris data set.

+
+
pd.read_csv('../../_data/accdb/mors/csv/TISSUE.csv').head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TISSUETISSUE_DESCRIPTION
01WHOLE FISH
12WHOLE FISH WITHOUT ENTRAILS
23WHOLE FISH WITHOUT HEAD AND ENTRAILS
34FLESH WITH BONES
45FLESH WITHOUT BONES (FILETS)
+ +
+
+
+
+
remapper = Remapper(provider_lut_df=pd.read_csv('../../_data/accdb/mors/csv/TISSUE.csv'),
+                    maris_lut_fn=bodyparts_lut_path,
+                    maris_col_id='bodypar_id',
+                    maris_col_name='bodypar',
+                    provider_col_to_match='TISSUE_DESCRIPTION',
+                    provider_col_key='TISSUE',
+                    fname_cache='tissues_helcom.pkl'
+                    )
+
+remapper.generate_lookup_table(as_df=True)
+remapper.select_match(match_score_threshold=1)
+
+
Processing: 100%|██████████| 29/29 [00:00<00:00, 123.14it/s]
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
matched_maris_namesource_namematch_score
source_key
3Flesh without bonesWHOLE FISH WITHOUT HEAD AND ENTRAILS20
2Flesh without bonesWHOLE FISH WITHOUT ENTRAILS13
8Soft partsSKIN/EPIDERMIS10
5Flesh without bonesFLESH WITHOUT BONES (FILETS)9
1Whole animalWHOLE FISH5
12BrainENTRAILS5
15Stomach and intestineSTOMACH + INTESTINE3
41Whole animalWHOLE ANIMALS1
+ +
+
+
+

We fix below some of the entries that are not properly matched by the Remapper object:

+
+
+Exported source +
fixes_biota_tissues = {
+    'WHOLE FISH WITHOUT HEAD AND ENTRAILS': 'Whole animal eviscerated without head',
+    'ENTRAILS': 'Viscera',
+    'SKIN/EPIDERMIS': 'Skin'}
+
+
+
+
remapper.generate_lookup_table(as_df=True, fixes=fixes_biota_tissues)
+remapper.select_match(match_score_threshold=1)
+
+
Processing: 100%|██████████| 29/29 [00:00<00:00, 123.73it/s]
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
matched_maris_namesource_namematch_score
source_key
2Flesh without bonesWHOLE FISH WITHOUT ENTRAILS13
5Flesh without bonesFLESH WITHOUT BONES (FILETS)9
1Whole animalWHOLE FISH5
15Stomach and intestineSTOMACH + INTESTINE3
41Whole animalWHOLE ANIMALS1
+ +
+
+
+
+

source

+
+

RemapBiotaBodyPartCB

+
+
 RemapBiotaBodyPartCB (fn_lut:Callable)
+
+

Update bodypart id based on MARIS body part LUT (dbo_bodypar.xlsx).

+ +++++ + + + + + + + + + + + + + + +
TypeDetails
fn_lutCallableFunction that returns the lookup table dictionary
+
+
+Exported source +
class RemapBiotaBodyPartCB(Callback):
+    "Update bodypart id based on MARIS body part LUT (dbo_bodypar.xlsx)."
+    def __init__(self, 
+                 fn_lut:Callable # Function that returns the lookup table dictionary
+                ):
+        fc.store_attr()
+
+    def __call__(self, tfm):
+        "Remap biota body parts in the DataFrame using the lookup table and print unmatched TISSUE values."
+        lut = self.fn_lut()
+        tfm.dfs['biota']['body_part'] = tfm.dfs['biota']['TISSUE'].apply(lambda x: self._get_body_part(x, lut))
+
+    def _get_body_part(self, 
+                       tissue_value:str, # The TISSUE value from the DataFrame
+                       lut:dict # The lookup table dictionary
+                      ):
+        "Get the matched_id from the lookup table and print TISSUE if the matched_id is -1."
+        match = lut.get(tissue_value, Match(-1, None, None, None))
+        if match.matched_id == -1: 
+            self.print_unmatched_tissue(tissue_value)
+        return match.matched_id
+
+    def print_unmatched_tissue(self, 
+                               tissue_value:str # The TISSUE value from the DataFrame
+                              ):
+        "Print the TISSUE value if the matched_id is -1."
+        print(f"Unmatched TISSUE: {tissue_value}")
+
+
+
+
+Exported source +
lut_tissues = lambda: Remapper(provider_lut_df=pd.read_csv('../../_data/accdb/mors/csv/TISSUE.csv'),
+                               maris_lut_fn=bodyparts_lut_path,
+                               maris_col_id='bodypar_id',
+                               maris_col_name='bodypar',
+                               provider_col_to_match='TISSUE_DESCRIPTION',
+                               provider_col_key='TISSUE',
+                               fname_cache='tissues_helcom.pkl'
+                               ).generate_lookup_table(fixes=fixes_biota_tissues, as_df=False, overwrite=False)
+
+
+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[RemapBiotaSpeciesCB(lut_biota),                
+                            RemapBiotaBodyPartCB(lut_tissues)
+                            ])
+
+print(tfm()['biota'][['TISSUE', 'body_part']][:5])
+
+
   TISSUE  body_part
+0       5         52
+1       5         52
+2       5         52
+3       5         52
+4       5         52
+
+
+
+
+
+

Remap biogroup

+

get_biogroup_lut reads the file at species_lut_path() and from the contents of this file creates a dictionary linking species_id to biogroup_id.

+
+
+Exported source +
lut_biogroup = lambda: get_lut(species_lut_path().parent, species_lut_path().name, 
+                               key='species_id', value='biogroup_id')
+
+
+

RemapBiogroupCB applies the corrected biota bio group data obtained from the lut_biogroup function to the biota dataframe in the dictionary of dataframes, dfs.

+
+

source

+
+

RemapBiogroupCB

+
+
 RemapBiogroupCB (fn_lut:Callable)
+
+

Update biogroup id based on MARIS species LUT (dbo_species.xlsx).

+ +++++ + + + + + + + + + + + + + + +
TypeDetails
fn_lutCallableFunction that returns the lookup table dictionary
+
+
+Exported source +
class RemapBiogroupCB(Callback):
+    "Update biogroup id based on MARIS species LUT (dbo_species.xlsx)."
+    def __init__(self, 
+                 fn_lut:Callable # Function that returns the lookup table dictionary
+                ):
+        fc.store_attr()
+        self.lut = {int(k):v for k,v in fn_lut().items()}
+
+    def __call__(self, tfm):
+        tfm.dfs['biota']['bio_group'] = tfm.dfs['biota']['species'].apply(self._lookup_biogroup)
+
+    def _lookup_biogroup(self, species_id):
+        biogroup = self.lut.get(species_id, -1)
+        if biogroup == -1: print(f"Warning: Species ID {species_id} not found in biogroup lookup table")
+        return biogroup
+
+
+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[RemapBiotaSpeciesCB(lut_biota),                
+                            RemapBiotaBodyPartCB(lut_tissues),
+                            RemapBiogroupCB(lut_biogroup)])
+
+print(tfm()['biota']['bio_group'].unique())
+
+
[ 4  2 14 11  8  3]
+
+
+
+
+
+

Remap Taxon Information

+

These details (Taxonname , TaxonRepName, Taxonrank) are used for importing into the MARIS master database, but are not included in the NetCDF encoding. We need to get the taxon information from the dbo_species.xlsx file:

+

We need to get the taxon information from the dbo_species.xlsx file:

+
+

source

+
+

get_taxon_info_lut

+
+
 get_taxon_info_lut (maris_lut:str)
+
+

Retrieve a lookup table for Taxonname from a MARIS lookup table.

+ +++++ + + + + + + + + + + + + + + + + + + + +
TypeDetails
maris_lutstrPath to the MARIS lookup table (Excel file)
ReturnsdictA dictionary mapping species_id to biogroup_id
+
+
+Exported source +
# TODO: Include Commonname field after next MARIS data reconciling process.
+def get_taxon_info_lut(
+    maris_lut:str # Path to the MARIS lookup table (Excel file)
+) -> dict: # A dictionary mapping species_id to biogroup_id
+    "Retrieve a lookup table for Taxonname from a MARIS lookup table."
+    species = pd.read_excel(maris_lut)
+    return species[['species_id', 'Taxonname', 'Taxonrank','TaxonDB','TaxonDBID','TaxonDBURL']].set_index('species_id').to_dict()
+
+lut_taxon = lambda: get_taxon_info_lut(species_lut_path())
+
+
+
+

source

+
+
+

RemapTaxonInformationCB

+
+
 RemapTaxonInformationCB (fn_lut:Callable)
+
+

Update taxon names based on MARIS species LUT dbo_species.xlsx.

+ +++++ + + + + + + + + + + + + + + +
TypeDetails
fn_lutCallableFunction that returns the lookup table dictionary
+
+
+Exported source +
class RemapTaxonInformationCB(Callback):
+    "Update taxon names based on MARIS species LUT `dbo_species.xlsx`."
+    def __init__(self, 
+                 fn_lut:Callable # Function that returns the lookup table dictionary
+                 ):
+        fc.store_attr()
+
+    def __call__(self, tfm):
+        "Update taxon information columns in the DataFrame using the lookup table."
+        lut = self.fn_lut()
+        df = tfm.dfs['biota']
+        
+        self._set_taxon_rep_name(df)
+        
+        taxon_columns = ['Taxonname', 'Taxonrank', 'TaxonDB', 'TaxonDBID', 'TaxonDBURL']
+        for col in taxon_columns:
+            df[col] = df['species'].apply(lambda x: self._get_name_by_species_id(x, lut[col]))
+
+    def _set_taxon_rep_name(self, df: pd.DataFrame):
+        "Set the `TaxonRepName` column to the `RUBIN` column values if it exists."
+        if 'RUBIN' in df.columns:
+            df['TaxonRepName'] = df['RUBIN']
+        else:
+            print("Warning: 'RUBIN' column not found in DataFrame.")
+
+    def _get_name_by_species_id(self, species_id: str, lut: dict) -> str:
+        "Get the name from the lookup table, defaulting to 'Unknown' if not found."
+        name = lut.get(species_id, 'Unknown')
+        if name == 'Unknown':
+            print(f"Unmatched species ID: {species_id}")
+        return name
+
+
+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[ 
+                            RemapBiotaSpeciesCB(lut_biota),                
+                            RemapBiotaBodyPartCB(lut_tissues),
+                            RemapBiogroupCB(lut_biogroup),
+                            RemapTaxonInformationCB(lut_taxon)
+                            ])
+tfm()
+print(tfm.dfs['biota'][['Taxonname', 'Taxonrank','TaxonDB','TaxonDBID','TaxonDBURL']].drop_duplicates().head())
+
+
               Taxonname Taxonrank   TaxonDB TaxonDBID  \
+0           Gadus morhua   species  Wikidata   Q199788   
+40     Sprattus sprattus   species  Wikidata   Q506823   
+44       Clupea harengus   species  Wikidata  Q2396858   
+77  Merlangius merlangus   species  Wikidata   Q273083   
+78       Limanda limanda   species  Wikidata  Q1135526   
+
+                                TaxonDBURL  
+0    https://www.wikidata.org/wiki/Q199788  
+40   https://www.wikidata.org/wiki/Q506823  
+44  https://www.wikidata.org/wiki/Q2396858  
+77   https://www.wikidata.org/wiki/Q273083  
+78  https://www.wikidata.org/wiki/Q1135526  
+
+
+
+
+
+

Remap Sediment types

+

We use again the same IMFA (Inspect, Match, Fix, Apply) pattern to remap the HELCOM sediment types.

+

Let’s inspect the SEDIMENT_TYPE.csv file provided by HELCOM describing the sediment type nomenclature:

+
+
pd.read_csv(Path(fname_in) / 'SEDIMENT_TYPE.csv').head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SEDISEDIMENT TYPERECOMMENDED TO BE USED
0-99NO DATANaN
10GRAVELYES
21SANDYES
32FINE SANDNO
43SILTYES
+ +
+
+
+
+
+
+ +
+
+Tip +
+
+
+

FEEDBACK TO DATA PROVIDER: The SEDI values 56 and 73 are not found in the SEDIMENT_TYPE.csv lookup table provided. Note also there are many nan values in the SEDIMENT_TYPE.csv file.

+

We reassign them to -99 for now but should be clarified/fixed. This is demonstrated below.

+
+
+
+
df_sed_lut = pd.read_csv(Path(fname_in) / 'SEDIMENT_TYPE.csv')
+dfs = load_data(fname_in)
+
+sediment_sedi = set(dfs['sediment'].SEDI.unique())
+lookup_sedi = set(df_sed_lut['SEDI'])
+missing = sediment_sedi - lookup_sedi
+print(f"Missing SEDI values: {missing if missing else 'None'}")
+
+
Missing SEDI values: {56.0, 73.0, nan}
+
+
+

Let’s try to match as many as possible:

+
+
remapper = Remapper(provider_lut_df=pd.read_csv(Path(fname_in)/'SEDIMENT_TYPE.csv'),
+                    maris_lut_fn=sediments_lut_path,
+                    maris_col_id='sedtype_id',
+                    maris_col_name='sedtype',
+                    provider_col_to_match='SEDIMENT TYPE',
+                    provider_col_key='SEDI',
+                    fname_cache='sediments_helcom.pkl'
+                    )
+
+remapper.generate_lookup_table(as_df=True)
+remapper.select_match(match_score_threshold=1)
+
+
Processing: 100%|██████████| 47/47 [00:00<00:00, 137.20it/s]
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
matched_maris_namesource_namematch_score
source_key
-99SoftNO DATA5
50Mud and gravelMUD AND GARVEL2
46Glacial clayCLACIAL CLAY1
+ +
+
+
+
+
+Exported source +
fixes_sediments = {
+    'NO DATA': '(Not available)'
+}
+
+
+
+
remapper.generate_lookup_table(as_df=True, fixes=fixes_sediments)
+remapper.select_match(match_score_threshold=1)
+
+
Processing: 100%|██████████| 47/47 [00:00<00:00, 83.93it/s] 
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
matched_maris_namesource_namematch_score
source_key
50Mud and gravelMUD AND GARVEL2
46Glacial clayCLACIAL CLAY1
+ +
+
+
+
+

source

+
+

RemapSedimentCB

+
+
 RemapSedimentCB (fn_lut:Callable)
+
+

Update sediment id based on MARIS species LUT (dbo_sedtype.xlsx).

+ +++++ + + + + + + + + + + + + + + +
TypeDetails
fn_lutCallableFunction that returns the lookup table dictionary
+
+
+Exported source +
class RemapSedimentCB(Callback):
+    "Update sediment id based on MARIS species LUT (dbo_sedtype.xlsx)."
+    def __init__(self, 
+                 fn_lut:Callable, # Function that returns the lookup table dictionary
+                ):
+        fc.store_attr()
+
+    def _fix_inconsistent_sedi(self, df:pd.DataFrame):
+        "Temporary fix for inconsistent SEDI values. Data provider to confirm and clarify."
+        df['SEDI'] = df['SEDI'].replace({56: -99, 73: -99, np.nan: -99})
+        return df
+    
+    def __call__(self, tfm):
+        "Remap sediment types in the DataFrame using the lookup table and handle specific replacements."
+        lut = self.fn_lut()
+        
+        # Set SedRepName (TBC: what's used for?)
+        tfm.dfs['sediment']['SedRepName']  = tfm.dfs['sediment']['SEDI'] 
+        
+        tfm.dfs['sediment'] = self._fix_inconsistent_sedi(tfm.dfs['sediment'])
+        tfm.dfs['sediment']['sed_type'] = tfm.dfs['sediment']['SEDI'].apply(lambda x: self._get_sediment_type(x, lut))
+
+    def _get_sediment_type(self, 
+                           sedi_value:int, # The `SEDI` value from the DataFrame
+                           lut:dict # The lookup table dictionary
+                          ): 
+        "Get the matched_id from the lookup table and print SEDI if the matched_id is -1."
+        match = lut.get(sedi_value, Match(-1, None, None, None))
+        
+        if match.matched_id == -1:
+            self._print_unmatched_sedi(sedi_value)
+        return match.matched_id
+
+    def _print_unmatched_sedi(self, 
+                              sedi_value:int # The `SEDI` value from the DataFram
+                             ):
+        "Print the SEDI value if the matched_id is -1."
+        print(f"Unmatched SEDI: {sedi_value}")
+
+
+
+
+Exported source +
lut_sediments = lambda: Remapper(provider_lut_df=pd.read_csv(Path(fname_in) / 'SEDIMENT_TYPE.csv'),
+                                 maris_lut_fn=sediments_lut_path,
+                                 maris_col_id='sedtype_id',
+                                 maris_col_name='sedtype',
+                                 provider_col_to_match='SEDIMENT TYPE',
+                                 provider_col_key='SEDI',
+                                 fname_cache='sediments_helcom.pkl'
+                                 ).generate_lookup_table(fixes=fixes_sediments, as_df=False, overwrite=False)
+
+
+

Apply the transformer for callbacks RemapSedimentCB(get_maris_sediments). Then, print the SEDI and sed_type for the biota dataframe.

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[RemapSedimentCB(lut_sediments)])
+
+tfm()['sediment']['sed_type'].unique()
+
+
array([ 0,  2, 58, 30, 59, 55, 56, 36, 29, 47,  4, 54, 33,  6, 44, 42, 48,
+       61, 57, 28, 49, 32, 45, 39, 46, 38, 31, 60, 62, 26, 53, 52,  1, 51,
+       37, 34, 50,  7, 10, 41, 43, 35])
+
+
+
+
+
+

Remap units

+
+
+
+ +
+
+Tip +
+
+
+

FEEDBACK TO DATA PROVIDER: The handling of unit types varies between biota and sediment sample types. For consistency and ease of use, it would be beneficial to have dedicated unit columns for all sample types.

+
+
+

For seawater and sediment sample types, the HELCOM dataset refers to units direcly in the name of certain columns, such as VALUE_Bq/m³ or VALUE_Bq/kg. As for biota, the units are included in the BASIS column. This is shown below:

+
+
dfs = load_data(fname_in)
+for grp in ['biota', 'sediment', 'seawater']:
+    print(f"{grp}: {dfs[grp].columns}")
+    
+dfs['biota']['BASIS'].unique()
+
+
biota: Index(['KEY', 'NUCLIDE', 'METHOD', '< VALUE_Bq/kg', 'VALUE_Bq/kg', 'BASIS',
+       'ERROR%', 'NUMBER', 'DATE_OF_ENTRY_x', 'COUNTRY', 'LABORATORY',
+       'SEQUENCE', 'DATE', 'YEAR', 'MONTH', 'DAY', 'STATION',
+       'LATITUDE ddmmmm', 'LATITUDE dddddd', 'LONGITUDE ddmmmm',
+       'LONGITUDE dddddd', 'SDEPTH', 'RUBIN', 'BIOTATYPE', 'TISSUE', 'NO',
+       'LENGTH', 'WEIGHT', 'DW%', 'LOI%', 'MORS_SUBBASIN', 'HELCOM_SUBBASIN',
+       'DATE_OF_ENTRY_y'],
+      dtype='object')
+sediment: Index(['KEY', 'NUCLIDE', 'METHOD', '< VALUE_Bq/kg', 'VALUE_Bq/kg', 'ERROR%_kg',
+       '< VALUE_Bq/m²', 'VALUE_Bq/m²', 'ERROR%_m²', 'DATE_OF_ENTRY_x',
+       'COUNTRY', 'LABORATORY', 'SEQUENCE', 'DATE', 'YEAR', 'MONTH', 'DAY',
+       'STATION', 'LATITUDE (ddmmmm)', 'LATITUDE (dddddd)',
+       'LONGITUDE (ddmmmm)', 'LONGITUDE (dddddd)', 'DEVICE', 'TDEPTH',
+       'UPPSLI', 'LOWSLI', 'AREA', 'SEDI', 'OXIC', 'DW%', 'LOI%',
+       'MORS_SUBBASIN', 'HELCOM_SUBBASIN', 'SUM_LINK', 'DATE_OF_ENTRY_y'],
+      dtype='object')
+seawater: Index(['KEY', 'NUCLIDE', 'METHOD', '< VALUE_Bq/m³', 'VALUE_Bq/m³', 'ERROR%_m³',
+       'DATE_OF_ENTRY_x', 'COUNTRY', 'LABORATORY', 'SEQUENCE', 'DATE', 'YEAR',
+       'MONTH', 'DAY', 'STATION', 'LATITUDE (ddmmmm)', 'LATITUDE (dddddd)',
+       'LONGITUDE (ddmmmm)', 'LONGITUDE (dddddd)', 'TDEPTH', 'SDEPTH', 'SALIN',
+       'TTEMP', 'FILT', 'MORS_SUBBASIN', 'HELCOM_SUBBASIN', 'DATE_OF_ENTRY_y'],
+      dtype='object')
+
+
+
array(['W', nan, 'D', 'F'], dtype=object)
+
+
+

Given the inconsistent handling of units across sample types, we need to define custom mapping rules for standardizing the units. Below the MARIS unit types:

+
+
pd.read_excel(unit_lut_path())[['unit_id', 'unit', 'unit_sanitized']]
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
unit_idunitunit_sanitized
0-1Not applicableNot applicable
10NOT AVAILABLENOT AVAILABLE
21Bq/m3Bq per m3
32Bq/m2Bq per m2
43Bq/kgBq per kg
54Bq/kgdBq per kgd
65Bq/kgwBq per kgw
76kg/kgkg per kg
87TUTU
98DELTA/millDELTA per mill
109atom/kgatom per kg
1110atom/kgdatom per kgd
1211atom/kgwatom per kgw
1312atom/latom per l
1413Bq/kgCBq per kgC
+ +
+
+
+

We define unit names renaming rules from HELCOM in an ad hoc way for now:

+
+

source

+
+

RemapUnitCB

+
+
 RemapUnitCB (lut_units:dict={'seawater': 1, 'sediment': 4, 'biota': {'D':
+              4, 'W': 5, 'F': 5}})
+
+

Set the unit id column in the DataFrames based on a lookup table.

+ ++++++ + + + + + + + + + + + + + + + + +
TypeDefaultDetails
lut_unitsdict{‘seawater’: 1, ‘sediment’: 4, ‘biota’: {‘D’: 4, ‘W’: 5, ‘F’: 5}}Dictionary containing renaming rules for different unit categories
+
+
+Exported source +
lut_units = {
+    'seawater': 1,  # 'Bq/m3'
+    'sediment': 4,  # 'Bq/kgd' for sediment
+    'biota': {
+        'D': 4,  # 'Bq/kgd'
+        'W': 5,  # 'Bq/kgw'
+        'F': 5   # 'Bq/kgw' (assumed to be 'Fresh', so set to wet)
+    }
+}
+
+
+

Apply the transformer for callback RemapUnitCB(). Then, print the unique unit for the seawater dataframe.

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[RemapUnitCB()])
+
+for grp in ['biota', 'sediment', 'seawater']:
+    print(f"{grp}: {tfm()[grp]['unit'].unique()}")
+
+
biota: [5 0 4]
+sediment: [4]
+seawater: [1]
+
+
+
+
+
+

Remap detection limit

+

Detection limits are encoded as follows in MARIS:

+
+
pd.read_excel(detection_limit_lut_path())
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
idnamename_sanitized
0-1Not applicableNot applicable
10Not AvailableNot available
21=Detected value
32<Detection limit
43NDNot detected
54DEDerived
+ +
+
+
+
+
+Exported source +
lut_dl = lambda: pd.read_excel(detection_limit_lut_path(), usecols=['name','id']).set_index('name').to_dict()['id']
+
+
+

Based on columns of interest for each sample type:

+
+
+Exported source +
coi_dl = {'seawater' : {'val' : 'VALUE_Bq/m³',
+                       'unc' : 'ERROR%_m³',
+                       'dl' : '< VALUE_Bq/m³'},
+          'biota':  {'val' : 'VALUE_Bq/kg',
+                     'unc' : 'ERROR%',
+                     'dl' : '< VALUE_Bq/kg'},
+          'sediment': {
+              'val' : 'VALUE_Bq/kg',
+              'unc' : 'ERROR%_kg',
+              'dl' : '< VALUE_Bq/kg'}}
+
+
+

We follow the following business logic to encode the detection limit:

+

RemapDetectionLimitCB creates a detection_limit column with values determined as follows: 1. Perform a lookup with the appropriate columns value type (or detection limit) columns (< VALUE_Bq/m³ or < VALUE_Bq/kg) against the table returned from the function get_detectionlimit_lut. 2. If < VALUE_Bq/m³ or < VALUE_Bq/kg is NaN but both activity values (VALUE_Bq/m³ or VALUE_Bq/kg) and standard uncertainty (ERROR%_m³, ERROR%, or ERROR%_kg) are provided, then assign the ID of 1 (i.e. “Detected value”). 3. For other NaN values in the detection_limit column, set them to 0 (i.e. Not Available).

+
+

source

+
+

RemapDetectionLimitCB

+
+
 RemapDetectionLimitCB (coi:dict, fn_lut:<built-infunctioncallable>)
+
+

Remap value type to MARIS format.

+ + + + + + + + + + + + + + + + + + + + +
TypeDetails
coidictConfiguration options for column names
fn_lutcallableFunction that returns a lookup table
+
+
+Exported source +
# TO BE REFACTORED
+class RemapDetectionLimitCB(Callback):
+    "Remap value type to MARIS format."
+    def __init__(self, 
+                 coi:dict, # Configuration options for column names
+                 fn_lut:callable # Function that returns a lookup table
+                ):
+        fc.store_attr()
+
+    def __call__(self, tfm):
+        "Remap detection limits in the DataFrames using the lookup table."
+        lut = self.fn_lut()
+        
+        for grp in tfm.dfs:
+            df = tfm.dfs[grp]
+            self._update_detection_limit(df, grp, lut)
+    
+    def _update_detection_limit(self, 
+                                df:pd.DataFrame, # The DataFrame to modify
+                                grp:str, # The group name to get the column configuration
+                                lut:dict # The lookup table dictionary
+                               ):
+        "Update detection limit column in the DataFrame based on lookup table and rules."
+        detection_col = self.coi[grp]['dl']
+        value_col = self.coi[grp]['val']
+        uncertainty_col = self.coi[grp]['unc']
+        
+        # Copy detection limit column
+        df['detection_limit'] = df[detection_col]
+        
+        # Fill values with '=' or 'Not Available'
+        condition = ((df[value_col].notna()) & (df[uncertainty_col].notna()) &
+                     (~df['detection_limit'].isin(lut.keys())))
+        df.loc[condition, 'detection_limit'] = '='
+        df.loc[~df['detection_limit'].isin(lut.keys()), 'detection_limit'] = 'Not Available'
+        
+        # Perform lookup
+        df['detection_limit'] = df['detection_limit'].map(lut)
+
+
+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[
+                            NormalizeUncCB(),
+                            SanitizeValue(coi_val),                       
+                            RemapUnitCB(),
+                            RemapDetectionLimitCB(coi_dl, lut_dl)])
+
+
+for grp in ['biota', 'sediment', 'seawater']:
+    print(f"{grp}: {tfm()[grp]['detection_limit'].unique()}")
+
+
biota: [2 1 0]
+sediment: [1 2 0]
+seawater: [1 2 0]
+
+
+
+
+
+

Remap filtering status

+

HELCOM filtered status is encoded as follows in the FILT column:

+
+
dfs = load_data(fname_in)
+get_unique_across_dfs(dfs, col_name='FILT', as_df=True).head(5)
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
indexvalue
00NaN
11N
22F
33n
+ +
+
+
+

While MARIS uses a different encoding for filtered status:

+
+
pd.read_excel(filtered_lut_path())
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
idname
0-1Not applicable
10Not available
21Yes
32No
+ +
+
+
+

For only four categories to remap, the Remapper is an overkill. We can use a simple dictionary to map the values:

+
+
+Exported source +
lut_filtered = {
+    'N': 2,
+    'n': 2,
+    'F': 1
+}
+
+
+

RemapFiltCB converts the HELCOM FILT format to the MARIS FILT format.

+
+

source

+
+

RemapFiltCB

+
+
 RemapFiltCB (lut_filtered:dict={'N': 2, 'n': 2, 'F': 1})
+
+

Lookup FILT value in dataframe using the lookup table.

+ ++++++ + + + + + + + + + + + + + + + + +
TypeDefaultDetails
lut_filtereddict{‘N’: 2, ‘n’: 2, ‘F’: 1}Dictionary mapping FILT codes to their corresponding names
+
+
+Exported source +
class RemapFiltCB(Callback):
+    "Lookup FILT value in dataframe using the lookup table."
+    def __init__(self,
+                 lut_filtered:dict=lut_filtered, # Dictionary mapping FILT codes to their corresponding names
+                ):
+        fc.store_attr()
+
+    def __call__(self, tfm):
+        for df in tfm.dfs.values():
+            if 'FILT' in df.columns:
+                df['FILT'] = df['FILT'].map(lambda x: self.lut_filtered.get(x, 0))
+
+
+

For instance:

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[RemapFiltCB(lut_filtered)])
+
+print(tfm()['seawater']['FILT'].unique())
+
+
[0 2 1]
+
+
+
+
+
+

Add Sample Laboratory code

+

Sample Laboratory code is currently stored in MARIS master DB but not encoded as NetCDF variable. Decision to include it in the NetCDF output is TBD.

+
+

source

+
+

AddSampleLabCodeCB

+
+
 AddSampleLabCodeCB ()
+
+

Remap KEY column to samplabcode in each DataFrame.

+
+
+Exported source +
class AddSampleLabCodeCB(Callback):
+    "Remap `KEY` column to `samplabcode` in each DataFrame."
+    def __call__(self, tfm):
+        for grp in tfm.dfs:
+            self._remap_sample_id(tfm.dfs[grp])
+    
+    def _remap_sample_id(self, df:pd.DataFrame):
+        df['samplabcode'] = df['KEY']
+
+
+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[
+                            AddSampleLabCodeCB(),
+                            CompareDfsAndTfmCB(dfs)
+                            ])
+
+print(tfm()['seawater']['samplabcode'].unique())
+print(pd.DataFrame.from_dict(tfm.compare_stats) , '\n')
+
+
['WKRIL2012003' 'WKRIL2012004' 'WKRIL2012005' ... 'WSSSM2021006'
+ 'WSSSM2021007' 'WSSSM2021008']
+                                                    seawater  sediment  biota
+Number of rows in dfs                                  21216     39817  15827
+Number of rows in tfm.dfs                              21216     39817  15827
+Number of dropped rows                                     0         0      0
+Number of rows in tfm.dfs + Number of dropped rows     21216     39817  15827 
+
+
+
+
+
+
+

Add masurement note

+

The HELCOM dataset includes a look-up table ANALYSIS_METHOD.csv capturing the measurement method used as described by HELCOM. For instance:

+
+
pd.read_csv(Path(fname_in) / 'ANALYSIS_METHOD.csv').head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
METHODDESCRIPTIONCOUNTRY
0BFFG01Gammaspectrometric analysis with Germanium det...6
1BFFG02Sr-90, a) Y-90 extraction method dried ash and...6
2BFFG03Pu238, Pu239241; Ashing and and drying the tra...6
3BFFG04Am-241 (not to in use any more)6
4CLOR01137Cs and 40K activity concentrations are dete...67
+ +
+
+
+
+

source

+
+

AddMeasurementNoteCB

+
+
 AddMeasurementNoteCB (fn_lut:<built-infunctioncallable>)
+
+

Record measurement notes by adding a ‘measurenote’ column to DataFrames.

+ +++++ + + + + + + + + + + + + + + +
TypeDetails
fn_lutcallableFunction that returns the lookup dictionary with METHOD as key and DESCRIPTION as value
+
+
+Exported source +
lut_method = lambda: pd.read_csv(Path(fname_in) / 'ANALYSIS_METHOD.csv').set_index('METHOD').to_dict()['DESCRIPTION']
+
+
+
+
+Exported source +
class AddMeasurementNoteCB(Callback):
+    "Record measurement notes by adding a 'measurenote' column to DataFrames."
+    def __init__(self, 
+                 fn_lut:callable # Function that returns the lookup dictionary with `METHOD` as key and `DESCRIPTION` as value
+                ):
+        fc.store_attr()
+        
+    def __call__(self, tfm):
+        lut = self.fn_lut()
+        for df in tfm.dfs.values():
+            if 'METHOD' in df.columns:
+                df['measurementnote'] = df['METHOD'].map(lambda x: lut.get(x, 0))
+
+
+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[AddMeasurementNoteCB(lut_method),
+                            CompareDfsAndTfmCB(dfs)])
+
+tfm()
+print(tfm.dfs['seawater']['measurementnote'].unique()[:5])
+print(pd.DataFrame.from_dict(tfm.compare_stats) , '\n')
+
+
[0
+ 'Radiochemical method Radiocaesium separation from seawater samples.134+137Cs was adsorbed on AMP mat,  dissolved with NaOH and after purification precipitated as chloroplatinate (Cs2PtCl6).Counting with low background anticoincidence beta counter.'
+ 'Radiochem. meth of Sr90. Precipation with oxalate and separation of calcium, barium, radium and ytrium couting with low background anticoincidence beta counter. 1982-1994'
+ 'For tritium liquid scintialtion counting, combined with electrolytic enrichment of analysed water samples, double distilled, before and after electrolysis in cells. Liquid Scintillation spectrometer LKB Wallac model 1410'
+ 'Pretreatment drying (sediment, biota samples) and ashing (biota samples)or vaporization to 1000 ml (sea water samples), measured by gamma-spectrometry using HPGe detectors sediment, biota, sea water /Cs-137, Cs-134, K-40']
+                                                    seawater  sediment  biota
+Number of rows in dfs                                  21216     39817  15827
+Number of rows in tfm.dfs                              21216     39817  15827
+Number of dropped rows                                     0         0      0
+Number of rows in tfm.dfs + Number of dropped rows     21216     39817  15827 
+
+
+
+
+
+
+

Add station

+

Not included in the NetCDF output.

+
+

source

+
+

RemapStationIdCB

+
+
 RemapStationIdCB ()
+
+

Remap Station ID to MARIS format.

+
+
+Exported source +
class RemapStationIdCB(Callback):
+    "Remap Station ID to MARIS format."
+    def __init__(self):
+        fc.store_attr()
+
+    def __call__(self, tfm:Transformer):
+        "Iterate through all DataFrames in the transformer object and remap `STATION` to `station_id`."
+        for grp in tfm.dfs.keys(): 
+            tfm.dfs[grp]['station'] = tfm.dfs[grp]['STATION']
+
+
+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[
+                            RemapStationIdCB(),
+                            CompareDfsAndTfmCB(dfs)
+                            ])
+tfm()
+print(pd.DataFrame.from_dict(tfm.compare_stats) , '\n')
+
+
                                                    seawater  sediment  biota
+Number of rows in dfs                                  21216     39817  15827
+Number of rows in tfm.dfs                              21216     39817  15827
+Number of dropped rows                                     0         0      0
+Number of rows in tfm.dfs + Number of dropped rows     21216     39817  15827 
+
+
+
+
+
+
+

Add slice position (top and bottom)

+

Not included in the NetCDF output.

+
+

source

+
+

RemapSedSliceTopBottomCB

+
+
 RemapSedSliceTopBottomCB ()
+
+

Remap Sediment slice top and bottom to MARIS format.

+
+
+Exported source +
class RemapSedSliceTopBottomCB(Callback):
+    "Remap Sediment slice top and bottom to MARIS format."
+    def __call__(self, tfm:Transformer):
+        "Iterate through all DataFrames in the transformer object and remap sediment slice top and bottom."
+        tfm.dfs['sediment']['top'] = tfm.dfs['sediment']['UPPSLI']
+        tfm.dfs['sediment']['bottom'] = tfm.dfs['sediment']['LOWSLI']
+
+
+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[RemapSedSliceTopBottomCB()])
+tfm()
+print(tfm.dfs['sediment'][['top','bottom']].head())
+
+
    top  bottom
+0  15.0    20.0
+1  20.0    27.0
+2   0.0     2.0
+3   2.0     4.0
+4   4.0     6.0
+
+
+
+
+
+

Add dry to wet ratio

+

DW% is not included in the NetCDF output currently.

+

HELCOM Description:

+

Sediment: 1. DW%: DRY WEIGHT AS PERCENTAGE (%) OF FRESH WEIGHT. 2. VALUE_Bq/kg: Measured radioactivity concentration in Bq/kg dry wt. in scientific format(e.g. 123 = 1.23E+02, 0.076 = 7.6E-02)

+

Biota: 1. WEIGHT: Average weight (in g) of specimen in the sample 2. DW%: DRY WEIGHT AS PERCENTAGE (%) OF FRESH WEIGHT

+
+

source

+
+

LookupDryWetRatio

+
+
 LookupDryWetRatio ()
+
+

Lookup dry-wet ratio and format for MARIS.

+
+
+Exported source +
class LookupDryWetRatio(Callback):
+    "Lookup dry-wet ratio and format for MARIS."
+    def __call__(self, tfm:Transformer):
+        "Iterate through all DataFrames in the transformer object and apply the dry-wet ratio lookup."
+        for grp in tfm.dfs.keys():
+            if 'DW%' in tfm.dfs[grp].columns:
+                self._apply_dry_wet_ratio(tfm.dfs[grp])
+
+    def _apply_dry_wet_ratio(self, df: pd.DataFrame):
+        "Apply dry-wet ratio conversion and formatting to the given DataFrame."
+        df['dry_wet_ratio'] = df['DW%']
+        # Convert 'DW%' = 0% to NaN.
+        df.loc[df['dry_wet_ratio'] == 0, 'dry_wet_ratio'] = np.NaN
+
+
+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[
+                            LookupDryWetRatio(),
+                            CompareDfsAndTfmCB(dfs)
+                            ])
+
+tfm()
+print(pd.DataFrame.from_dict(tfm.compare_stats) , '\n')
+print(tfm.dfs['biota']['dry_wet_ratio'].head())
+
+
                                                    seawater  sediment  biota
+Number of rows in dfs                                  21216     39817  15827
+Number of rows in tfm.dfs                              21216     39817  15827
+Number of dropped rows                                     0         0      0
+Number of rows in tfm.dfs + Number of dropped rows     21216     39817  15827 
+
+0    18.453
+1    18.453
+2    18.453
+3    18.453
+4    18.458
+Name: dry_wet_ratio, dtype: float64
+
+
+
+
+
+

Standardize Coordinates

+
+

Parsing

+

Use decimal degree coordinates if available; otherwise, convert from degree-minute format to decimal degrees.

+
+

source

+
+
+

ddmmmm2dddddd

+
+
 ddmmmm2dddddd (ddmmmm:float)
+
+ +++++ + + + + + + + + + + + + + + +
TypeDetails
ddmmmmfloatCoordinates in ddmmmm format where dd are degrees and mmmm`` are minutes | | **Returns** | **float** | **Coordinates indddddd`` format**
+
+
+Exported source +
coi_coordinates = {
+    'seawater': {
+        'lon_d': 'LONGITUDE (dddddd)',
+        'lat_d': 'LATITUDE (dddddd)',
+        'lon_m': 'LONGITUDE (ddmmmm)',
+        'lat_m': 'LATITUDE (ddmmmm)'
+    },
+    'biota': {
+        'lon_d': 'LONGITUDE dddddd',
+        'lat_d': 'LATITUDE dddddd',
+        'lon_m': 'LONGITUDE ddmmmm',
+        'lat_m': 'LATITUDE ddmmmm'
+    },
+    'sediment': {
+        'lon_d': 'LONGITUDE (dddddd)',
+        'lat_d': 'LATITUDE (dddddd)',
+        'lon_m': 'LONGITUDE (ddmmmm)',
+        'lat_m': 'LATITUDE (ddmmmm)'
+    }
+}
+
+
+
+
+Exported source +
def ddmmmm2dddddd(
+    ddmmmm:float # Coordinates in `ddmmmm` format where `dd` are degrees and `mmmm`` are minutes
+    ) -> float: # Coordinates in `dddddd`` format
+    # Split into degrees and minutes
+    mins, degs = modf(ddmmmm)
+    # Convert minutes to decimal
+    mins = mins * 100
+    # Convert to 'dddddd' format
+    return round(int(degs) + (mins / 60), 6)
+
+
+
+

source

+
+
+

FormatCoordinates

+
+
 FormatCoordinates (coi:dict, fn_convert_cor:Callable)
+
+

Format coordinates for MARIS. Converts coordinates from ‘ddmmmm’ to ‘dddddd’ format if needed.

+ + + + + + + + + + + + + + + + + + + + +
TypeDetails
coidictColumn names mapping for coordinates
fn_convert_corCallableFunction to convert coordinates
+
+
+Exported source +
class FormatCoordinates(Callback):
+    "Format coordinates for MARIS. Converts coordinates from 'ddmmmm' to 'dddddd' format if needed."
+    def __init__(self, 
+                 coi:dict, # Column names mapping for coordinates
+                 fn_convert_cor:Callable # Function to convert coordinates
+                 ):
+        fc.store_attr()
+
+    def __call__(self, tfm:Transformer):
+        "Apply formatting to coordinates in the DataFrame."
+        for grp in tfm.dfs.keys():
+            self._format_coordinates(tfm.dfs[grp], grp)
+
+    def _format_coordinates(self, 
+                            df:pd.DataFrame, # DataFrame to modify
+                            grp: str # Group name to determine column names
+                            ):
+        "Format coordinates in the DataFrame for a specific group."
+        lon_col_d = self.coi[grp]['lon_d']
+        lat_col_d = self.coi[grp]['lat_d']
+        lon_col_m = self.coi[grp]['lon_m']
+        lat_col_m = self.coi[grp]['lat_m']
+        
+        # Define condition where 'dddddd' format is not available or is zero
+        condition = (
+            (df[lon_col_d].isna() | (df[lon_col_d] == 0)) |
+            (df[lat_col_d].isna() | (df[lat_col_d] == 0))
+        )
+        
+        # Apply conversion function only to non-null and non-zero values
+        df['lon'] = np.where(
+            condition,
+            df[lon_col_m].apply(lambda x: self._safe_convert(x)),
+            df[lon_col_d]
+        )
+        
+        df['lat'] = np.where(
+            condition,
+            df[lat_col_m].apply(lambda x: self._safe_convert(x)),
+            df[lat_col_d]
+        )
+        
+        # Drop rows where coordinate columns contain NaN values
+        df.dropna(subset=['lat', 'lon'], inplace=True)
+
+    def _safe_convert(self, 
+                      value:float # Coordinate value to convert
+                      ):
+        "Convert coordinate value safely, handling NaN values."
+        if pd.isna(value):
+            return value  # Return NaN if value is NaN
+        try:
+            return self.fn_convert_cor(value)
+        except Exception as e:
+            print(f"Error converting value {value}: {e}")
+            return value  # Return original value if an error occurs
+
+
+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[                    
+                            FormatCoordinates(coi_coordinates, ddmmmm2dddddd),
+                            CompareDfsAndTfmCB(dfs)
+                            ])
+tfm()
+print(pd.DataFrame.from_dict(tfm.compare_stats) , '\n')
+print(tfm.dfs['biota'][['lat','lon']])
+
+
                                                    seawater  sediment  biota
+Number of rows in dfs                                  21216     39817  15827
+Number of rows in tfm.dfs                              21208     39816  15827
+Number of dropped rows                                     8         1      0
+Number of rows in tfm.dfs + Number of dropped rows     21216     39817  15827 
+
+             lat        lon
+0      54.283333  12.316667
+1      54.283333  12.316667
+2      54.283333  12.316667
+3      54.283333  12.316667
+4      54.283333  12.316667
+...          ...        ...
+15822  60.373333  18.395667
+15823  60.373333  18.395667
+15824  60.503333  18.366667
+15825  60.503333  18.366667
+15826  60.503333  18.366667
+
+[15827 rows x 2 columns]
+
+
+
+
+

Sanitizing

+

Sanitize coordinates drops a row when both longitude & latitude equal 0 or data contains unrealistic longitude & latitude values. Converts longitude & latitude , separator to . separator.”

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[
+                            FormatCoordinates(coi_coordinates, ddmmmm2dddddd),
+                            SanitizeLonLatCB(),
+                            CompareDfsAndTfmCB(dfs)
+                            ])
+
+tfm()
+print(pd.DataFrame.from_dict(tfm.compare_stats) , '\n')
+print(tfm.dfs['biota'][['lat','lon']])
+
+
                                                    seawater  sediment  biota
+Number of rows in dfs                                  21216     39817  15827
+Number of rows in tfm.dfs                              21208     39816  15827
+Number of dropped rows                                     8         1      0
+Number of rows in tfm.dfs + Number of dropped rows     21216     39817  15827 
+
+             lat        lon
+0      54.283333  12.316667
+1      54.283333  12.316667
+2      54.283333  12.316667
+3      54.283333  12.316667
+4      54.283333  12.316667
+...          ...        ...
+15822  60.373333  18.395667
+15823  60.373333  18.395667
+15824  60.503333  18.366667
+15825  60.503333  18.366667
+15826  60.503333  18.366667
+
+[15827 rows x 2 columns]
+
+
+
+
+
+

Review all callbacks

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[
+                            AddSampleTypeIdColumnCB(),
+                            LowerStripNameCB(col_src='NUCLIDE'),
+                            RemapNuclideNameCB(lut_nuclides),
+                            AddNuclideIdColumnCB(col_value='NUCLIDE'),
+                            ParseTimeCB(),
+                            EncodeTimeCB(cfg()),
+                            SanitizeValue(coi_val),       
+                            NormalizeUncCB(),
+                            RemapBiotaSpeciesCB(lut_biota),
+                            RemapBiotaBodyPartCB(lut_tissues),
+                            RemapBiogroupCB(lut_biogroup),
+                            RemapTaxonInformationCB(lut_taxon),
+                            RemapSedimentCB(lut_sediments),
+                            RemapUnitCB(),
+                            RemapDetectionLimitCB(coi_dl, lut_dl),
+                            RemapFiltCB(lut_filtered),
+                            AddSampleLabCodeCB(),
+                            AddMeasurementNoteCB(lut_method),
+                            RemapStationIdCB(),
+                            RemapSedSliceTopBottomCB(),
+                            LookupDryWetRatio(),
+                            FormatCoordinates(coi_coordinates, ddmmmm2dddddd),
+                            SanitizeLonLatCB(),
+                            CompareDfsAndTfmCB(dfs)
+                            ])
+
+tfm()
+print(pd.DataFrame.from_dict(tfm.compare_stats) , '\n')
+
+
                                                    seawater  sediment  biota
+Number of rows in dfs                                  21216     39817  15827
+Number of rows in tfm.dfs                              21114     39531  15798
+Number of dropped rows                                   102       286     29
+Number of rows in tfm.dfs + Number of dropped rows     21216     39817  15827 
+
+
+
+

For instance, to inspect dropped rows:

+
+
tfm.dfs_dropped['seawater'].head()
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KEYNUCLIDEMETHOD< VALUE_Bq/m³VALUE_Bq/m³ERROR%_m³DATE_OF_ENTRY_xCOUNTRYLABORATORYSEQUENCE...LONGITUDE (ddmmmm)LONGITUDE (dddddd)TDEPTHSDEPTHSALINTTEMPFILTMORS_SUBBASINHELCOM_SUBBASINDATE_OF_ENTRY_y
13439WRISO2001025CS137RISO02NaNNaN10.0NaN26.0RISO2001025.0...10.50010.83333322.020.00.00NaNN5.05.0NaN
14017WLEPA2002001CS134LEPA02<NaNNaNNaN93.0LEPA2002001.0...21.03021.05000016.00.03.7714.40N4.09.0NaN
14020WLEPA2002002CS134LEPA02<NaNNaNNaN93.0LEPA2002004.0...20.57420.95666714.00.06.5711.95N4.09.0NaN
14023WLEPA2002003CS134LEPA02<NaNNaNNaN93.0LEPA2002007.0...19.23619.39333373.00.07.009.19N4.09.0NaN
14026WLEPA2002004CS134LEPA02<NaNNaNNaN93.0LEPA2002010.0...20.20520.34170047.00.07.068.65N4.09.0NaN
+ +

5 rows × 27 columns

+
+
+
+
+
+

Rename columns of interest for NetCDF or Open Refine

+
+

Column names are standardized to MARIS NetCDF format (i.e. PEP8 ).

+
+
+

source

+
+

get_renaming_rules

+
+
 get_renaming_rules (encoding_type='netcdf')
+
+

Define columns of interest (keys) and renaming rules (values).

+
+
+Exported source +
# TO BE REFACTORED
+def get_renaming_rules(encoding_type='netcdf'):
+    "Define columns of interest (keys) and renaming rules (values)."
+    vars = cdl_cfg()['vars']
+    if encoding_type == 'netcdf':
+        return OrderedDict({
+            ('seawater', 'biota', 'sediment'): {
+                # DEFAULT
+                'lat': vars['defaults']['lat']['name'],
+                'lon': vars['defaults']['lon']['name'],
+                'time': vars['defaults']['time']['name'],
+                'NUCLIDE': 'nuclide',
+                'detection_limit': vars['suffixes']['detection_limit']['name'],
+                'unit': vars['suffixes']['unit']['name'],
+                'value': 'value',
+                'uncertainty': vars['suffixes']['uncertainty']['name'],
+                'counting_method': vars['suffixes']['counting_method']['name'],
+                'sampling_method': vars['suffixes']['sampling_method']['name'],
+                'preparation_method': vars['suffixes']['preparation_method']['name']
+            },
+            ('seawater',): {
+                # SEAWATER
+                'SALIN': vars['suffixes']['salinity']['name'],
+                'SDEPTH': vars['defaults']['smp_depth']['name'],
+                #'FILT': vars['suffixes']['filtered']['name'], Need to fix
+                'TTEMP': vars['suffixes']['temperature']['name'],
+                'TDEPTH': vars['defaults']['tot_depth']['name'],
+
+            },
+            ('biota',): {
+                # BIOTA
+                'SDEPTH': vars['defaults']['smp_depth']['name'],
+                'species': vars['bio']['species']['name'],
+                'body_part': vars['bio']['body_part']['name'],
+                'bio_group': vars['bio']['bio_group']['name']
+            },
+            ('sediment',): {
+                # SEDIMENT
+                'sed_type': vars['sed']['sed_type']['name'],
+                'TDEPTH': vars['defaults']['tot_depth']['name'],
+            }
+        })
+    
+    elif encoding_type == 'openrefine':
+        return OrderedDict({
+            ('seawater', 'biota', 'sediment'): {
+                # DEFAULT
+                'samptype_id': 'samptype_id',
+                'lat': 'latitude',
+                'lon': 'longitude',
+                'station': 'station',
+                'begperiod': 'begperiod',
+                'samplabcode': 'samplabcode',
+                #'endperiod': 'endperiod',
+                'nuclide_id': 'nuclide_id',
+                'detection_limit': 'detection',
+                'unit': 'unit_id',
+                'value': 'activity',
+                'uncertainty': 'uncertaint',
+                #'vartype': 'vartype',
+                #'rangelow': 'rangelow',
+                #'rangeupp': 'rangeupp',
+                #'rl_detection': 'rl_detection',
+                #'ru_detection': 'ru_detection',
+                #'freq': 'freq',
+                'SDEPTH': 'sampdepth',
+                #'samparea': 'samparea',
+                'SALIN': 'salinity',
+                'TTEMP': 'temperatur',
+                'FILT': 'filtered',
+                #'oxygen': 'oxygen',
+                #'sampquality': 'sampquality',
+                #'station': 'station',
+                #'samplabcode': 'samplabcode',
+                #'profile': 'profile',
+                #'transect': 'transect',
+                #'IODE_QualityFlag': 'IODE_QualityFlag',
+                'TDEPTH': 'totdepth',
+                #'counmet_id': 'counting_method',
+                #'sampmet_id': 'sampling_method',
+                #'prepmet_id': 'preparation_method',
+                'sampnote': 'sampnote',
+                'measurenote': 'measurenote'
+            },
+            ('seawater',) : {
+                # SEAWATER
+                #'volume': 'volume',
+                #'filtpore': 'filtpore',
+                #'acid': 'acid'
+            },
+            ('biota',) : {
+                # BIOTA
+                'species': 'species_id',
+                'Taxonname': 'Taxonname',
+                'TaxonRepName': 'TaxonRepName',
+                #'Commonname': 'Commonname',
+                'Taxonrank': 'Taxonrank',
+                'TaxonDB': 'TaxonDB',
+                'TaxonDBID': 'TaxonDBID',
+                'TaxonDBURL': 'TaxonDBURL',
+                'body_part': 'bodypar_id',
+                #'drywt': 'drywt',
+                #'wetwt': 'wetwt',
+                'dry_wet_ratio': 'percentwt',
+                #'drymet_id': 'drymet_id'
+            },
+            ('sediment',): {
+                # SEDIMENT
+                'sed_type': 'sedtype_id',
+                #'sedtrap': 'sedtrap',
+                'top': 'sliceup',
+                'bottom': 'slicedown',
+                'SedRepName': 'SedRepName',
+                #'drywt': 'drywt',
+                #'wetwt': 'wetwt',
+                'dry_wet_ratio': 'percentwt',
+                #'drymet_id': 'drymet_id'
+                
+            }
+        })
+    else:
+        print("Invalid encoding_type provided. Please use 'netcdf' or 'openrefine'.")
+        return None
+
+
+
+

source

+
+
+

SelectAndRenameColumnCB

+
+
 SelectAndRenameColumnCB (fn_renaming_rules:Callable,
+                          encoding_type:str='netcdf', verbose:bool=False)
+
+

Select and rename columns in a DataFrame based on renaming rules for a specified encoding type.

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
fn_renaming_rulesCallableA function that returns an OrderedDict of renaming rules
encoding_typestrnetcdfThe encoding type (netcdf or openrefine) to determine which renaming rules to use
verboseboolFalseWhether to print out renaming rules that were not applied
+
+
+Exported source +
class SelectAndRenameColumnCB(Callback):
+    "Select and rename columns in a DataFrame based on renaming rules for a specified encoding type."
+    def __init__(self, 
+                 fn_renaming_rules:Callable, # A function that returns an OrderedDict of renaming rules 
+                 encoding_type:str='netcdf', # The encoding type (`netcdf` or `openrefine`) to determine which renaming rules to use
+                 verbose:bool=False # Whether to print out renaming rules that were not applied
+                 ):
+        fc.store_attr()
+
+    def __call__(self, tfm:Transformer):
+        "Apply column selection and renaming to DataFrames in the transformer, and identify unused rules."
+        try:
+            renaming_rules = self.fn_renaming_rules(self.encoding_type)
+        except ValueError as e:
+            print(f"Error fetching renaming rules: {e}")
+            return
+
+        for group in tfm.dfs.keys():
+            # Get relevant renaming rules for the current group
+            group_rules = self._get_group_rules(renaming_rules, group)
+
+            if not group_rules:
+                continue
+
+            # Apply renaming rules and track keys not found in the DataFrame
+            df = tfm.dfs[group]
+            df, not_found_keys = self._apply_renaming(df, group_rules)
+            tfm.dfs[group] = df
+            
+            # Print any renaming rules that were not used
+            if not_found_keys and self.verbose:
+                print(f"\nGroup '{group}' has the following renaming rules not applied:")
+                for old_col in not_found_keys:
+                    print(f"Key '{old_col}' from renaming rules was not found in the DataFrame.")
+
+    def _get_group_rules(self, 
+                         renaming_rules:OrderedDict, # Renaming rules
+                         group:str # Group name to filter rules
+                         ) -> OrderedDict: # Renaming rules applicable to the specified group
+        "Retrieve and merge renaming rules for the specified group based on the encoding type."
+        relevant_rules = [rules for key, rules in renaming_rules.items() if group in key]
+        merged_rules = OrderedDict()
+        for rules in relevant_rules:
+            merged_rules.update(rules)
+        return merged_rules
+
+    def _apply_renaming(self, 
+                        df:pd.DataFrame, # DataFrame to modify
+                        rename_rules:OrderedDict # Renaming rules
+                        ) -> tuple: # (Renamed and filtered df, Column names from renaming rules that were not found in the DataFrame)
+        """
+        Select columns based on renaming rules and apply renaming, only for existing columns
+        while maintaining the order of the dictionary columns."""
+        existing_columns = set(df.columns)
+        valid_rules = OrderedDict((old_col, new_col) for old_col, new_col in rename_rules.items() if old_col in existing_columns)
+
+        # Create a list to maintain the order of columns
+        columns_to_keep = [col for col in rename_rules.keys() if col in existing_columns]
+        columns_to_keep += [new_col for old_col, new_col in valid_rules.items() if new_col in df.columns]
+
+        df = df[list(OrderedDict.fromkeys(columns_to_keep))]
+
+        # Apply renaming
+        df.rename(columns=valid_rules, inplace=True)
+
+        # Determine which keys were not found
+        not_found_keys = set(rename_rules.keys()) - existing_columns
+        return df, not_found_keys
+
+
+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[AddSampleTypeIdColumnCB(),
+                            LowerStripNameCB(col_src='NUCLIDE'),
+                            RemapNuclideNameCB(lut_nuclides),
+                            AddNuclideIdColumnCB(col_value='NUCLIDE'),
+                            ParseTimeCB(),
+                            EncodeTimeCB(cfg()),
+                            SanitizeValue(coi_val),       
+                            NormalizeUncCB(),
+                            RemapBiotaSpeciesCB(lut_biota),
+                            RemapBiotaBodyPartCB(lut_tissues),
+                            RemapBiogroupCB(lut_biogroup),
+                            RemapTaxonInformationCB(lut_taxon),
+                            RemapSedimentCB(lut_sediments),
+                            RemapUnitCB(),
+                            RemapDetectionLimitCB(coi_dl, lut_dl),
+                            RemapFiltCB(lut_filtered),
+                            AddSampleLabCodeCB(),
+                            AddMeasurementNoteCB(lut_method),
+                            RemapStationIdCB(),
+                            RemapSedSliceTopBottomCB(),
+                            LookupDryWetRatio(),
+                            FormatCoordinates(coi_coordinates, ddmmmm2dddddd),
+                            SanitizeLonLatCB(),
+                            CompareDfsAndTfmCB(dfs),
+                            SelectAndRenameColumnCB(get_renaming_rules, encoding_type='netcdf'),
+                            ])
+
+tfm()
+for grp in tfm.dfs.keys():
+    print(f'{grp} columns:')
+    print(tfm.dfs[grp].columns)
+
+
seawater columns:
+Index(['lat', 'lon', 'time', 'nuclide', '_dl', '_unit', 'value', '_unc',
+       '_sal', 'smp_depth', '_temp', 'tot_depth'],
+      dtype='object')
+sediment columns:
+Index(['lat', 'lon', 'time', 'nuclide', '_dl', '_unit', 'value', '_unc',
+       'sed_type', 'tot_depth'],
+      dtype='object')
+biota columns:
+Index(['lat', 'lon', 'time', 'nuclide', '_dl', '_unit', 'value', '_unc',
+       'smp_depth', 'species', 'body_part', 'bio_group'],
+      dtype='object')
+
+
+
+
+
+

Reshape: long to wide

+

Convert data from long to wide and rename columns to comply with NetCDF format.

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[AddSampleTypeIdColumnCB(),
+                            LowerStripNameCB(col_src='NUCLIDE'),
+                            RemapNuclideNameCB(lut_nuclides),
+                            AddNuclideIdColumnCB(col_value='NUCLIDE'),
+                            ParseTimeCB(),
+                            EncodeTimeCB(cfg()),
+                            SanitizeValue(coi_val),       
+                            NormalizeUncCB(),
+                            RemapBiotaSpeciesCB(lut_biota),
+                            RemapBiotaBodyPartCB(lut_tissues),
+                            RemapBiogroupCB(lut_biogroup),
+                            RemapTaxonInformationCB(lut_taxon),
+                            RemapSedimentCB(lut_sediments),
+                            RemapUnitCB(),
+                            RemapDetectionLimitCB(coi_dl, lut_dl),
+                            RemapFiltCB(lut_filtered),
+                            AddSampleLabCodeCB(),
+                            AddMeasurementNoteCB(lut_method),
+                            RemapStationIdCB(),
+                            RemapSedSliceTopBottomCB(),
+                            LookupDryWetRatio(),
+                            FormatCoordinates(coi_coordinates, ddmmmm2dddddd),
+                            SanitizeLonLatCB(),
+                            SelectAndRenameColumnCB(get_renaming_rules, encoding_type='netcdf'),
+                            ReshapeLongToWide()
+                            ])
+
+tfm()
+for grp in tfm.dfs.keys():
+    print(f'{grp} columns:')
+    print(tfm.dfs[grp].columns)
+
+
seawater columns:
+Index(['lon', 'lat', 'tot_depth', 'time', 'smp_depth', 'ag110m_dl', 'am241_dl',
+       'ba140_dl', 'ce144_dl', 'cm242_dl',
+       ...
+       'pu240', 'ru103', 'ru106', 'sb125', 'sr89', 'sr90', 'tc99', 'u234',
+       'u238', 'zr95'],
+      dtype='object', length=175)
+sediment columns:
+Index(['sed_type', 'lon', 'lat', 'tot_depth', 'time', 'ac228_dl', 'ag110m_dl',
+       'am241_dl', 'ba140_dl', 'be7_dl',
+       ...
+       'sb124', 'sb125', 'sr90', 'th228', 'th232', 'th234', 'tl208', 'u235',
+       'zn65', 'zr95'],
+      dtype='object', length=177)
+biota columns:
+Index(['body_part', 'lon', 'bio_group', 'lat', 'species', 'time', 'smp_depth',
+       'ac228_dl', 'ag108m_dl', 'ag110m_dl',
+       ...
+       'sr89', 'sr90', 'tc99', 'te129m', 'th228', 'th232', 'tl208', 'u235',
+       'zn65', 'zr95'],
+      dtype='object', length=211)
+
+
+
+
+

NetCDF encoder

+
+

Example change logs

+
+
dfs = load_data(fname_in)
+
+tfm = Transformer(dfs, cbs=[AddSampleTypeIdColumnCB(),
+                            LowerStripNameCB(col_src='NUCLIDE'),
+                            RemapNuclideNameCB(lut_nuclides),
+                            AddNuclideIdColumnCB(col_value='NUCLIDE'),
+                            ParseTimeCB(),
+                            EncodeTimeCB(cfg()),
+                            SanitizeValue(coi_val),       
+                            NormalizeUncCB(),
+                            RemapBiotaSpeciesCB(lut_biota),
+                            RemapBiotaBodyPartCB(lut_tissues),
+                            RemapBiogroupCB(lut_biogroup),
+                            RemapTaxonInformationCB(lut_taxon),
+                            RemapSedimentCB(lut_sediments),
+                            RemapUnitCB(),
+                            RemapDetectionLimitCB(coi_dl, lut_dl),
+                            RemapFiltCB(lut_filtered),
+                            AddSampleLabCodeCB(),
+                            AddMeasurementNoteCB(lut_method),
+                            RemapStationIdCB(),
+                            RemapSedSliceTopBottomCB(),
+                            LookupDryWetRatio(),
+                            FormatCoordinates(coi_coordinates, ddmmmm2dddddd),
+                            SanitizeLonLatCB(),
+                            SelectAndRenameColumnCB(get_renaming_rules, encoding_type='netcdf'),
+                            ReshapeLongToWide()
+                            ])
+
+tfm()
+tfm.logs
+
+
["Convert values from 'NUCLIDE' to lowercase, strip spaces, and store in 'None'.",
+ 'Encode time as `int` representing seconds since xxx',
+ 'Remap `KEY` column to `samplabcode` in each DataFrame.',
+ 'Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator.']
+
+
+
+
+

Feed global attributes

+
+

source

+
+
+

get_attrs

+
+
 get_attrs (tfm, zotero_key, kw=['oceanography', 'Earth Science > Oceans >
+            Ocean Chemistry> Radionuclides', 'Earth Science > Human
+            Dimensions > Environmental Impacts > Nuclear Radiation
+            Exposure', 'Earth Science > Oceans > Ocean Chemistry > Ocean
+            Tracers, Earth Science > Oceans > Marine Sediments', 'Earth
+            Science > Oceans > Ocean Chemistry, Earth Science > Oceans >
+            Sea Ice > Isotopes', 'Earth Science > Oceans > Water Quality >
+            Ocean Contaminants', 'Earth Science > Biological
+            Classification > Animals/Vertebrates > Fish', 'Earth Science >
+            Biosphere > Ecosystems > Marine Ecosystems', 'Earth Science >
+            Biological Classification > Animals/Invertebrates > Mollusks',
+            'Earth Science > Biological Classification >
+            Animals/Invertebrates > Arthropods > Crustaceans', 'Earth
+            Science > Biological Classification > Plants > Macroalgae
+            (Seaweeds)'])
+
+

Retrieve all global attributes.

+
+
+Exported source +
def get_attrs(tfm, zotero_key, kw=kw):
+    "Retrieve all global attributes."
+    return GlobAttrsFeeder(tfm.dfs, cbs=[
+        BboxCB(),
+        DepthRangeCB(),
+        TimeRangeCB(cfg()),
+        ZoteroCB(zotero_key, cfg=cfg()),
+        KeyValuePairCB('keywords', ', '.join(kw)),
+        KeyValuePairCB('publisher_postprocess_logs', ', '.join(tfm.logs))
+        ])()
+
+
+
+
get_attrs(tfm, zotero_key=zotero_key, kw=kw)
+
+
{'geospatial_lat_min': '31.17',
+ 'geospatial_lat_max': '65.75',
+ 'geospatial_lon_min': '9.6333',
+ 'geospatial_lon_max': '53.5',
+ 'geospatial_bounds': 'POLYGON ((9.6333 53.5, 31.17 53.5, 31.17 65.75, 9.6333 65.75, 9.6333 53.5))',
+ 'time_coverage_start': '1984-01-10T00:00:00',
+ 'time_coverage_end': '2021-12-15T00:00:00',
+ 'title': 'Environmental database - Helsinki Commission Monitoring of Radioactive Substances',
+ 'summary': 'MORS Environment database has been used to collate data resulting from monitoring of environmental radioactivity in the Baltic Sea based on HELCOM Recommendation 26/3.\n\nThe database is structured according to HELCOM Guidelines on Monitoring of Radioactive Substances (https://www.helcom.fi/wp-content/uploads/2019/08/Guidelines-for-Monitoring-of-Radioactive-Substances.pdf), which specifies reporting format, database structure, data types and obligatory parameters used for reporting data under Recommendation 26/3.\n\nThe database is updated and quality assured annually by HELCOM MORS EG.',
+ 'creator_name': '[{"creatorType": "author", "name": "HELCOM MORS"}]',
+ 'keywords': 'oceanography, Earth Science > Oceans > Ocean Chemistry> Radionuclides, Earth Science > Human Dimensions > Environmental Impacts > Nuclear Radiation Exposure, Earth Science > Oceans > Ocean Chemistry > Ocean Tracers, Earth Science > Oceans > Marine Sediments, Earth Science > Oceans > Ocean Chemistry, Earth Science > Oceans > Sea Ice > Isotopes, Earth Science > Oceans > Water Quality > Ocean Contaminants, Earth Science > Biological Classification > Animals/Vertebrates > Fish, Earth Science > Biosphere > Ecosystems > Marine Ecosystems, Earth Science > Biological Classification > Animals/Invertebrates > Mollusks, Earth Science > Biological Classification > Animals/Invertebrates > Arthropods > Crustaceans, Earth Science > Biological Classification > Plants > Macroalgae (Seaweeds)',
+ 'publisher_postprocess_logs': "Convert values from 'NUCLIDE' to lowercase, strip spaces, and store in 'None'., Encode time as `int` representing seconds since xxx, Remap `KEY` column to `samplabcode` in each DataFrame., Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator."}
+
+
+
+

source

+
+
+

enums_xtra

+
+
 enums_xtra (tfm, vars)
+
+

Retrieve a subset of the lengthy enum as species_t for instance.

+
+
+Exported source +
def enums_xtra(tfm, vars):
+    "Retrieve a subset of the lengthy enum as `species_t` for instance."
+    enums = Enums(lut_src_dir=lut_path(), cdl_enums=cdl_cfg()['enums'])
+    xtras = {}
+    for var in vars:
+        unique_vals = tfm.unique(var)
+        if unique_vals.any():
+            xtras[f'{var}_t'] = enums.filter(f'{var}_t', unique_vals)
+    return xtras
+
+
+
+
+

Encoding NetCDF

+
+

source

+
+
+

encode

+
+
 encode (fname_in, fname_out_nc, nc_tpl_path, **kwargs)
+
+
+
+Exported source +
def encode(fname_in, fname_out_nc, nc_tpl_path, **kwargs):
+    dfs = load_data(fname_in)
+    tfm = Transformer(dfs, cbs=[AddSampleTypeIdColumnCB(),
+                            LowerStripNameCB(col_src='NUCLIDE'),
+                            RemapNuclideNameCB(lut_nuclides),
+                            AddNuclideIdColumnCB(col_value='NUCLIDE'),
+                            ParseTimeCB(),
+                            EncodeTimeCB(cfg()),
+                            SanitizeValue(coi_val),       
+                            NormalizeUncCB(),
+                            RemapBiotaSpeciesCB(lut_biota),
+                            RemapBiotaBodyPartCB(lut_tissues),
+                            RemapBiogroupCB(lut_biogroup),
+                            RemapTaxonInformationCB(lut_taxon),
+                            RemapSedimentCB(lut_sediments),
+                            RemapUnitCB(),
+                            RemapDetectionLimitCB(coi_dl, lut_dl),
+                            RemapFiltCB(lut_filtered),
+                            AddSampleLabCodeCB(),
+                            AddMeasurementNoteCB(lut_method),
+                            RemapStationIdCB(),
+                            RemapSedSliceTopBottomCB(),
+                            LookupDryWetRatio(),
+                            FormatCoordinates(coi_coordinates, ddmmmm2dddddd),
+                            SanitizeLonLatCB(),
+                            SelectAndRenameColumnCB(get_renaming_rules, encoding_type='netcdf'),
+                            ReshapeLongToWide()
+                            ])
+    tfm()
+    encoder = NetCDFEncoder(tfm.dfs, 
+                            src_fname=nc_tpl_path,
+                            dest_fname=fname_out_nc, 
+                            global_attrs=get_attrs(tfm, zotero_key=zotero_key, kw=kw),
+                            verbose=kwargs.get('verbose', False),
+                            enums_xtra=enums_xtra(tfm, vars=['species', 'body_part'])
+                           )
+    encoder.encode()
+
+
+
+
encode(fname_in, fname_out_nc, nc_tpl_path(), verbose=False)
+
+
+
+
+

Open Refine Pipeline (WIP)

+
+

Rename columns for Open Refine

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[
+                            AddSampleTypeIdColumnCB(),
+                            LowerStripRdnNameCB(col_src='NUCLIDE'),
+                            RemapRdnNameCB(),
+                            ParseTimeCB(),
+                            EncodeTimeCB(cfg()),        
+                            SanitizeValue(coi_val),                       
+                            NormalizeUncCB(),
+                            LookupBiotaSpeciesCB(get_maris_species),
+                            LookupBiotaBodyPartCB(get_maris_bodypart),                          
+                            LookupBiogroupCB(partial(get_biogroup_lut, species_lut_path())),
+                            LookupTaxonInformationCB(partial(get_taxon_info_lut, species_lut_path())),
+                            LookupSedimentCB(get_maris_sediments),
+                            LookupUnitCB(),
+                            LookupDetectionLimitCB(),    
+                            RemapDataProviderSampleIdCB(),
+                            RecordMeasurementNoteCB(get_helcom_method_desc),
+                            LookupFiltCB(),
+                            RemapStationIdCB(),
+                            RemapSedSliceTopBottomCB(),
+                            LookupDryWetRatio(),
+                            FormatCoordinates(coi_coordinates, ddmmmm2dddddd),
+                            SanitizeLonLatCB(),
+                            SelectAndRenameColumnCB(get_renaming_rules, encoding_type='openrefine', verbose=True),
+                            CompareDfsAndTfmCB(dfs)
+                            ])
+
+tfm()
+print(pd.DataFrame.from_dict(tfm.compare_stats) , '\n')
+
+

+Group 'seawater' has the following renaming rules not applied:
+Key 'sampnote' from renaming rules was not found in the DataFrame.
+
+Group 'sediment' has the following renaming rules not applied:
+Key 'FILT' from renaming rules was not found in the DataFrame.
+Key 'TTEMP' from renaming rules was not found in the DataFrame.
+Key 'SDEPTH' from renaming rules was not found in the DataFrame.
+Key 'SALIN' from renaming rules was not found in the DataFrame.
+Key 'sampnote' from renaming rules was not found in the DataFrame.
+
+Group 'biota' has the following renaming rules not applied:
+Key 'TDEPTH' from renaming rules was not found in the DataFrame.
+Key 'FILT' from renaming rules was not found in the DataFrame.
+Key 'TTEMP' from renaming rules was not found in the DataFrame.
+Key 'SALIN' from renaming rules was not found in the DataFrame.
+Key 'sampnote' from renaming rules was not found in the DataFrame.
+                                                    seawater  sediment  biota
+Number of rows in dfs                                  21216     39817  15827
+Number of rows in tfm.dfs                              21114     39531  15798
+Number of dropped rows                                   102       286     29
+Number of rows in tfm.dfs + Number of dropped rows     21216     39817  15827 
+
+
+
+

Example of data included in dfs_dropped.

+

Main reasons for data to be dropped from dfs: - No activity value reported (e.g. VALUE_Bq/kg) - No time value reported.

+
+
grp='sediment'
+#grp='seawater'
+#grp='biota'
+
+tfm.dfs_dropped[grp]
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KEYNUCLIDEMETHOD< VALUE_Bq/kgVALUE_Bq/kgERROR%_kg< VALUE_Bq/m²VALUE_Bq/m²ERROR%_m²DATE_OF_ENTRY_x...LOWSLIAREASEDIOXICDW%LOI%MORS_SUBBASINHELCOM_SUBBASINSUM_LINKDATE_OF_ENTRY_y
11784SLREB1998021SR902NaNNaNNaNNaNNaNNaNNaN...12.00.0210055.0ONaNNaN14.014.0aNaN
11824SLVDC1997023CS1371NaNNaNNaNNaNNaNNaNNaN...14.00.0210055.0ONaNNaN9.09.0aNaN
11832SLVDC1997031CS1371NaNNaNNaNNaNNaNNaNNaN...14.00.0210055.0ONaNNaN9.09.0aNaN
11841SLVDC1997040CS1371NaNNaNNaNNaNNaNNaNNaN...16.00.0210055.0ONaNNaN9.09.0aNaN
11849SLVDC1998011CS1371NaNNaNNaNNaNNaNNaNNaN...16.00.0210055.0ONaNNaN14.014.0aNaN
..................................................................
39769SSSSM2021030CO60SSSM43<NaNNaN<NaNNaN09/06/22 00:00:00...2.00.01608NaNNaN28.20000015.012.012.0NaN09/06/22 00:00:00
39774SSSSM2021030RA226SSSM43<NaNNaN<NaNNaN09/06/22 00:00:00...2.00.01608NaNNaN28.20000015.012.012.0NaN09/06/22 00:00:00
39775SSSSM2021030RA223SSSM43<NaNNaN<NaNNaN09/06/22 00:00:00...2.00.01608NaNNaN28.20000015.012.012.0NaN09/06/22 00:00:00
39777SSSSM2021031CS137SSSM43<NaNNaN<0.0NaN09/06/22 00:00:00...2.00.01608NaNNaN31.993243NaN13.013.0NaN09/06/22 00:00:00
39779SSSSM2021031CO60SSSM43<NaNNaN<NaNNaN09/06/22 00:00:00...2.00.01608NaNNaN31.993243NaN13.013.0NaN09/06/22 00:00:00
+ +

286 rows × 35 columns

+
+
+
+
+
+
+

Open Refine encoder (WIP)

+
+
def encode_or(fname_in, fname_out_csv, ref_id, **kwargs):
+    dfs = load_data(fname_in)
+    tfm = Transformer(dfs, cbs=[
+                                AddSampleTypeIdColumnCB(),
+                                LowerStripRdnNameCB(col_src='NUCLIDE'),
+                                RemapRdnNameCB(),
+                                ParseTimeCB(),
+                                EncodeTimeCB(cfg()),        
+                                SanitizeValue(coi_val),                       
+                                NormalizeUncCB(),
+                                LookupBiotaSpeciesCB(get_maris_species),
+                                LookupBiotaBodyPartCB(get_maris_bodypart),                          
+                                LookupBiogroupCB(partial(get_biogroup_lut, species_lut_path())),
+                                LookupTaxonInformationCB(partial(get_taxon_info_lut, species_lut_path())),
+                                LookupSedimentCB(get_maris_sediments),
+                                LookupUnitCB(),
+                                LookupDetectionLimitCB(),    
+                                RemapDataProviderSampleIdCB(),
+                                RecordMeasurementNoteCB(get_helcom_method_desc),
+                                LookupFiltCB(),
+                                RemapStationIdCB(),
+                                RemapSedSliceTopBottomCB(),
+                                LookupDryWetRatio(),
+                                FormatCoordinates(coi_coordinates, ddmmmm2dddddd),
+                                SanitizeLonLatCB(),
+                                SelectAndRenameColumnCB(get_renaming_rules, encoding_type='openrefine'),
+                                CompareDfsAndTfmCB(dfs)
+                                ])
+    tfm()
+
+    encoder = OpenRefineCsvEncoder(tfm.dfs, 
+                                    dest_fname=fname_out_csv, 
+                                    ref_id = ref_id,
+                                    verbose = True
+                                )
+    encoder.encode()
+
+
+
encode_or(fname_in, fname_out_csv, ref_id, verbose=True)
+
+
+

Open Refine Variables not included in Helcom

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Field nameFull nameHELCOM
sampqualitySample qualityN
lab_idLaboratory IDN
profile_idProfile IDN
transect_idTransect IDN
endperiodEnd periodN
vartypeVariable typeN
freqFrequencyN
rl_detectionRange low detectionN
rangelowRange lowN
rangeuppRange upperN
CommonnameCommon nameN
volumeVolumeN
filtporeFilter poreN
acidAcidifiedN
oxygenOxygenN
sampareaSample areaN
drywtDry weightN
wetwtWet weightN
sampmet_idSampling method IDN
drymet_idDrying method IDN
prepmet_idPreparation method IDN
counmet_idCounting method IDN
refnoteReference noteN
sampnoteSample noteN
gfeGood for export?
+

TODO:

+
    +
  • Should we use a single encoder for both NetCDF and OpenRefine? If so, should we have a single encode function that accepts a variable ‘encoding_type’.
  • +
+

TODO: Include FILT for NetCDF

+

TODO: Check sediment ‘DW%’ data that is less than 1%. Is this realistic? Check the ‘DW%’ data that is 0%. Run below before SelectAndRenameColumnCB.

+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[LowerStripRdnNameCB(col_src='NUCLIDE'),
+                            ])
+tfm()
+
+
{'seawater':                 KEY NUCLIDE METHOD < VALUE_Bq/m³  VALUE_Bq/m³  ERROR%_m³  \
+ 0      WKRIL2012003   cs137    NaN           NaN          5.3  32.000000   
+ 1      WKRIL2012004   cs137    NaN           NaN         19.9  20.000000   
+ 2      WKRIL2012005   cs137    NaN           NaN         25.5  20.000000   
+ 3      WKRIL2012006   cs137    NaN           NaN         17.0  29.000000   
+ 4      WKRIL2012007   cs137    NaN           NaN         22.2  18.000000   
+ ...             ...     ...    ...           ...          ...        ...   
+ 21211  WSSSM2021005      h3  SSM45           NaN       1030.0  93.203883   
+ 21212  WSSSM2021006      h3  SSM45           NaN       2240.0  43.303571   
+ 21213  WSSSM2021007      h3  SSM45           NaN       2060.0  47.087379   
+ 21214  WSSSM2021008      h3  SSM45           NaN       2300.0  43.478261   
+ 21215  WSSSM2021004      h3  SSM45             <          NaN        NaN   
+ 
+          DATE_OF_ENTRY_x  COUNTRY LABORATORY   SEQUENCE  ...  \
+ 0      08/20/14 00:00:00     90.0       KRIL  2012003.0  ...   
+ 1      08/20/14 00:00:00     90.0       KRIL  2012004.0  ...   
+ 2      08/20/14 00:00:00     90.0       KRIL  2012005.0  ...   
+ 3      08/20/14 00:00:00     90.0       KRIL  2012006.0  ...   
+ 4      08/20/14 00:00:00     90.0       KRIL  2012007.0  ...   
+ ...                  ...      ...        ...        ...  ...   
+ 21211  09/06/22 00:00:00     77.0       SSSM   202105.0  ...   
+ 21212  09/06/22 00:00:00     77.0       SSSM   202106.0  ...   
+ 21213  09/06/22 00:00:00     77.0       SSSM   202107.0  ...   
+ 21214  09/06/22 00:00:00     77.0       SSSM   202108.0  ...   
+ 21215  09/06/22 00:00:00     77.0       SSSM   202104.0  ...   
+ 
+       LONGITUDE (ddmmmm)  LONGITUDE (dddddd)  TDEPTH  SDEPTH SALIN  TTEMP  \
+ 0                29.2000             29.3333     NaN     0.0   NaN    NaN   
+ 1                29.2000             29.3333     NaN    29.0   NaN    NaN   
+ 2                23.0900             23.1500     NaN     0.0   NaN    NaN   
+ 3                27.5900             27.9833     NaN     0.0   NaN    NaN   
+ 4                27.5900             27.9833     NaN    39.0   NaN    NaN   
+ ...                  ...                 ...     ...     ...   ...    ...   
+ 21211            18.2143             18.3572     NaN     1.0   NaN    NaN   
+ 21212            17.0000             17.0000     NaN     1.0   NaN    NaN   
+ 21213            11.5671             11.9452     NaN     1.0   NaN    NaN   
+ 21214            11.5671             11.9452     NaN     1.0   NaN    NaN   
+ 21215            11.1470             11.2450     NaN     1.0   NaN    NaN   
+ 
+        FILT  MORS_SUBBASIN  HELCOM_SUBBASIN    DATE_OF_ENTRY_y  
+ 0       NaN           11.0             11.0  08/20/14 00:00:00  
+ 1       NaN           11.0             11.0  08/20/14 00:00:00  
+ 2       NaN           11.0              3.0  08/20/14 00:00:00  
+ 3       NaN           11.0             11.0  08/20/14 00:00:00  
+ 4       NaN           11.0             11.0  08/20/14 00:00:00  
+ ...     ...            ...              ...                ...  
+ 21211     N            1.0              8.0  09/06/22 00:00:00  
+ 21212     N           10.0             10.0  09/06/22 00:00:00  
+ 21213     N           12.0             12.0  09/06/22 00:00:00  
+ 21214     N           12.0             12.0  09/06/22 00:00:00  
+ 21215     N           15.0             18.0  09/06/22 00:00:00  
+ 
+ [21216 rows x 27 columns],
+ 'sediment':                 KEY NUCLIDE  METHOD < VALUE_Bq/kg  VALUE_Bq/kg  ERROR%_kg  \
+ 0      SKRIL2012048   ra226     NaN           NaN         35.0      26.00   
+ 1      SKRIL2012049   ra226     NaN           NaN         36.0      22.00   
+ 2      SKRIL2012050   ra226     NaN           NaN         38.0      24.00   
+ 3      SKRIL2012051   ra226     NaN           NaN         36.0      25.00   
+ 4      SKRIL2012052   ra226     NaN           NaN         30.0      23.00   
+ ...             ...     ...     ...           ...          ...        ...   
+ 39812  SSSSM2020029   ac228  SSSM43           NaN         37.5       5.00   
+ 39813  SSSSM2020030     k40  SSSM43           NaN        526.0       1.72   
+ 39814  SSSSM2020030   cs137  SSSM43           NaN         17.2       2.21   
+ 39815  SSSSM2020031     k40  SSSM43           NaN       1000.0       1.80   
+ 39816  SSSSM2020031   cs137  SSSM43           NaN         64.0       1.20   
+ 
+       < VALUE_Bq/m²  VALUE_Bq/m²  ERROR%_m²    DATE_OF_ENTRY_x  ...  LOWSLI  \
+ 0               NaN          NaN        NaN  08/20/14 00:00:00  ...    20.0   
+ 1               NaN          NaN        NaN  08/20/14 00:00:00  ...    27.0   
+ 2               NaN          NaN        NaN  08/20/14 00:00:00  ...     2.0   
+ 3               NaN          NaN        NaN  08/20/14 00:00:00  ...     4.0   
+ 4               NaN          NaN        NaN  08/20/14 00:00:00  ...     6.0   
+ ...             ...          ...        ...                ...  ...     ...   
+ 39812           NaN        255.0       28.0  04/22/22 00:00:00  ...     2.0   
+ 39813           NaN       5690.0        2.0  04/22/22 00:00:00  ...     2.0   
+ 39814           NaN        186.0        2.0  04/22/22 00:00:00  ...     2.0   
+ 39815           NaN      16000.0        2.0  04/22/22 00:00:00  ...     2.0   
+ 39816           NaN       1020.0        1.0  04/22/22 00:00:00  ...     2.0   
+ 
+         AREA  SEDI OXIC    DW%  LOI%  MORS_SUBBASIN HELCOM_SUBBASIN  SUM_LINK  \
+ 0      0.006   NaN  NaN    NaN   NaN           11.0            11.0       NaN   
+ 1      0.006   NaN  NaN    NaN   NaN           11.0            11.0       NaN   
+ 2      0.006   NaN  NaN    NaN   NaN           11.0            11.0       NaN   
+ 3      0.006   NaN  NaN    NaN   NaN           11.0            11.0       NaN   
+ 4      0.006   NaN  NaN    NaN   NaN           11.0            11.0       NaN   
+ ...      ...   ...  ...    ...   ...            ...             ...       ...   
+ 39812  0.019   0.0    O  28.73  14.0           13.0            13.0       NaN   
+ 39813  0.019   0.0    O  32.03   NaN           12.0            12.0       NaN   
+ 39814  0.019   0.0    O  32.03   NaN           12.0            12.0       NaN   
+ 39815  0.017   0.0    O  48.77   NaN            1.0             8.0       NaN   
+ 39816  0.017   0.0    O  48.77   NaN            1.0             8.0       NaN   
+ 
+          DATE_OF_ENTRY_y  
+ 0      08/20/14 00:00:00  
+ 1      08/20/14 00:00:00  
+ 2      08/20/14 00:00:00  
+ 3      08/20/14 00:00:00  
+ 4      08/20/14 00:00:00  
+ ...                  ...  
+ 39812  04/22/22 00:00:00  
+ 39813  04/22/22 00:00:00  
+ 39814  04/22/22 00:00:00  
+ 39815  04/22/22 00:00:00  
+ 39816  04/22/22 00:00:00  
+ 
+ [39817 rows x 35 columns],
+ 'biota':                 KEY NUCLIDE  METHOD < VALUE_Bq/kg  VALUE_Bq/kg BASIS  ERROR%  \
+ 0      BVTIG2012041   cs134  VTIG01             <     0.010140     W     NaN   
+ 1      BVTIG2012041     k40  VTIG01                 135.300000     W    3.57   
+ 2      BVTIG2012041    co60  VTIG01             <     0.013980     W     NaN   
+ 3      BVTIG2012041   cs137  VTIG01                   4.338000     W    3.48   
+ 4      BVTIG2012040   cs134  VTIG01             <     0.009614     W     NaN   
+ ...             ...     ...     ...           ...          ...   ...     ...   
+ 15822  BSSSM2020016     k40  SSSM42           NaN    65.000000     D   10.20   
+ 15823  BSSSM2020016   cs137  SSSM42           NaN     4.500000     D    6.20   
+ 15824  BSSSM2020017     be7  SSSM42           NaN    94.000000     D    3.40   
+ 15825  BSSSM2020017     k40  SSSM42           NaN  1100.000000     D    1.60   
+ 15826  BSSSM2020017   cs137  SSSM42           NaN    13.000000     D    2.50   
+ 
+        NUMBER    DATE_OF_ENTRY_x  COUNTRY  ... BIOTATYPE  TISSUE     NO  \
+ 0         NaN  02/27/14 00:00:00      6.0  ...         F       5   16.0   
+ 1         NaN  02/27/14 00:00:00      6.0  ...         F       5   16.0   
+ 2         NaN  02/27/14 00:00:00      6.0  ...         F       5   16.0   
+ 3         NaN  02/27/14 00:00:00      6.0  ...         F       5   16.0   
+ 4         NaN  02/27/14 00:00:00      6.0  ...         F       5   17.0   
+ ...       ...                ...      ...  ...       ...     ...    ...   
+ 15822     NaN  04/22/22 00:00:00     77.0  ...         B      41  319.0   
+ 15823     NaN  04/22/22 00:00:00     77.0  ...         B      41  319.0   
+ 15824     NaN  04/22/22 00:00:00     77.0  ...         P      51    NaN   
+ 15825     NaN  04/22/22 00:00:00     77.0  ...         P      51    NaN   
+ 15826     NaN  04/22/22 00:00:00     77.0  ...         P      51    NaN   
+ 
+        LENGTH  WEIGHT     DW%  LOI%  MORS_SUBBASIN  HELCOM_SUBBASIN  \
+ 0        45.7   948.0  18.453  92.9            2.0               16   
+ 1        45.7   948.0  18.453  92.9            2.0               16   
+ 2        45.7   948.0  18.453  92.9            2.0               16   
+ 3        45.7   948.0  18.453  92.9            2.0               16   
+ 4        45.9   964.0  18.458  92.9            2.0               16   
+ ...       ...     ...     ...   ...            ...              ...   
+ 15822     NaN     NaN  41.000   0.0            1.0                8   
+ 15823     NaN     NaN  41.000   0.0            1.0                8   
+ 15824     NaN     NaN  21.000   0.0            1.0                8   
+ 15825     NaN     NaN  21.000   0.0            1.0                8   
+ 15826     NaN     NaN  21.000   0.0            1.0                8   
+ 
+          DATE_OF_ENTRY_y  
+ 0      02/27/14 00:00:00  
+ 1      02/27/14 00:00:00  
+ 2      02/27/14 00:00:00  
+ 3      02/27/14 00:00:00  
+ 4      02/27/14 00:00:00  
+ ...                  ...  
+ 15822  04/22/22 00:00:00  
+ 15823  04/22/22 00:00:00  
+ 15824  04/22/22 00:00:00  
+ 15825  04/22/22 00:00:00  
+ 15826  04/22/22 00:00:00  
+ 
+ [15827 rows x 33 columns]}
+
+
+
+
grp='sediment'
+check_data_sediment=tfm.dfs[grp][(tfm.dfs[grp]['DW%'] < 1) & (tfm.dfs[grp]['DW%'] > 0.001) ]
+check_data_sediment
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KEYNUCLIDEMETHOD< VALUE_Bq/kgVALUE_Bq/kgERROR%_kg< VALUE_Bq/m²VALUE_Bq/m²ERROR%_m²DATE_OF_ENTRY_x...LOWSLIAREASEDIOXICDW%LOI%MORS_SUBBASINHELCOM_SUBBASINSUM_LINKDATE_OF_ENTRY_y
30938SLVEA2010001cs137LVEA01NaN334.251.57NaN131.88641179.0NaN...2.00.01515.0O0.1150.914.014.0NaN11/11/11 00:00:00
30939SLVEA2010002cs137LVEA01NaN343.581.49NaN132.09241179.0NaN...4.00.01515.0A0.1590.814.014.0NaN11/11/11 00:00:00
30940SLVEA2010003cs137LVEA01NaN334.691.56NaN134.39041179.0NaN...6.00.01515.0A0.1890.814.014.0NaN11/11/11 00:00:00
30941SLVEA2010004cs137LVEA01NaN348.501.56NaN136.69941179.0NaN...8.00.01515.0A0.1940.814.014.0NaN11/11/11 00:00:00
30942SLVEA2010005cs137LVEA01NaN258.671.73NaN104.89441179.0NaN...10.00.01515.0A0.1950.814.014.0NaN11/11/11 00:00:00
30943SLVEA2010006cs137LVEA01NaN182.022.05NaN77.52341179.0NaN...12.00.01515.0A0.2210.814.014.0NaN11/11/11 00:00:00
30944SLVEA2010007cs137LVEA01NaN116.342.79NaN46.94641179.0NaN...14.00.01515.0A0.2380.814.014.0NaN11/11/11 00:00:00
30945SLVEA2010008cs137LVEA01NaN94.072.61NaN38.16241179.0NaN...16.00.01515.0A0.2340.814.014.0NaN11/11/11 00:00:00
30946SLVEA2010009cs137LVEA01NaN69.703.12NaN27.44441179.0NaN...18.00.01515.0A0.2420.814.014.0NaN11/11/11 00:00:00
30947SLVEA2010010cs137LVEA01NaN59.633.40NaN24.22041179.0NaN...20.00.01515.0A0.2570.714.014.0NaN11/11/11 00:00:00
30948SLVEA2010011cs137LVEA01<12.243.88<5.03541179.0NaN...22.00.01515.0A0.2640.714.014.0NaN11/11/11 00:00:00
30949SLVEA2010012cs137LVEA01<0.83NaN<0.33041179.0NaN...24.00.01515.0A0.2440.814.014.0NaN11/11/11 00:00:00
30950SLVEA2010013cs137LVEA01NaN331.611.40NaN125.56641179.0NaN...2.00.01515.0O0.1150.914.014.0NaN11/11/11 00:00:00
30951SLVEA2010014cs137LVEA01NaN352.061.33NaN144.51641179.0NaN...4.00.01515.0A0.1640.814.014.0NaN11/11/11 00:00:00
30952SLVEA2010015cs137LVEA01NaN367.111.36NaN139.43441179.0NaN...6.00.01515.0A0.1910.814.014.0NaN11/11/11 00:00:00
30953SLVEA2010016cs137LVEA01NaN328.971.42NaN124.34841179.0NaN...8.00.01515.0A0.1880.814.014.0NaN11/11/11 00:00:00
30954SLVEA2010017cs137LVEA01NaN356.301.37NaN135.44741179.0NaN...10.00.01515.0A0.1790.814.014.0NaN11/11/11 00:00:00
30955SLVEA2010018cs137LVEA01NaN314.751.42NaN118.76541179.0NaN...12.00.01515.0A0.1860.814.014.0NaN11/11/11 00:00:00
30956SLVEA2010019cs137LVEA01NaN261.641.52NaN104.58041179.0NaN...14.00.01515.0A0.1940.814.014.0NaN11/11/11 00:00:00
30957SLVEA2010020cs137LVEA01NaN181.001.76NaN74.05841179.0NaN...16.00.01515.0A0.2090.814.014.0NaN11/11/11 00:00:00
30958SLVEA2010021cs137LVEA01NaN143.652.02NaN57.68041179.0NaN...18.00.01515.0A0.2140.814.014.0NaN11/11/11 00:00:00
30959SLVEA2010022cs137LVEA01NaN109.362.15NaN42.15341179.0NaN...20.00.01515.0A0.2180.814.014.0NaN11/11/11 00:00:00
30960SLVEA2010023cs137LVEA01NaN94.121.39NaN35.87341179.0NaN...22.00.01515.0A0.2120.814.014.0NaN11/11/11 00:00:00
30961SLVEA2010024cs137LVEA01NaN96.631.35NaN38.86441179.0NaN...24.00.01515.0A0.2170.814.014.0NaN11/11/11 00:00:00
+ +

24 rows × 35 columns

+
+
+
+
+
grp='sediment'
+check_data_sediment=tfm.dfs[grp][(tfm.dfs[grp]['DW%'] == 0) ]
+check_data_sediment
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KEYNUCLIDEMETHOD< VALUE_Bq/kgVALUE_Bq/kgERROR%_kg< VALUE_Bq/m²VALUE_Bq/m²ERROR%_m²DATE_OF_ENTRY_x...LOWSLIAREASEDIOXICDW%LOI%MORS_SUBBASINHELCOM_SUBBASINSUM_LINKDATE_OF_ENTRY_y
9824SERPC1997001cs134NaNNaN3.8020.0NaN5.75NaNNaN...2.00.0085.0A0.00.011.011.0aNaN
9825SERPC1997001cs137NaNNaN389.004.0NaN589.00NaNNaN...2.00.0085.0A0.00.011.011.0aNaN
9826SERPC1997002cs134NaNNaN4.7813.0NaN12.00NaNNaN...4.00.0085.0A0.00.011.011.0aNaN
9827SERPC1997002cs137NaNNaN420.004.0NaN1060.00NaNNaN...4.00.0085.0A0.00.011.011.0aNaN
9828SERPC1997003cs134NaNNaN3.1217.0NaN12.00NaNNaN...6.00.0085.0A0.00.011.011.0aNaN
..................................................................
15257SKRIL1999062th2281NaN68.00NaNNaNNaNNaNNaN...15.00.0060.0O0.00.011.011.0aNaN
15258SKRIL1999063k401NaN1210.00NaNNaNNaNNaNNaN...21.50.0060.0O0.00.011.011.0aNaN
15259SKRIL1999063ra226KRIL01NaN56.50NaNNaNNaNNaNNaN...21.50.0060.0O0.00.011.011.0aNaN
15260SKRIL1999063ra228KRIL01NaN72.20NaNNaNNaNNaNNaN...21.50.0060.0O0.00.011.011.0aNaN
15261SKRIL1999063th2281NaN74.20NaNNaNNaNNaNNaN...21.50.0060.0O0.00.011.011.0aNaN
+ +

302 rows × 35 columns

+
+
+
+
+
grp='biota'
+check_data_sediment=tfm.dfs[grp][(tfm.dfs[grp]['DW%'] == 0) ]
+check_data_sediment
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KEYNUCLIDEMETHOD< VALUE_Bq/kgVALUE_Bq/kgBASISERROR%NUMBERDATE_OF_ENTRY_xCOUNTRY...BIOTATYPETISSUENOLENGTHWEIGHTDW%LOI%MORS_SUBBASINHELCOM_SUBBASINDATE_OF_ENTRY_y
5971BERPC1997002k40NaNNaN116.00W3.0NaNNaN91.0...F50.00.00.00.00.011.011NaN
5972BERPC1997002cs137NaNNaN12.60W4.0NaNNaN91.0...F50.00.00.00.00.011.011NaN
5973BERPC1997002cs134NaNNaN0.14W18.0NaNNaN91.0...F50.00.00.00.00.011.011NaN
5974BERPC1997001k40NaNNaN116.00W4.0NaNNaN91.0...F50.00.00.00.00.011.011NaN
5975BERPC1997001cs137NaNNaN12.00W4.0NaNNaN91.0...F50.00.00.00.00.011.011NaN
5976BERPC1997001cs134NaNNaN0.21W24.0NaNNaN91.0...F50.00.00.00.00.011.011NaN
+ +

6 rows × 33 columns

+
+
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/handlers/maris_legacy.html b/handlers/maris_legacy.html new file mode 100644 index 0000000..70612e7 --- /dev/null +++ b/handlers/maris_legacy.html @@ -0,0 +1,3945 @@ + + + + + + + + + + +MARIS Legacy – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+ +
+ +
+
+ Data pipeline (handler) to convert global MARIS db dump into NetCDF format. It allows to encode as NetCDF all legacy datasets in one batch. +
+
+ + +
+ + + + +
+ + + +
+ + + +
+

Packages import

+
+
+Exported source +
from tqdm import tqdm
+from pathlib import Path
+import fastcore.all as fc
+import pandas as pd
+import numpy as np
+
+from marisco.callbacks import (Callback, Transformer, SanitizeLonLatCB, EncodeTimeCB, ReshapeLongToWide)
+from marisco.metadata import (GlobAttrsFeeder, BboxCB, DepthRangeCB, TimeRangeCB, ZoteroCB, KeyValuePairCB)
+from marisco.configs import lut_path, cdl_cfg, cfg, nc_tpl_path, Enums, get_lut
+from marisco.serializers import NetCDFEncoder
+
+
+
+
+

Configuration and file paths

+
+
+Exported source +
fname_in = Path().home() / 'pro/data/maris/MARIS_exportSample_20240313.txt'
+dir_dest = '../../_data/output/dump'
+
+
+
+
+

Utils

+
+

source

+
+

DataLoader

+
+
 DataLoader (fname:str)
+
+

Load specific MARIS dataset through its ref_id.

+ + + + + + + + + + + + + + + +
TypeDetails
fnamestrPath to the MARIS global dump file
+
+
+Exported source +
class DataLoader:
+    LUT = {
+        'Sediment': 'sediment', 'Seawater': 'seawater',
+        'Suspended matter': 'suspended-matter', 'Biota': 'biota'}
+
+    def __init__(self, 
+                 fname: str # Path to the MARIS global dump file
+                 ):
+        "Load specific MARIS dataset through its ref_id."
+        self.fname = fname
+        self.df = None  # Lazy loading
+
+    def _load_data(self):
+        if self.df is None:
+            self.df = pd.read_csv(self.fname, sep='\t', encoding='ISO-8859-1')
+
+    def __call__(self, 
+                 ref_id: int # Reference ID of interest
+                 ) -> dict: # Dictionary of dataframes
+        self._load_data()
+        filtered_df = self.df[self.df.ref_id == ref_id]
+        return {
+            self.LUT[name]: grp
+            for name, grp in filtered_df.groupby('samptype')
+            if name in self.LUT
+        }
+
+
+
+

source

+
+
+

get_fname

+
+
 get_fname (dfs)
+
+
+
+Exported source +
def get_zotero_key(dfs):
+    return dfs[next(iter(dfs))][['zoterourl']].iloc[0].values[0].split('/')[-1]
+
+def get_fname(dfs):
+    id, name = dfs[next(iter(dfs))][['ref_id', 'displaytext']].iloc[0]
+    name = name.replace(',', '').replace('.', '').replace('-', ' ').split(' ')
+    return '-'.join(([str(id)] + name)) + '.nc'
+
+
+
+

source

+
+
+

get_zotero_key

+
+
 get_zotero_key (dfs)
+
+
+
+
+

Load data

+

Let’s get a quick look at the input MARIS dump:

+
+
df = pd.read_csv(fname_in, sep='\t', encoding='ISO-8859-1')
+
+print('# of unique refs: ', len(df.ref_id.unique()))
+print('columns: ', df.columns)
+df.head()
+
+
# of unique refs:  526
+columns:  Index(['ref_id', 'displaytext', 'samptype', 'nuclide_id', 'latitude',
+       'longitude', 'begperiod', 'endperiod', 'sampdepth', 'totdepth',
+       'uncertaint', 'unit_id', 'detection', 'area_id', 'species_id',
+       'biogroup_id', 'bodypar_id', 'sedtype_id', 'volume', 'salinity',
+       'temperatur', 'sampmet_id', 'prepmet_id', 'counmet_id', 'activity',
+       'zoterourl'],
+      dtype='object')
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ref_iddisplaytextsamptypenuclide_idlatitudelongitudebegperiodendperiodsampdepthtotdepth...bodypar_idsedtype_idvolumesalinitytemperatursampmet_idprepmet_idcounmet_idactivityzoterourl
0182Urban et al., 2015Biota33-35.140833117.6044442014-05-06 00:00:00NaN-1.0NaN...520NaNNaNNaN06200.387https://www.zotero.org/groups/2432820/maris/it...
1182Urban et al., 2015Biota47-35.140833117.6044442014-05-06 00:00:00NaN-1.0NaN...520NaNNaNNaN0651.44https://www.zotero.org/groups/2432820/maris/it...
2182Urban et al., 2015Biota31-16.466944123.5358332014-02-27 00:00:00NaN-1.0NaN...520NaNNaNNaN06200.042https://www.zotero.org/groups/2432820/maris/it...
3182Urban et al., 2015Biota33-16.466944123.5358332014-02-27 00:00:00NaN-1.0NaN...520NaNNaNNaN06200.075https://www.zotero.org/groups/2432820/maris/it...
4182Urban et al., 2015Biota47-16.466944123.5358332014-02-27 00:00:00NaN-1.0NaN...520NaNNaNNaN0650.069https://www.zotero.org/groups/2432820/maris/it...
+ +

5 rows × 26 columns

+
+
+
+

Let’s checkout if we retrieve the expected keys (sample types) and associated dataframes:

+
+
dataloader = DataLoader(fname_in)
+ref_id = 100 # Some other ref_id examples: OSPAR: 191, HELCOM: 100, 717 (only seawater)
+
+dfs = dataloader(ref_id=ref_id)
+print(f'keys: {dfs.keys()}')
+dfs['sediment'].head()
+
+
keys: dict_keys(['biota', 'seawater', 'sediment'])
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ref_iddisplaytextsamptypenuclide_idlatitudelongitudebegperiodendperiodsampdepthtotdepth...bodypar_idsedtype_idvolumesalinitytemperatursampmet_idprepmet_idcounmet_idactivityzoterourl
549778100HELCOM MORS, 2018Sediment1754.8383339.91989-06-14 00:00:00NaN-1.024.0...059NaNNaNNaN00026.6https://www.zotero.org/groups/2432820/maris/it...
549779100HELCOM MORS, 2018Sediment2454.8383339.91989-06-14 00:00:00NaN-1.024.0...059NaNNaNNaN000134.0https://www.zotero.org/groups/2432820/maris/it...
549780100HELCOM MORS, 2018Sediment2454.8383339.91989-06-14 00:00:00NaN-1.024.0...059NaNNaNNaN00018.6https://www.zotero.org/groups/2432820/maris/it...
549781100HELCOM MORS, 2018Sediment3154.8383339.91989-06-14 00:00:00NaN-1.024.0...059NaNNaNNaN00042.5https://www.zotero.org/groups/2432820/maris/it...
549782100HELCOM MORS, 2018Sediment3154.8383339.91989-06-14 00:00:00NaN-1.024.0...059NaNNaNNaN0005.9https://www.zotero.org/groups/2432820/maris/it...
+ +

5 rows × 26 columns

+
+
+
+
+
+

Data transformation pipeline

+
+

Normalize nuclide names

+

Remap nuclide_id to MARIS radionuclide standard names:

+
+

source

+
+
+

RemapRdnNameCB

+
+
 RemapRdnNameCB (fn_lut=<function <lambda>>)
+
+

Remap to MARIS radionuclide names.

+
+
+Exported source +
nuclide_id_to_name = lambda: get_lut(lut_path(), 'dbo_nuclide.xlsx', 
+                                     key='nc_name', value='nuclide_id',
+                                     reverse=True)
+
+
+
+
+Exported source +
class RemapRdnNameCB(Callback):
+    "Remap to MARIS radionuclide names."
+    def __init__(self, fn_lut=nuclide_id_to_name): fc.store_attr()
+    def __call__(self, tfm):
+        lut = self.fn_lut()
+        for k in tfm.dfs.keys():
+            tfm.dfs[k]['nuclide_id'] = tfm.dfs[k]['nuclide_id'].replace(lut)
+
+
+
+
dfs = dataloader(ref_id=ref_id)
+tfm = Transformer(dfs, cbs=[RemapRdnNameCB()])
+
+print(tfm()['sediment']['nuclide_id'].unique())
+
+
['ru106' 'sb125' 'cs134' 'cs137' 'k40' 'co60' 'ag110m' 'ra226' 'th232'
+ 'pb212' 'pb214' 'pu238' 'am241' 'pu239_240_tot' 'zr95' 'mn54' 'ac228'
+ 'u235' 'tl208' 'be7' 'bi214' 'ra223' 'ru103' 'sr90' 'eu155' 'ba140'
+ 'co58' 'ra224' 'po210' 'ra228' 'th228' 'ce144' 'cs134_137_tot' 'pb210'
+ 'pu239' 'cd109' 'bi212' 'pu238_240_tot' 'nb95' 'ir192' 'sb124' 'zn65'
+ 'th234' 'pu241']
+
+
+
+
+

Rename columns

+

Rename MARIS dump columns to MARIS netCDF standard names:

+
+
dfs['sediment'].columns
+
+
Index(['ref_id', 'displaytext', 'samptype', 'nuclide_id', 'latitude',
+       'longitude', 'begperiod', 'endperiod', 'sampdepth', 'totdepth',
+       'uncertaint', 'unit_id', 'detection', 'area_id', 'species_id',
+       'biogroup_id', 'bodypar_id', 'sedtype_id', 'volume', 'salinity',
+       'temperatur', 'sampmet_id', 'prepmet_id', 'counmet_id', 'activity',
+       'zoterourl'],
+      dtype='object')
+
+
+
+

source

+
+
+

renaming_rules

+
+
 renaming_rules ()
+
+

Rename MARIS dump columns to MARIS netCDF standard names.

+
+
+Exported source +
def renaming_rules():
+    "Rename MARIS dump columns to MARIS netCDF standard names."
+    vars = cdl_cfg()['vars']
+    return {
+        'latitude': vars['defaults']['lat']['name'],
+        'longitude': vars['defaults']['lon']['name'],
+        'begperiod': vars['defaults']['time']['name'],
+        'sampdepth': vars['defaults']['smp_depth']['name'],
+        'totdepth': vars['defaults']['tot_depth']['name'],
+        'uncertaint': vars['suffixes']['uncertainty']['name'],
+        'unit_id': vars['suffixes']['unit']['name'],
+        'detection': vars['suffixes']['detection_limit']['name'],
+        'area_id': vars['defaults']['area']['name'], 
+        'species_id': vars['bio']['species']['name'],
+        'biogroup_id': vars['bio']['bio_group']['name'],
+        'bodypar_id': vars['bio']['body_part']['name'],
+        'sedtype_id': vars['sed']['sed_type']['name'],
+        'volume': vars['suffixes']['volume']['name'],
+        'salinity': vars['suffixes']['salinity']['name'],
+        'temperatur': vars['suffixes']['temperature']['name'],
+        'sampmet_id': vars['suffixes']['sampling_method']['name'],
+        'prepmet_id': vars['suffixes']['preparation_method']['name'],
+        'counmet_id': vars['suffixes']['counting_method']['name'],
+        'activity': 'value',
+        'nuclide_id': 'nuclide'
+    }
+
+
+
+

source

+
+
+

RenameColumnCB

+
+
 RenameColumnCB (renaming_rules=<function renaming_rules>)
+
+

Renaming variables to MARIS standard names.

+
+
+Exported source +
class RenameColumnCB(Callback):
+    "Renaming variables to MARIS standard names."
+    def __init__(self, renaming_rules=renaming_rules): fc.store_attr()
+    def __call__(self, tfm):
+        lut = renaming_rules()
+        coi = lut.keys()
+        for k in tfm.dfs.keys():
+            tfm.dfs[k] = tfm.dfs[k].loc[:, coi]
+            tfm.dfs[k].rename(columns=lut, inplace=True)
+
+
+
+
dfs = dataloader(ref_id=ref_id)
+tfm = Transformer(dfs, cbs=[
+    RemapRdnNameCB(),
+    RenameColumnCB()
+    ])
+
+print(tfm()['sediment'])
+
+
               lat        lon                 time smp_depth tot_depth  \
+549778   54.838333        9.9  1989-06-14 00:00:00      -1.0      24.0   
+549779   54.838333        9.9  1989-06-14 00:00:00      -1.0      24.0   
+549780   54.838333        9.9  1989-06-14 00:00:00      -1.0      24.0   
+549781   54.838333        9.9  1989-06-14 00:00:00      -1.0      24.0   
+549782   54.838333        9.9  1989-06-14 00:00:00      -1.0      24.0   
+...            ...        ...                  ...       ...       ...   
+1532415  57.619722  23.621389  2005-12-02 00:00:00      -1.0      55.0   
+1532416  57.619722  23.621389  2005-12-02 00:00:00      -1.0      55.0   
+1532417  57.619722  23.621389  2005-12-02 00:00:00      -1.0      55.0   
+1532418  57.619722  23.621389  2005-12-02 00:00:00      -1.0      55.0   
+1532419  57.619722  23.621389  2005-12-02 00:00:00      -1.0      55.0   
+
+             _unc _unit _dl  area species  ... body_part sed_type _vol _sal  \
+549778       3.99     4   =  2374       0  ...         0       59  NaN  NaN   
+549779        NaN     2   =  2374       0  ...         0       59  NaN  NaN   
+549780      1.674     4   =  2374       0  ...         0       59  NaN  NaN   
+549781        NaN     2   =  2374       0  ...         0       59  NaN  NaN   
+549782      1.829     4   =  2374       0  ...         0       59  NaN  NaN   
+...           ...   ...  ..   ...     ...  ...       ...      ...  ...  ...   
+1532415   86.2836     4   =  2409       0  ...         0       58  NaN  NaN   
+1532416       NaN     2   =  2409       0  ...         0       58  NaN  NaN   
+1532417  24.45552     4   =  2409       0  ...         0       58  NaN  NaN   
+1532418       NaN     2   =  2409       0  ...         0       58  NaN  NaN   
+1532419  123.2568     4   =  2409       0  ...         0       58  NaN  NaN   
+
+        _temp _sampmet _prepmet _counmet    value nuclide  
+549778    NaN        0        0        0     26.6   ru106  
+549779    NaN        0        0        0    134.0   sb125  
+549780    NaN        0        0        0     18.6   sb125  
+549781    NaN        0        0        0     42.5   cs134  
+549782    NaN        0        0        0      5.9   cs134  
+...       ...      ...      ...      ...      ...     ...  
+1532415   NaN        0        0        0   1106.2     k40  
+1532416   NaN        0        0        0  991.023   cs137  
+1532417   NaN        0        0        0    550.8   cs137  
+1532418   NaN        0        0        0  2461.36     k40  
+1532419   NaN        0        0        0   1368.0     k40  
+
+[123196 rows x 21 columns]
+
+
+
+
+

Drop NaN only columns

+
+

source

+
+
+

DropNAColumnsCB

+
+
 DropNAColumnsCB (na_value=0)
+
+

Drop variable containing only NaN or ‘Not available’ (id=0 in MARIS lookup tables).

+
+
+Exported source +
class DropNAColumnsCB(Callback):
+    "Drop variable containing only NaN or 'Not available' (id=0 in MARIS lookup tables)."
+    def __init__(self, na_value=0): fc.store_attr()
+    def isMarisNA(self, col): 
+        return len(col.unique()) == 1 and col.iloc[0] == self.na_value
+    
+    def dropMarisNA(self, df):
+        na_cols = [col for col in df.columns if self.isMarisNA(df[col])]
+        return df.drop(labels=na_cols, axis=1)
+        
+    def __call__(self, tfm):
+        for k in tfm.dfs.keys():
+            tfm.dfs[k] = tfm.dfs[k].dropna(axis=1, how='all')
+            tfm.dfs[k] = self.dropMarisNA(tfm.dfs[k])
+
+
+
+
dfs = dataloader(ref_id=ref_id)
+tfm = Transformer(dfs, cbs=[
+    RemapRdnNameCB(),
+    RenameColumnCB(),
+    DropNAColumnsCB()
+    ])
+
+print(tfm()['sediment'])
+
+
               lat        lon                 time smp_depth tot_depth  \
+549778   54.838333        9.9  1989-06-14 00:00:00      -1.0      24.0   
+549779   54.838333        9.9  1989-06-14 00:00:00      -1.0      24.0   
+549780   54.838333        9.9  1989-06-14 00:00:00      -1.0      24.0   
+549781   54.838333        9.9  1989-06-14 00:00:00      -1.0      24.0   
+549782   54.838333        9.9  1989-06-14 00:00:00      -1.0      24.0   
+...            ...        ...                  ...       ...       ...   
+1532415  57.619722  23.621389  2005-12-02 00:00:00      -1.0      55.0   
+1532416  57.619722  23.621389  2005-12-02 00:00:00      -1.0      55.0   
+1532417  57.619722  23.621389  2005-12-02 00:00:00      -1.0      55.0   
+1532418  57.619722  23.621389  2005-12-02 00:00:00      -1.0      55.0   
+1532419  57.619722  23.621389  2005-12-02 00:00:00      -1.0      55.0   
+
+             _unc _unit _dl  area sed_type _sampmet _prepmet    value nuclide  
+549778       3.99     4   =  2374       59        0        0     26.6   ru106  
+549779        NaN     2   =  2374       59        0        0    134.0   sb125  
+549780      1.674     4   =  2374       59        0        0     18.6   sb125  
+549781        NaN     2   =  2374       59        0        0     42.5   cs134  
+549782      1.829     4   =  2374       59        0        0      5.9   cs134  
+...           ...   ...  ..   ...      ...      ...      ...      ...     ...  
+1532415   86.2836     4   =  2409       58        0        0   1106.2     k40  
+1532416       NaN     2   =  2409       58        0        0  991.023   cs137  
+1532417  24.45552     4   =  2409       58        0        0    550.8   cs137  
+1532418       NaN     2   =  2409       58        0        0  2461.36     k40  
+1532419  123.2568     4   =  2409       58        0        0   1368.0     k40  
+
+[123196 rows x 14 columns]
+
+
+
+
+

Remap detection limit values

+
+
+Exported source +
dl_name_to_id = lambda: get_lut(lut_path(), 'dbo_detectlimit.xlsx', key='name', value='id')
+
+
+
+
dl_name_to_id()
+
+
{'Not applicable': -1, 'Not Available': 0, '=': 1, '<': 2, 'ND': 3, 'DE': 4}
+
+
+
+

source

+
+
+

SanitizeDetectionLimitCB

+
+
 SanitizeDetectionLimitCB (fn_lut=<function <lambda>>)
+
+

Assign Detection Limit name to its id based on MARIS nomenclature.

+
+
+Exported source +
class SanitizeDetectionLimitCB(Callback):
+    "Assign Detection Limit name to its id based on MARIS nomenclature."
+    def __init__(self,
+                 fn_lut=dl_name_to_id):
+        fc.store_attr()
+        self.var_name = cdl_cfg()['vars']['suffixes']['detection_limit']['name']
+
+    def __call__(self, tfm):
+        lut = self.fn_lut()
+        for k in tfm.dfs.keys():
+            tfm.dfs[k][self.var_name] = tfm.dfs[k][self.var_name].replace(lut)
+
+
+
+
dfs = dataloader(ref_id=ref_id)
+tfm = Transformer(dfs, cbs=[
+    RemapRdnNameCB(),
+    RenameColumnCB(),
+    DropNAColumnsCB(),
+    SanitizeDetectionLimitCB()
+    ])
+
+print(tfm()['sediment']['_dl'])
+
+
549778     1
+549779     1
+549780     1
+549781     1
+549782     1
+          ..
+1532415    1
+1532416    1
+1532417    1
+1532418    1
+1532419    1
+Name: _dl, Length: 123196, dtype: int64
+
+
+
+
+

Parse and encode time

+

We remind that in netCDF format time need to be encoded as integer representing the number of seconds since a time of reference. In our case we chose 1970-01-01 00:00:00.0 as defined in configs.ipynb.

+
+

source

+
+
+

ParseTimeCB

+
+
 ParseTimeCB ()
+
+

Base class for callbacks.

+
+
+Exported source +
class ParseTimeCB(Callback):
+    def __call__(self, tfm):
+        for k in tfm.dfs.keys():
+            tfm.dfs[k]['time'] = pd.to_datetime(tfm.dfs[k].time, format='ISO8601')
+
+
+
+
dfs = dataloader(ref_id=ref_id)
+tfm = Transformer(dfs, cbs=[
+    RemapRdnNameCB(),
+    RenameColumnCB(),
+    DropNAColumnsCB(),
+    SanitizeDetectionLimitCB(),
+    ParseTimeCB(),
+    EncodeTimeCB(cfg())
+    ])
+
+print(tfm()['sediment'])
+
+
               lat        lon        time smp_depth tot_depth      _unc _unit  \
+549778   54.838333        9.9   613785600      -1.0      24.0      3.99     4   
+549779   54.838333        9.9   613785600      -1.0      24.0       NaN     2   
+549780   54.838333        9.9   613785600      -1.0      24.0     1.674     4   
+549781   54.838333        9.9   613785600      -1.0      24.0       NaN     2   
+549782   54.838333        9.9   613785600      -1.0      24.0     1.829     4   
+...            ...        ...         ...       ...       ...       ...   ...   
+1532415  57.619722  23.621389  1133481600      -1.0      55.0   86.2836     4   
+1532416  57.619722  23.621389  1133481600      -1.0      55.0       NaN     2   
+1532417  57.619722  23.621389  1133481600      -1.0      55.0  24.45552     4   
+1532418  57.619722  23.621389  1133481600      -1.0      55.0       NaN     2   
+1532419  57.619722  23.621389  1133481600      -1.0      55.0  123.2568     4   
+
+         _dl  area sed_type _sampmet _prepmet    value nuclide  
+549778     1  2374       59        0        0     26.6   ru106  
+549779     1  2374       59        0        0    134.0   sb125  
+549780     1  2374       59        0        0     18.6   sb125  
+549781     1  2374       59        0        0     42.5   cs134  
+549782     1  2374       59        0        0      5.9   cs134  
+...      ...   ...      ...      ...      ...      ...     ...  
+1532415    1  2409       58        0        0   1106.2     k40  
+1532416    1  2409       58        0        0  991.023   cs137  
+1532417    1  2409       58        0        0    550.8   cs137  
+1532418    1  2409       58        0        0  2461.36     k40  
+1532419    1  2409       58        0        0   1368.0     k40  
+
+[123196 rows x 14 columns]
+
+
+
+
+

Reshape: long to wide

+
+
dfs = dataloader(ref_id=ref_id)
+tfm = Transformer(dfs, cbs=[
+    RemapRdnNameCB(),
+    RenameColumnCB(),
+    DropNAColumnsCB(),
+    SanitizeDetectionLimitCB(),
+    ParseTimeCB(),
+    EncodeTimeCB(cfg()),
+    ReshapeLongToWide()
+    ])
+
+print(tfm()['sediment'])
+
+
                 lon        time  area        lat  smp_depth  tot_depth  \
+org_index                                                                 
+549834      9.633333   544838400  2374  54.850000       -1.0       16.0   
+549835      9.633333   544838400  2374  54.850000       -1.0       16.0   
+549836      9.633333   544838400  2374  54.850000       -1.0       16.0   
+549837      9.633333   544838400  2374  54.850000       -1.0       16.0   
+549838      9.633333   544838400  2374  54.850000       -1.0       16.0   
+...              ...         ...   ...        ...        ...        ...   
+1518808    29.833333  1128211200  2407  59.983333       -1.0        0.0   
+1518809    29.833333  1128211200  2407  59.983333       -1.0        0.0   
+1518810    29.833333  1128211200  2407  59.983333       -1.0        0.0   
+1528756    29.833333  1128211200  2407  59.983333       -1.0        0.0   
+1528757    29.833333  1128211200  2407  59.983333       -1.0        0.0   
+
+           sed_type  ac228_dl  ag110m_dl  am241_dl  ...  sb124  sb125  sr90  \
+org_index                                           ...                       
+549834           58       NaN        NaN       NaN  ...    NaN    NaN   NaN   
+549835           58       NaN        NaN       NaN  ...    NaN    NaN   NaN   
+549836           58       NaN        NaN       NaN  ...    NaN    NaN   NaN   
+549837           58       NaN        NaN       NaN  ...    NaN    NaN   NaN   
+549838           58       NaN        NaN       NaN  ...    NaN    NaN   NaN   
+...             ...       ...        ...       ...  ...    ...    ...   ...   
+1518808           2       NaN        NaN       NaN  ...    NaN    NaN   NaN   
+1518809           2       NaN        NaN       NaN  ...    NaN    NaN   NaN   
+1518810           2       NaN        NaN       NaN  ...    NaN    NaN   NaN   
+1528756           2       NaN        NaN       NaN  ...    NaN    NaN   NaN   
+1528757           2       NaN        NaN       NaN  ...    NaN    NaN   NaN   
+
+           th228  th232  th234  tl208  u235  zn65  zr95  
+org_index                                                
+549834       NaN    NaN    NaN    NaN   NaN   NaN   NaN  
+549835       NaN    NaN    NaN    NaN   NaN   NaN   NaN  
+549836       NaN    NaN    NaN    NaN   NaN   NaN   NaN  
+549837       NaN    NaN    NaN    NaN   NaN   NaN   NaN  
+549838       NaN    NaN    NaN    NaN   NaN   NaN   NaN  
+...          ...    ...    ...    ...   ...   ...   ...  
+1518808      NaN    NaN    NaN    NaN   NaN   NaN   NaN  
+1518809      NaN    NaN    NaN    NaN   NaN   NaN   NaN  
+1518810      NaN    NaN    NaN    NaN   NaN   NaN   NaN  
+1528756      NaN    NaN    NaN    NaN   NaN   NaN   NaN  
+1528757      NaN    NaN    NaN    NaN   NaN   NaN   NaN  
+
+[123196 rows x 270 columns]
+
+
+
+
+

Sanitize coordinates

+
+
dfs = dataloader(ref_id=ref_id)
+tfm = Transformer(dfs, cbs=[
+    RemapRdnNameCB(),
+    RenameColumnCB(),
+    DropNAColumnsCB(),
+    SanitizeDetectionLimitCB(),
+    ParseTimeCB(),
+    EncodeTimeCB(cfg()),
+    ReshapeLongToWide(),
+    SanitizeLonLatCB()
+    ])
+
+tfm()['sediment']
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
lontimearealatsmp_depthtot_depthsed_typeac228_dlag110m_dlam241_dl...sb124sb125sr90th228th232th234tl208u235zn65zr95
org_index
5498349.633333544838400237454.850000-1.016.058NaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
5498359.633333544838400237454.850000-1.016.058NaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
5498369.633333544838400237454.850000-1.016.058NaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
5498379.633333544838400237454.850000-1.016.058NaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
5498389.633333544838400237454.850000-1.016.058NaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
..................................................................
151880829.8333331128211200240759.983333-1.00.02NaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
151880929.8333331128211200240759.983333-1.00.02NaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
151881029.8333331128211200240759.983333-1.00.02NaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
152875629.8333331128211200240759.983333-1.00.02NaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
152875729.8333331128211200240759.983333-1.00.02NaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
+ +

123196 rows × 270 columns

+
+
+
+
+
+
+

Encode to NetCDF

+
+
dfs = dataloader(ref_id=ref_id)
+tfm = Transformer(dfs, cbs=[
+    RemapRdnNameCB(),
+    RenameColumnCB(),
+    DropNAColumnsCB(),
+    SanitizeDetectionLimitCB(),
+    ParseTimeCB(),
+    EncodeTimeCB(cfg()),
+    ReshapeLongToWide(),
+    SanitizeLonLatCB()
+    ])
+
+dfs_tfm = tfm()
+tfm.logs
+
+
['Remap to MARIS radionuclide names.',
+ 'Renaming variables to MARIS standard names.',
+ "Drop variable containing only NaN or 'Not available' (id=0 in MARIS lookup tables).",
+ 'Assign Detection Limit name to its id based on MARIS nomenclature.',
+ 'Encode time as `int` representing seconds since xxx',
+ 'Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator.']
+
+
+
+

source

+
+

get_attrs

+
+
 get_attrs (tfm, zotero_key, kw=['oceanography', 'Earth Science > Oceans >
+            Ocean Chemistry> Radionuclides', 'Earth Science > Human
+            Dimensions > Environmental Impacts > Nuclear Radiation
+            Exposure', 'Earth Science > Oceans > Ocean Chemistry > Ocean
+            Tracers, Earth Science > Oceans > Marine Sediments', 'Earth
+            Science > Oceans > Ocean Chemistry, Earth Science > Oceans >
+            Sea Ice > Isotopes', 'Earth Science > Oceans > Water Quality >
+            Ocean Contaminants', 'Earth Science > Biological
+            Classification > Animals/Vertebrates > Fish', 'Earth Science >
+            Biosphere > Ecosystems > Marine Ecosystems', 'Earth Science >
+            Biological Classification > Animals/Invertebrates > Mollusks',
+            'Earth Science > Biological Classification >
+            Animals/Invertebrates > Arthropods > Crustaceans', 'Earth
+            Science > Biological Classification > Plants > Macroalgae
+            (Seaweeds)'])
+
+

Retrieve global attributes from MARIS dump.

+
+
+Exported source +
kw = ['oceanography', 'Earth Science > Oceans > Ocean Chemistry> Radionuclides',
+      'Earth Science > Human Dimensions > Environmental Impacts > Nuclear Radiation Exposure',
+      'Earth Science > Oceans > Ocean Chemistry > Ocean Tracers, Earth Science > Oceans > Marine Sediments',
+      'Earth Science > Oceans > Ocean Chemistry, Earth Science > Oceans > Sea Ice > Isotopes',
+      'Earth Science > Oceans > Water Quality > Ocean Contaminants',
+      'Earth Science > Biological Classification > Animals/Vertebrates > Fish',
+      'Earth Science > Biosphere > Ecosystems > Marine Ecosystems',
+      'Earth Science > Biological Classification > Animals/Invertebrates > Mollusks',
+      'Earth Science > Biological Classification > Animals/Invertebrates > Arthropods > Crustaceans',
+      'Earth Science > Biological Classification > Plants > Macroalgae (Seaweeds)']
+
+
+
+
+Exported source +
def get_attrs(tfm, zotero_key, kw=kw):
+    "Retrieve global attributes from MARIS dump."
+    return GlobAttrsFeeder(tfm.dfs, cbs=[
+        BboxCB(),
+        DepthRangeCB(),
+        TimeRangeCB(cfg()),
+        ZoteroCB(zotero_key, cfg=cfg()),
+        KeyValuePairCB('keywords', ', '.join(kw)),
+        KeyValuePairCB('publisher_postprocess_logs', ', '.join(tfm.logs))
+        ])()
+
+
+
+
get_attrs(tfm, zotero_key='3W354SQG', kw=kw)
+
+
{'geospatial_lat_min': '30.435833333333335',
+ 'geospatial_lat_max': '65.75',
+ 'geospatial_lon_min': '9.633333333333333',
+ 'geospatial_lon_max': '53.5',
+ 'geospatial_bounds': 'POLYGON ((9.633333333333333 53.5, 30.435833333333335 53.5, 30.435833333333335 65.75, 9.633333333333333 65.75, 9.633333333333333 53.5))',
+ 'time_coverage_start': '1984-01-10T00:00:00',
+ 'time_coverage_end': '2018-12-14T00:00:00',
+ 'title': 'Radioactivity Monitoring of the Irish Marine Environment 1991 and 1992',
+ 'summary': '',
+ 'creator_name': '[{"creatorType": "author", "firstName": "A.", "lastName": "McGarry"}, {"creatorType": "author", "firstName": "S.", "lastName": "Lyons"}, {"creatorType": "author", "firstName": "C.", "lastName": "McEnri"}, {"creatorType": "author", "firstName": "T.", "lastName": "Ryan"}, {"creatorType": "author", "firstName": "M.", "lastName": "O\'Colmain"}, {"creatorType": "author", "firstName": "J.D.", "lastName": "Cunningham"}]',
+ 'keywords': 'oceanography, Earth Science > Oceans > Ocean Chemistry> Radionuclides, Earth Science > Human Dimensions > Environmental Impacts > Nuclear Radiation Exposure, Earth Science > Oceans > Ocean Chemistry > Ocean Tracers, Earth Science > Oceans > Marine Sediments, Earth Science > Oceans > Ocean Chemistry, Earth Science > Oceans > Sea Ice > Isotopes, Earth Science > Oceans > Water Quality > Ocean Contaminants, Earth Science > Biological Classification > Animals/Vertebrates > Fish, Earth Science > Biosphere > Ecosystems > Marine Ecosystems, Earth Science > Biological Classification > Animals/Invertebrates > Mollusks, Earth Science > Biological Classification > Animals/Invertebrates > Arthropods > Crustaceans, Earth Science > Biological Classification > Plants > Macroalgae (Seaweeds)',
+ 'publisher_postprocess_logs': "Remap to MARIS radionuclide names., Renaming variables to MARIS standard names., Drop variable containing only NaN or 'Not available' (id=0 in MARIS lookup tables)., Assign Detection Limit name to its id based on MARIS nomenclature., Encode time as `int` representing seconds since xxx, Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator."}
+
+
+
+

source

+
+
+

enums_xtra

+
+
 enums_xtra (tfm, vars)
+
+

Retrieve a subset of the lengthy enum as species_t for instance

+
+
+Exported source +
def enums_xtra(tfm, vars):
+    "Retrieve a subset of the lengthy enum as `species_t` for instance"
+    enums = Enums(lut_src_dir=lut_path(), cdl_enums=cdl_cfg()['enums'])
+    xtras = {}
+    for var in vars:
+        unique_vals = tfm.unique(var)
+        if unique_vals.any():
+            xtras[f'{var}_t'] = enums.filter(f'{var}_t', unique_vals)
+    return xtras
+
+
+
+

source

+
+
+

encode

+
+
 encode (fname_in, fname_out, nc_tpl_path, **kwargs)
+
+
+
+Exported source +
def encode(fname_in, fname_out, nc_tpl_path, **kwargs):
+    dataloader = DataLoader(fname_in)
+    ref_ids = kwargs.get('ref_ids', df.ref_id.unique())
+    print('Encoding ...')
+    for ref_id in tqdm(ref_ids, leave=False):
+        dfs = dataloader(ref_id=ref_id)
+        print(get_fname(dfs))
+        tfm = Transformer(dfs, cbs=[
+            RemapRdnNameCB(),
+            RenameColumnCB(),
+            DropNAColumnsCB(),
+            SanitizeDetectionLimitCB(),
+            ParseTimeCB(),
+            EncodeTimeCB(cfg()),
+            ReshapeLongToWide(),
+            SanitizeLonLatCB(verbose=True)
+            ])
+       
+        tfm()
+        encoder = NetCDFEncoder(tfm.dfs, 
+                                src_fname=nc_tpl_path,
+                                dest_fname=Path(fname_out) / get_fname(dfs), 
+                                global_attrs=get_attrs(tfm, zotero_key=get_zotero_key(dfs), kw=kw),
+                                verbose=kwargs.get('verbose', False),
+                                enums_xtra=enums_xtra(tfm, vars=['species', 'body_part'])
+                                )
+        encoder.encode()
+
+
+
+
+

Single dataset

+
+
tfm = Transformer(dfs, cbs=[
+            RemapRdnNameCB(),
+            RenameColumnCB(),
+            DropNAColumnsCB(),
+            SanitizeDetectionLimitCB(),
+            ParseTimeCB(),
+            EncodeTimeCB(cfg()),
+            ReshapeLongToWide(),
+            SanitizeLonLatCB(verbose=True)
+            ])
+
+dfs_test = tfm()
+
+
+
ref_id = 100
+encode(fname_in, dir_dest, nc_tpl_path(), verbose=True, ref_ids=[ref_id])
+
+
Encoding ...
+
+
+
  0%|          | 0/1 [00:00<?, ?it/s]
+
+
+
100-HELCOM-MORS-2018.nc
+--------------------------------------------------------------------------------
+Group: biota, Variable: lon
+--------------------------------------------------------------------------------
+Group: biota, Variable: lat
+--------------------------------------------------------------------------------
+Group: biota, Variable: smp_depth
+--------------------------------------------------------------------------------
+Group: biota, Variable: time
+--------------------------------------------------------------------------------
+Group: biota, Variable: area
+--------------------------------------------------------------------------------
+Group: biota, Variable: bio_group
+--------------------------------------------------------------------------------
+Group: biota, Variable: species
+--------------------------------------------------------------------------------
+Group: biota, Variable: body_part
+--------------------------------------------------------------------------------
+Group: biota, Variable: be7
+--------------------------------------------------------------------------------
+Group: biota, Variable: be7_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: be7_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: be7_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: be7_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: be7_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: k40
+--------------------------------------------------------------------------------
+Group: biota, Variable: k40_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: k40_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: k40_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: k40_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: k40_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: mn54
+--------------------------------------------------------------------------------
+Group: biota, Variable: mn54_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: mn54_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: mn54_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: mn54_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: mn54_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: co57
+--------------------------------------------------------------------------------
+Group: biota, Variable: co57_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: co57_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: co57_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: co57_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: co57_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: co58
+--------------------------------------------------------------------------------
+Group: biota, Variable: co58_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: co58_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: co58_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: co58_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: co58_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: co60
+--------------------------------------------------------------------------------
+Group: biota, Variable: co60_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: co60_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: co60_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: co60_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: co60_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: zn65
+--------------------------------------------------------------------------------
+Group: biota, Variable: zn65_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: zn65_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: zn65_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: zn65_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: zn65_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: sr89
+--------------------------------------------------------------------------------
+Group: biota, Variable: sr89_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: sr89_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: sr89_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: sr89_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: sr89_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: sr90
+--------------------------------------------------------------------------------
+Group: biota, Variable: sr90_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: sr90_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: sr90_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: sr90_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: sr90_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: zr95
+--------------------------------------------------------------------------------
+Group: biota, Variable: zr95_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: zr95_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: zr95_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: zr95_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: zr95_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: nb95
+--------------------------------------------------------------------------------
+Group: biota, Variable: nb95_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: nb95_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: nb95_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: nb95_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: nb95_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: tc99
+--------------------------------------------------------------------------------
+Group: biota, Variable: tc99_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: tc99_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: tc99_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: tc99_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: tc99_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: ru103
+--------------------------------------------------------------------------------
+Group: biota, Variable: ru103_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: ru103_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: ru103_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ru103_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ru103_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: ru106
+--------------------------------------------------------------------------------
+Group: biota, Variable: ru106_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: ru106_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: ru106_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ru106_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ru106_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: ag108m
+--------------------------------------------------------------------------------
+Group: biota, Variable: ag108m_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: ag108m_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: ag108m_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ag108m_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ag108m_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: ag110m
+--------------------------------------------------------------------------------
+Group: biota, Variable: ag110m_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: ag110m_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: ag110m_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ag110m_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ag110m_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: sb124
+--------------------------------------------------------------------------------
+Group: biota, Variable: sb124_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: sb124_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: sb124_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: sb124_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: sb124_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: sb125
+--------------------------------------------------------------------------------
+Group: biota, Variable: sb125_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: sb125_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: sb125_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: sb125_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: sb125_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: te129m
+--------------------------------------------------------------------------------
+Group: biota, Variable: te129m_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: te129m_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: te129m_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: te129m_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: i131
+--------------------------------------------------------------------------------
+Group: biota, Variable: i131_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: i131_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: i131_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: i131_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs134
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs134_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs134_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs134_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs134_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs134_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs137
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs137_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs137_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs137_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs137_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs137_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: ba140
+--------------------------------------------------------------------------------
+Group: biota, Variable: ba140_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: ba140_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ba140_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ba140_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: la140
+--------------------------------------------------------------------------------
+Group: biota, Variable: la140_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: la140_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: la140_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: la140_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: ce141
+--------------------------------------------------------------------------------
+Group: biota, Variable: ce141_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: ce141_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: ce141_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ce141_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ce141_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: ce144
+--------------------------------------------------------------------------------
+Group: biota, Variable: ce144_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: ce144_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: ce144_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ce144_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ce144_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: eu155
+--------------------------------------------------------------------------------
+Group: biota, Variable: eu155_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: eu155_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: eu155_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: eu155_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: eu155_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb210
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb210_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb210_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb210_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb210_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb210_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb212
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb212_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb212_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb212_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb212_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb212_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb214
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb214_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb214_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb214_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb214_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: pb214_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: bi214
+--------------------------------------------------------------------------------
+Group: biota, Variable: bi214_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: bi214_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: bi214_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: bi214_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: bi214_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: po210
+--------------------------------------------------------------------------------
+Group: biota, Variable: po210_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: po210_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: po210_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: po210_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: po210_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra223
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra223_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra223_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra223_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra223_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra223_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra224
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra224_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra224_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra224_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra224_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra224_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra226
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra226_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra226_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra226_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra226_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra226_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra228
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra228_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra228_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra228_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra228_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ra228_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: ac228
+--------------------------------------------------------------------------------
+Group: biota, Variable: ac228_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: ac228_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: ac228_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ac228_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: ac228_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: th228
+--------------------------------------------------------------------------------
+Group: biota, Variable: th228_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: th228_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: th228_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: th228_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: th228_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: th232
+--------------------------------------------------------------------------------
+Group: biota, Variable: th232_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: th232_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: th232_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: th232_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: th232_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: u235
+--------------------------------------------------------------------------------
+Group: biota, Variable: u235_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: u235_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: u235_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: u235_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: u235_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: pu238
+--------------------------------------------------------------------------------
+Group: biota, Variable: pu238_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: pu238_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: pu238_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: pu238_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: pu238_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: am241
+--------------------------------------------------------------------------------
+Group: biota, Variable: am241_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: am241_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: am241_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: am241_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: am241_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs134_137_tot
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs134_137_tot_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs134_137_tot_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs134_137_tot_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs134_137_tot_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: cs134_137_tot_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: pu239_240_tot
+--------------------------------------------------------------------------------
+Group: biota, Variable: pu239_240_tot_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: pu239_240_tot_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: pu239_240_tot_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: pu239_240_tot_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: pu239_240_tot_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: eu152
+--------------------------------------------------------------------------------
+Group: biota, Variable: eu152_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: eu152_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: eu152_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: eu152_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: eu152_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: fe59
+--------------------------------------------------------------------------------
+Group: biota, Variable: fe59_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: fe59_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: fe59_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: fe59_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: fe59_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: gd153
+--------------------------------------------------------------------------------
+Group: biota, Variable: gd153_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: gd153_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: gd153_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: gd153_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: gd153_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: rb86
+--------------------------------------------------------------------------------
+Group: biota, Variable: rb86_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: rb86_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: rb86_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: rb86_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: rb86_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: sc46
+--------------------------------------------------------------------------------
+Group: biota, Variable: sc46_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: sc46_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: sc46_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: sc46_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: sc46_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: sn113
+--------------------------------------------------------------------------------
+Group: biota, Variable: sn113_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: sn113_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: sn113_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: sn113_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: sn113_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: sn117m
+--------------------------------------------------------------------------------
+Group: biota, Variable: sn117m_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: sn117m_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: sn117m_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: sn117m_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: sn117m_unit
+--------------------------------------------------------------------------------
+Group: biota, Variable: tl208
+--------------------------------------------------------------------------------
+Group: biota, Variable: tl208_unc
+--------------------------------------------------------------------------------
+Group: biota, Variable: tl208_dl
+--------------------------------------------------------------------------------
+Group: biota, Variable: tl208_counmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: tl208_prepmet
+--------------------------------------------------------------------------------
+Group: biota, Variable: tl208_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: lon
+--------------------------------------------------------------------------------
+Group: seawater, Variable: lat
+--------------------------------------------------------------------------------
+Group: seawater, Variable: smp_depth
+--------------------------------------------------------------------------------
+Group: seawater, Variable: tot_depth
+--------------------------------------------------------------------------------
+Group: seawater, Variable: time
+--------------------------------------------------------------------------------
+Group: seawater, Variable: area
+--------------------------------------------------------------------------------
+Group: seawater, Variable: h3
+--------------------------------------------------------------------------------
+Group: seawater, Variable: h3_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: h3_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: h3_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: h3_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: h3_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: h3_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: h3_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: h3_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: k40
+--------------------------------------------------------------------------------
+Group: seawater, Variable: k40_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: k40_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: k40_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: k40_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: k40_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: k40_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: k40_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: k40_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: mn54
+--------------------------------------------------------------------------------
+Group: seawater, Variable: mn54_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: mn54_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: mn54_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: mn54_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: mn54_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: mn54_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: mn54_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: co60
+--------------------------------------------------------------------------------
+Group: seawater, Variable: co60_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: co60_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: co60_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: co60_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: co60_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: co60_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: co60_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: co60_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr89
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr89_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr89_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr89_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr89_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr89_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr89_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr89_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr90
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr90_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr90_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr90_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr90_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr90_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr90_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr90_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sr90_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: zr95
+--------------------------------------------------------------------------------
+Group: seawater, Variable: zr95_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: zr95_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: zr95_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: zr95_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: zr95_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: zr95_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: zr95_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: nb95
+--------------------------------------------------------------------------------
+Group: seawater, Variable: nb95_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: nb95_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: nb95_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: nb95_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: nb95_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: nb95_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: nb95_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: nb95_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: tc99
+--------------------------------------------------------------------------------
+Group: seawater, Variable: tc99_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: tc99_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: tc99_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: tc99_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: tc99_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: tc99_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: tc99_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: tc99_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru103
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru103_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru103_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru103_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru103_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru103_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru103_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru103_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru103_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru106
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru106_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru106_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru106_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru106_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru106_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru106_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru106_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ru106_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ag110m
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ag110m_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ag110m_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ag110m_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ag110m_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ag110m_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ag110m_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ag110m_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sb125
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sb125_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sb125_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sb125_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sb125_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sb125_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sb125_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sb125_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: sb125_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs134
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs134_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs134_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs134_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs134_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs134_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs134_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs134_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs134_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs137
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs137_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs137_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs137_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs137_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs137_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs137_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs137_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cs137_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ba140
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ba140_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ba140_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ba140_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ba140_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ba140_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ba140_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ba140_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ce144
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ce144_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ce144_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ce144_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ce144_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ce144_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ce144_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: ce144_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pb210
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pb210_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pb210_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pb210_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pb210_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pb210_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pb210_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pb210_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pb210_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: po210
+--------------------------------------------------------------------------------
+Group: seawater, Variable: po210_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: po210_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: po210_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: po210_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: po210_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: po210_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: po210_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: po210_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u234
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u234_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u234_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u234_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u234_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u234_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u234_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u234_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u238
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u238_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u238_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u238_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u238_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u238_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u238_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: u238_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: np237
+--------------------------------------------------------------------------------
+Group: seawater, Variable: np237_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: np237_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: np237_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: np237_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: np237_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: np237_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: np237_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu238
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu238_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu238_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu238_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu238_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu238_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu238_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu238_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu238_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu240
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu240_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu240_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu240_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu240_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu240_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu240_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu240_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: am241
+--------------------------------------------------------------------------------
+Group: seawater, Variable: am241_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: am241_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: am241_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: am241_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: am241_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: am241_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: am241_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: am241_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm242
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm242_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm242_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm242_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm242_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm242_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm242_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm242_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm242_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm244
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm244_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm244_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm244_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm244_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm244_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm244_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm244_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm244_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_240_tot
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_240_tot_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_240_tot_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_240_tot_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_240_tot_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_240_tot_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_240_tot_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_240_tot_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: pu239_240_tot_unit
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm243_244_tot
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm243_244_tot_unc
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm243_244_tot_dl
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm243_244_tot_sal
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm243_244_tot_temp
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm243_244_tot_counmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm243_244_tot_sampmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm243_244_tot_prepmet
+--------------------------------------------------------------------------------
+Group: seawater, Variable: cm243_244_tot_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: lon
+--------------------------------------------------------------------------------
+Group: sediment, Variable: lat
+--------------------------------------------------------------------------------
+Group: sediment, Variable: smp_depth
+--------------------------------------------------------------------------------
+Group: sediment, Variable: tot_depth
+--------------------------------------------------------------------------------
+Group: sediment, Variable: time
+--------------------------------------------------------------------------------
+Group: sediment, Variable: area
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sed_type
+--------------------------------------------------------------------------------
+Group: sediment, Variable: be7
+--------------------------------------------------------------------------------
+Group: sediment, Variable: be7_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: be7_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: be7_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: be7_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: be7_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: k40
+--------------------------------------------------------------------------------
+Group: sediment, Variable: k40_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: k40_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: k40_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: k40_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: k40_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: mn54
+--------------------------------------------------------------------------------
+Group: sediment, Variable: mn54_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: mn54_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: mn54_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: mn54_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: mn54_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: co58
+--------------------------------------------------------------------------------
+Group: sediment, Variable: co58_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: co58_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: co58_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: co58_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: co58_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: co60
+--------------------------------------------------------------------------------
+Group: sediment, Variable: co60_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: co60_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: co60_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: co60_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: co60_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: zn65
+--------------------------------------------------------------------------------
+Group: sediment, Variable: zn65_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: zn65_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: zn65_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: zn65_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: zn65_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sr90
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sr90_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sr90_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sr90_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sr90_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sr90_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: zr95
+--------------------------------------------------------------------------------
+Group: sediment, Variable: zr95_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: zr95_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: zr95_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: zr95_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: zr95_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: nb95
+--------------------------------------------------------------------------------
+Group: sediment, Variable: nb95_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: nb95_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: nb95_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: nb95_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: nb95_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ru103
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ru103_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ru103_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ru103_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ru103_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ru103_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ru106
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ru106_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ru106_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ru106_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ru106_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ru106_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ag110m
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ag110m_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ag110m_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ag110m_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ag110m_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ag110m_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sb124
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sb124_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sb124_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sb124_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sb124_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sb124_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sb125
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sb125_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sb125_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sb125_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sb125_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: sb125_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs134
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs134_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs134_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs134_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs134_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs134_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs137
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs137_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs137_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs137_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs137_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs137_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ba140
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ba140_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ba140_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ba140_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ba140_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ba140_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ce144
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ce144_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ce144_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ce144_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ce144_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ce144_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: eu155
+--------------------------------------------------------------------------------
+Group: sediment, Variable: eu155_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: eu155_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: eu155_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: eu155_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: eu155_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb210
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb210_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb210_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb210_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb210_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb210_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb212
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb212_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb212_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb212_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb212_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb212_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb214
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb214_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb214_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb214_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb214_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pb214_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: bi214
+--------------------------------------------------------------------------------
+Group: sediment, Variable: bi214_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: bi214_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: bi214_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: bi214_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: bi214_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: po210
+--------------------------------------------------------------------------------
+Group: sediment, Variable: po210_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: po210_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: po210_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: po210_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: po210_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra223
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra223_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra223_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra223_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra223_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra223_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra224
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra224_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra224_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra224_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra224_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra224_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra226
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra226_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra226_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra226_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra226_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra226_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra228
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra228_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra228_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra228_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra228_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ra228_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ac228
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ac228_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ac228_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ac228_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ac228_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ac228_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th228
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th228_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th228_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th228_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th228_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th228_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th232
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th232_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th232_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th232_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th232_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th232_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th234
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th234_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th234_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th234_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th234_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: th234_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: u235
+--------------------------------------------------------------------------------
+Group: sediment, Variable: u235_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: u235_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: u235_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: u235_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: u235_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu238
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu238_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu238_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu238_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu238_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu238_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu239
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu239_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu239_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu239_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu239_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu239_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu241
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu241_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu241_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu241_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu241_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu241_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: am241
+--------------------------------------------------------------------------------
+Group: sediment, Variable: am241_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: am241_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: am241_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: am241_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: am241_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs134_137_tot
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs134_137_tot_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs134_137_tot_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs134_137_tot_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs134_137_tot_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cs134_137_tot_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu239_240_tot
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu239_240_tot_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu239_240_tot_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu239_240_tot_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu239_240_tot_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu239_240_tot_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cd109
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cd109_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cd109_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cd109_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cd109_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: cd109_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ir192
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ir192_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ir192_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ir192_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ir192_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: ir192_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu238_240_tot
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu238_240_tot_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu238_240_tot_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu238_240_tot_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: pu238_240_tot_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: tl208
+--------------------------------------------------------------------------------
+Group: sediment, Variable: tl208_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: tl208_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: tl208_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: tl208_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: tl208_unit
+--------------------------------------------------------------------------------
+Group: sediment, Variable: bi212
+--------------------------------------------------------------------------------
+Group: sediment, Variable: bi212_unc
+--------------------------------------------------------------------------------
+Group: sediment, Variable: bi212_dl
+--------------------------------------------------------------------------------
+Group: sediment, Variable: bi212_sampmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: bi212_prepmet
+--------------------------------------------------------------------------------
+Group: sediment, Variable: bi212_unit
+
+
+
                                              
+
+
+
+
+

All datasets

+
+
encode(fname_in, dir_dest, nc_tpl_path(), verbose=False)
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/handlers/netcdf_to_csv.html b/handlers/netcdf_to_csv.html new file mode 100644 index 0000000..8625171 --- /dev/null +++ b/handlers/netcdf_to_csv.html @@ -0,0 +1,3820 @@ + + + + + + + + + +NetCDF to Open Refine CSV (WIP) – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

NetCDF to Open Refine CSV (WIP)

+
+ + + +
+ + + + +
+ + + +
+ + + +
+
+

Packages import

+

Get the current working directory (cwd). .

+
+
Path.cwd()
+
+
Path('/Users/franckalbinet/pro/IAEA/MARIS/marisco/nbs/handlers')
+
+
+
+
+

Load NetCDF

+
+

source

+
+

netcdf4_to_df

+
+
 netcdf4_to_df (fname_in)
+
+
+
dfs = netcdf4_to_df(fname_in)
+dfs
+
+
+
dfs['seawater']
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
lonlatsmp_depthtot_depthtimeh3h3_unch3_dlh3_salh3_temp...pu239_240_tot_dlpu239_240_tot_salpu239_240_tot_temppu239_240_tot_unitcm243_244_totcm243_244_tot_unccm243_244_tot_dlcm243_244_tot_salcm243_244_tot_tempcm243_244_tot_unit
sample
014.25780053.9422000.010.01339545600NaNNaN-1NaNNaN...-1NaNNaN-1NaNNaN-1NaNNaN-1
114.25780053.9422008.010.01339545600NaNNaN-1NaNNaN...-1NaNNaN-1NaNNaN-1NaNNaN-1
214.25780053.9422000.010.01339545600NaNNaN-1NaNNaN...-1NaNNaN-1NaNNaN-1NaNNaN-1
314.25780053.9422008.010.01339545600NaNNaN-1NaNNaN...-1NaNNaN-1NaNNaN-1NaNNaN-1
414.25780053.9422000.09.01370390400NaNNaN-1NaNNaN...-1NaNNaN-1NaNNaN-1NaNNaN-1
..................................................................
2023724.33499965.6346970.017.0773971200NaNNaN-1NaNNaN...-1NaNNaN-1NaNNaN-1NaNNaN-1
2023824.33499965.6346970.017.0773971200NaNNaN-1NaNNaN...-1NaNNaN-1NaNNaN-1NaNNaN-1
2023924.33499965.6346970.017.0773971200NaNNaN-1NaNNaN...-1NaNNaN-1NaNNaN-1NaNNaN-1
2024024.33499965.6346970.017.0841190400NaNNaN-1NaNNaN...-1NaNNaN-1NaNNaN-1NaNNaN-1
2024124.33499965.6346970.017.0841190400NaNNaN-1NaNNaN...-1NaNNaN-1NaNNaN-1NaNNaN-1
+ +

20242 rows × 175 columns

+
+
+
+
+
dfs['biota']
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
lonlatsmp_depthtimebio_groupspeciesbody_partbe7be7_uncbe7_dl...sn113_dlsn113_unitsn117msn117m_uncsn117m_dlsn117m_unittl208tl208_unctl208_dltl208_unit
sample
014.30000053.500000NaN1443052800424752NaNNaN-1...-1-1NaNNaN-1-1NaNNaN-1-1
114.30000053.500000NaN1443052800424752NaNNaN-1...-1-1NaNNaN-1-1NaNNaN-1-1
214.30000053.500000NaN1443052800424752NaNNaN-1...-1-1NaNNaN-1-1NaNNaN-1-1
314.30000053.500000NaN1443052800424752NaNNaN-1...-1-1NaNNaN-1-1NaNNaN-1-1
414.30000053.500000NaN1443052800424752NaNNaN-1...-1-1NaNNaN-1-1NaNNaN-1-1
..................................................................
1486823.00000065.7166980.0112760640045052NaNNaN-1...-1-1NaNNaN-1-1NaNNaN-1-1
1486923.04999965.7166980.0106401600045052NaNNaN-1...-1-1NaNNaN-1-1NaNNaN-1-1
1487023.04999965.7166980.0106401600045052NaNNaN-1...-1-1NaNNaN-1-1NaNNaN-1-1
1487123.00000065.7500000.0128494080045052NaNNaN-1...-1-1NaNNaN-1-1NaNNaN-1-1
1487223.00000065.7500000.0128494080045052NaNNaN-1...-1-1NaNNaN-1-1NaNNaN-1-1
+ +

14873 rows × 211 columns

+
+
+
+
+
+
+

Transform data

+
+

Reshape: wide to long

+
+

source

+
+
+

ReshapeWideToLong

+
+
 ReshapeWideToLong (columns='nuclide', values=['value'])
+
+

Convert data from wide to long with renamed columns.

+
+
dfs = netcdf4_to_df(fname_in)
+tfm = Transformer(dfs, cbs=[ReshapeWideToLong()])
+tfm()
+
+
{'seawater':              lon        lat  smp_depth  tot_depth        time  sample  \
+ 0      14.199800  54.006001        0.0       11.0  1497744000      78   
+ 1      14.202300  54.006199        0.0       12.0  1339632000      83   
+ 2      14.199500  54.006302        0.0       12.0  1402876800      86   
+ 3      14.201000  54.006500        0.0       12.0  1278460800      91   
+ 4      14.200500  54.006668        0.0       12.0  1309910400     101   
+ ...          ...        ...        ...        ...         ...     ...   
+ 20237  20.030001  57.343300        0.0      236.0   524620800   14175   
+ 20238  21.500000  59.433300        0.0      156.0   555033600   15712   
+ 20239  21.525801  59.439800        0.0      160.0   585446400   15840   
+ 20240  21.525801  59.439800      150.0      160.0   585446400   15847   
+ 20241  23.555000  65.239998        0.0       73.0   587001600   20130   
+ 
+              nuclide      value       _unc  _dl  _sal  _temp  _unit  
+ 0                 h3   850.0000  59.669998    1  7.50    NaN      1  
+ 1                 h3   970.0000  29.100000    1  6.77    NaN      1  
+ 2                 h3   910.0000  24.570000    1  6.80    NaN      1  
+ 3                 h3  1070.0000  21.400000    1  5.82    NaN      1  
+ 4                 h3  1020.0000  20.400000    1  5.40    NaN      1  
+ ...              ...        ...        ...  ...   ...    ...    ...  
+ 20237  cm243_244_tot     0.0064   0.001280    1  6.90    NaN      1  
+ 20238  cm243_244_tot     0.0045   0.000900    1  6.75    NaN      1  
+ 20239  cm243_244_tot     0.0022   0.000660    1  5.83   20.4      1  
+ 20240  cm243_244_tot     0.0064   0.001920    1  9.77    3.9      1  
+ 20241  cm243_244_tot     0.0039   0.001170    1  3.10   15.6      1  
+ 
+ [20242 rows x 13 columns],
+ 'sediment':              lon        lat  tot_depth        time  sed_type  sample nuclide  \
+ 0      10.850000  54.049999       22.0   866592000        58     842     be7   
+ 1      10.203300  54.415001       13.0   811641600        58    4064     be7   
+ 2      10.203300  54.415001       13.0   811641600        58    4069     be7   
+ 3      10.203300  54.415001       13.0   811641600        58    4074     be7   
+ 4      11.750000  54.416698       24.0   838512000        58    4535     be7   
+ ...          ...        ...        ...         ...       ...     ...     ...   
+ 37084  23.391199  65.277496       90.0  1283299200         2   37039   bi212   
+ 37085  23.391199  65.277496       90.0  1283299200         2   37048   bi212   
+ 37086  23.391199  65.277496       90.0  1283299200         2   37065   bi212   
+ 37087  23.391199  65.277496       90.0  1283299200         2   37074   bi212   
+ 37088  23.391199  65.277496       90.0  1283299200         2   37083   bi212   
+ 
+            value    _unc  _dl  _unit  
+ 0      24.299999  7.7760    1      4  
+ 1      45.500000  4.5500    1      4  
+ 2       7.000000     NaN    2      4  
+ 3       4.800000     NaN    2      4  
+ 4       6.900000  1.9320    1      4  
+ ...          ...     ...  ...    ...  
+ 37084  42.900002  6.1347    1      4  
+ 37085  58.400002  6.1904    1      4  
+ 37086  51.400002  5.9624    1      4  
+ 37087  41.799999  5.4758    1      4  
+ 37088  43.700001  3.4523    1      4  
+ 
+ [37089 rows x 11 columns],
+ 'biota':            lon        lat  smp_depth        time  bio_group  species  \
+ 0      11.5000  54.080002        0.0   908755200         11       96   
+ 1      11.5000  54.080002        0.0   900547200         11       96   
+ 2      11.5000  54.080002        0.0   874540800         14      129   
+ 3      11.5000  54.080002        0.0   865900800         14      129   
+ 4      11.5000  54.080002        0.0   874886400         11       96   
+ ...        ...        ...        ...         ...        ...      ...   
+ 14868  12.0742  57.335201        0.0  1253145600         11       96   
+ 14869  12.0742  57.335201        0.0  1225670400         11       96   
+ 14870  12.0742  57.335201        0.0  1160352000         11       96   
+ 14871  12.0742  57.335201        0.0  1380240000         11       96   
+ 14872  12.0742  57.335201        0.0  1409788800         11       96   
+ 
+        body_part  sample nuclide   value      _unc  _dl  _unit  
+ 0             54     150     be7  46.500  1.813500    1      4  
+ 1             54     159     be7  66.500  6.317500    1      4  
+ 2              1     168     be7   5.430  1.574700    1      4  
+ 3              1     177     be7  13.700  4.384000    1      4  
+ 4             54     183     be7  11.300  0.000000    2      4  
+ ...          ...     ...     ...     ...       ...  ...    ...  
+ 14868         54   11586   tl208   0.880  0.079200    1      4  
+ 14869         54   11598   tl208   0.770  0.069300    1      4  
+ 14870         54   11620   tl208   1.310  0.142790    1      4  
+ 14871         54   11766   tl208   0.668  0.057448    1      4  
+ 14872         54   11775   tl208   0.684  0.072504    1      4  
+ 
+ [14873 rows x 13 columns]}
+
+
+
+
tfm.dfs['sediment']
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
lonlattot_depthtimesed_typesamplenuclidevalue_unc_dl_unit
010.85000054.04999922.086659200058842be724.2999997.776014
110.20330054.41500113.0811641600584064be745.5000004.550014
210.20330054.41500113.0811641600584069be77.000000NaN24
310.20330054.41500113.0811641600584074be74.800000NaN24
411.75000054.41669824.0838512000584535be76.9000001.932014
....................................
3708423.39119965.27749690.01283299200237039bi21242.9000026.134714
3708523.39119965.27749690.01283299200237048bi21258.4000026.190414
3708623.39119965.27749690.01283299200237065bi21251.4000025.962414
3708723.39119965.27749690.01283299200237074bi21241.7999995.475814
3708823.39119965.27749690.01283299200237083bi21243.7000013.452314
+ +

37089 rows × 11 columns

+
+
+
+
+
+
+

Format: Time

+
+

source

+
+
+

LookupTimeFromEncodedTime

+
+
 LookupTimeFromEncodedTime (cfg)
+
+

Base class for callbacks.

+
+
dfs = netcdf4_to_df(fname_in)
+tfm = Transformer(dfs, cbs=[ReshapeWideToLong(),
+                            LookupTimeFromEncodedTime(cfg())])
+tfm()
+
+
{'seawater':              lon        lat  smp_depth  tot_depth        time  sample  \
+ 0      14.199800  54.006001        0.0       11.0  1497744000      78   
+ 1      14.202300  54.006199        0.0       12.0  1339632000      83   
+ 2      14.199500  54.006302        0.0       12.0  1402876800      86   
+ 3      14.201000  54.006500        0.0       12.0  1278460800      91   
+ 4      14.200500  54.006668        0.0       12.0  1309910400     101   
+ ...          ...        ...        ...        ...         ...     ...   
+ 20237  20.030001  57.343300        0.0      236.0   524620800   14175   
+ 20238  21.500000  59.433300        0.0      156.0   555033600   15712   
+ 20239  21.525801  59.439800        0.0      160.0   585446400   15840   
+ 20240  21.525801  59.439800      150.0      160.0   585446400   15847   
+ 20241  23.555000  65.239998        0.0       73.0   587001600   20130   
+ 
+              nuclide      value       _unc  _dl  _sal  _temp  _unit  \
+ 0                 h3   850.0000  59.669998    1  7.50    NaN      1   
+ 1                 h3   970.0000  29.100000    1  6.77    NaN      1   
+ 2                 h3   910.0000  24.570000    1  6.80    NaN      1   
+ 3                 h3  1070.0000  21.400000    1  5.82    NaN      1   
+ 4                 h3  1020.0000  20.400000    1  5.40    NaN      1   
+ ...              ...        ...        ...  ...   ...    ...    ...   
+ 20237  cm243_244_tot     0.0064   0.001280    1  6.90    NaN      1   
+ 20238  cm243_244_tot     0.0045   0.000900    1  6.75    NaN      1   
+ 20239  cm243_244_tot     0.0022   0.000660    1  5.83   20.4      1   
+ 20240  cm243_244_tot     0.0064   0.001920    1  9.77    3.9      1   
+ 20241  cm243_244_tot     0.0039   0.001170    1  3.10   15.6      1   
+ 
+       Sampling start date Sampling start time  
+ 0             18-Jun-2017            00:00:00  
+ 1             14-Jun-2012            00:00:00  
+ 2             16-Jun-2014            00:00:00  
+ 3             07-Jul-2010            00:00:00  
+ 4             06-Jul-2011            00:00:00  
+ ...                   ...                 ...  
+ 20237         17-Aug-1986            00:00:00  
+ 20238         04-Aug-1987            00:00:00  
+ 20239         21-Jul-1988            00:00:00  
+ 20240         21-Jul-1988            00:00:00  
+ 20241         08-Aug-1988            00:00:00  
+ 
+ [20242 rows x 15 columns],
+ 'sediment':              lon        lat  tot_depth        time  sed_type  sample nuclide  \
+ 0      10.850000  54.049999       22.0   866592000        58     842     be7   
+ 1      10.203300  54.415001       13.0   811641600        58    4064     be7   
+ 2      10.203300  54.415001       13.0   811641600        58    4069     be7   
+ 3      10.203300  54.415001       13.0   811641600        58    4074     be7   
+ 4      11.750000  54.416698       24.0   838512000        58    4535     be7   
+ ...          ...        ...        ...         ...       ...     ...     ...   
+ 37084  23.391199  65.277496       90.0  1283299200         2   37039   bi212   
+ 37085  23.391199  65.277496       90.0  1283299200         2   37048   bi212   
+ 37086  23.391199  65.277496       90.0  1283299200         2   37065   bi212   
+ 37087  23.391199  65.277496       90.0  1283299200         2   37074   bi212   
+ 37088  23.391199  65.277496       90.0  1283299200         2   37083   bi212   
+ 
+            value    _unc  _dl  _unit Sampling start date Sampling start time  
+ 0      24.299999  7.7760    1      4         18-Jun-1997            00:00:00  
+ 1      45.500000  4.5500    1      4         21-Sep-1995            00:00:00  
+ 2       7.000000     NaN    2      4         21-Sep-1995            00:00:00  
+ 3       4.800000     NaN    2      4         21-Sep-1995            00:00:00  
+ 4       6.900000  1.9320    1      4         28-Jul-1996            00:00:00  
+ ...          ...     ...  ...    ...                 ...                 ...  
+ 37084  42.900002  6.1347    1      4         01-Sep-2010            00:00:00  
+ 37085  58.400002  6.1904    1      4         01-Sep-2010            00:00:00  
+ 37086  51.400002  5.9624    1      4         01-Sep-2010            00:00:00  
+ 37087  41.799999  5.4758    1      4         01-Sep-2010            00:00:00  
+ 37088  43.700001  3.4523    1      4         01-Sep-2010            00:00:00  
+ 
+ [37089 rows x 13 columns],
+ 'biota':            lon        lat  smp_depth        time  bio_group  species  \
+ 0      11.5000  54.080002        0.0   908755200         11       96   
+ 1      11.5000  54.080002        0.0   900547200         11       96   
+ 2      11.5000  54.080002        0.0   874540800         14      129   
+ 3      11.5000  54.080002        0.0   865900800         14      129   
+ 4      11.5000  54.080002        0.0   874886400         11       96   
+ ...        ...        ...        ...         ...        ...      ...   
+ 14868  12.0742  57.335201        0.0  1253145600         11       96   
+ 14869  12.0742  57.335201        0.0  1225670400         11       96   
+ 14870  12.0742  57.335201        0.0  1160352000         11       96   
+ 14871  12.0742  57.335201        0.0  1380240000         11       96   
+ 14872  12.0742  57.335201        0.0  1409788800         11       96   
+ 
+        body_part  sample nuclide   value      _unc  _dl  _unit  \
+ 0             54     150     be7  46.500  1.813500    1      4   
+ 1             54     159     be7  66.500  6.317500    1      4   
+ 2              1     168     be7   5.430  1.574700    1      4   
+ 3              1     177     be7  13.700  4.384000    1      4   
+ 4             54     183     be7  11.300  0.000000    2      4   
+ ...          ...     ...     ...     ...       ...  ...    ...   
+ 14868         54   11586   tl208   0.880  0.079200    1      4   
+ 14869         54   11598   tl208   0.770  0.069300    1      4   
+ 14870         54   11620   tl208   1.310  0.142790    1      4   
+ 14871         54   11766   tl208   0.668  0.057448    1      4   
+ 14872         54   11775   tl208   0.684  0.072504    1      4   
+ 
+       Sampling start date Sampling start time  
+ 0             19-Oct-1998            00:00:00  
+ 1             16-Jul-1998            00:00:00  
+ 2             18-Sep-1997            00:00:00  
+ 3             10-Jun-1997            00:00:00  
+ 4             22-Sep-1997            00:00:00  
+ ...                   ...                 ...  
+ 14868         17-Sep-2009            00:00:00  
+ 14869         03-Nov-2008            00:00:00  
+ 14870         09-Oct-2006            00:00:00  
+ 14871         27-Sep-2013            00:00:00  
+ 14872         04-Sep-2014            00:00:00  
+ 
+ [14873 rows x 15 columns]}
+
+
+
+
tfm.dfs['seawater']['Sampling start date']
+
+
0        18-Jun-2017
+1        14-Jun-2012
+2        16-Jun-2014
+3        07-Jul-2010
+4        06-Jul-2011
+            ...     
+20237    17-Aug-1986
+20238    04-Aug-1987
+20239    21-Jul-1988
+20240    21-Jul-1988
+20241    08-Aug-1988
+Name: Sampling start date, Length: 20242, dtype: object
+
+
+
+
+
+

Lookup: Sample Type

+
+

source

+
+
+

GetSampleTypeCB

+
+
 GetSampleTypeCB ()
+
+

Base class for callbacks.

+
+
dfs = netcdf4_to_df(fname_in)
+tfm = Transformer(dfs, cbs=[ReshapeWideToLong(),
+                            LookupTimeFromEncodedTime(cfg()),
+                            GetSampleTypeCB()])
+tfm()['biota']['Sample type']
+
+
0        BIOTA
+1        BIOTA
+2        BIOTA
+3        BIOTA
+4        BIOTA
+         ...  
+14868    BIOTA
+14869    BIOTA
+14870    BIOTA
+14871    BIOTA
+14872    BIOTA
+Name: Sample type, Length: 14873, dtype: object
+
+
+
+
+
+

Lookup : Nuclide

+
+

source

+
+
+

get_nucnames_lut

+
+
 get_nucnames_lut ()
+
+
+

source

+
+
+

LookupNuclideByIdCB

+
+
 LookupNuclideByIdCB (fn_lut=<function get_nucnames_lut>)
+
+

Lookup MARIS nuclide_id.

+
+
dfs = netcdf4_to_df(fname_in)
+tfm = Transformer(dfs, cbs=[ReshapeWideToLong(),
+                            LookupTimeFromEncodedTime(cfg()),
+                            GetSampleTypeCB(),
+                            LookupNuclideByIdCB(),
+                            ])
+tfm()
+
+
{'seawater':              lon        lat  smp_depth  tot_depth        time  sample  \
+ 0      14.199800  54.006001        0.0       11.0  1497744000      78   
+ 1      14.202300  54.006199        0.0       12.0  1339632000      83   
+ 2      14.199500  54.006302        0.0       12.0  1402876800      86   
+ 3      14.201000  54.006500        0.0       12.0  1278460800      91   
+ 4      14.200500  54.006668        0.0       12.0  1309910400     101   
+ ...          ...        ...        ...        ...         ...     ...   
+ 20237  20.030001  57.343300        0.0      236.0   524620800   14175   
+ 20238  21.500000  59.433300        0.0      156.0   555033600   15712   
+ 20239  21.525801  59.439800        0.0      160.0   585446400   15840   
+ 20240  21.525801  59.439800      150.0      160.0   585446400   15847   
+ 20241  23.555000  65.239998        0.0       73.0   587001600   20130   
+ 
+              nuclide      value       _unc  _dl  _sal  _temp  _unit  \
+ 0                 h3   850.0000  59.669998    1  7.50    NaN      1   
+ 1                 h3   970.0000  29.100000    1  6.77    NaN      1   
+ 2                 h3   910.0000  24.570000    1  6.80    NaN      1   
+ 3                 h3  1070.0000  21.400000    1  5.82    NaN      1   
+ 4                 h3  1020.0000  20.400000    1  5.40    NaN      1   
+ ...              ...        ...        ...  ...   ...    ...    ...   
+ 20237  cm243_244_tot     0.0064   0.001280    1  6.90    NaN      1   
+ 20238  cm243_244_tot     0.0045   0.000900    1  6.75    NaN      1   
+ 20239  cm243_244_tot     0.0022   0.000660    1  5.83   20.4      1   
+ 20240  cm243_244_tot     0.0064   0.001920    1  9.77    3.9      1   
+ 20241  cm243_244_tot     0.0039   0.001170    1  3.10   15.6      1   
+ 
+       Sampling start date Sampling start time Sample type    Nuclide  
+ 0             18-Jun-2017            00:00:00    SEAWATER         3H  
+ 1             14-Jun-2012            00:00:00    SEAWATER         3H  
+ 2             16-Jun-2014            00:00:00    SEAWATER         3H  
+ 3             07-Jul-2010            00:00:00    SEAWATER         3H  
+ 4             06-Jul-2011            00:00:00    SEAWATER         3H  
+ ...                   ...                 ...         ...        ...  
+ 20237         17-Aug-1986            00:00:00    SEAWATER  243_244Cm  
+ 20238         04-Aug-1987            00:00:00    SEAWATER  243_244Cm  
+ 20239         21-Jul-1988            00:00:00    SEAWATER  243_244Cm  
+ 20240         21-Jul-1988            00:00:00    SEAWATER  243_244Cm  
+ 20241         08-Aug-1988            00:00:00    SEAWATER  243_244Cm  
+ 
+ [20242 rows x 17 columns],
+ 'sediment':              lon        lat  tot_depth        time  sed_type  sample nuclide  \
+ 0      10.850000  54.049999       22.0   866592000        58     842     be7   
+ 1      10.203300  54.415001       13.0   811641600        58    4064     be7   
+ 2      10.203300  54.415001       13.0   811641600        58    4069     be7   
+ 3      10.203300  54.415001       13.0   811641600        58    4074     be7   
+ 4      11.750000  54.416698       24.0   838512000        58    4535     be7   
+ ...          ...        ...        ...         ...       ...     ...     ...   
+ 37084  23.391199  65.277496       90.0  1283299200         2   37039   bi212   
+ 37085  23.391199  65.277496       90.0  1283299200         2   37048   bi212   
+ 37086  23.391199  65.277496       90.0  1283299200         2   37065   bi212   
+ 37087  23.391199  65.277496       90.0  1283299200         2   37074   bi212   
+ 37088  23.391199  65.277496       90.0  1283299200         2   37083   bi212   
+ 
+            value    _unc  _dl  _unit Sampling start date Sampling start time  \
+ 0      24.299999  7.7760    1      4         18-Jun-1997            00:00:00   
+ 1      45.500000  4.5500    1      4         21-Sep-1995            00:00:00   
+ 2       7.000000     NaN    2      4         21-Sep-1995            00:00:00   
+ 3       4.800000     NaN    2      4         21-Sep-1995            00:00:00   
+ 4       6.900000  1.9320    1      4         28-Jul-1996            00:00:00   
+ ...          ...     ...  ...    ...                 ...                 ...   
+ 37084  42.900002  6.1347    1      4         01-Sep-2010            00:00:00   
+ 37085  58.400002  6.1904    1      4         01-Sep-2010            00:00:00   
+ 37086  51.400002  5.9624    1      4         01-Sep-2010            00:00:00   
+ 37087  41.799999  5.4758    1      4         01-Sep-2010            00:00:00   
+ 37088  43.700001  3.4523    1      4         01-Sep-2010            00:00:00   
+ 
+       Sample type Nuclide  
+ 0        SEDIMENT     7Be  
+ 1        SEDIMENT     7Be  
+ 2        SEDIMENT     7Be  
+ 3        SEDIMENT     7Be  
+ 4        SEDIMENT     7Be  
+ ...           ...     ...  
+ 37084    SEDIMENT   212Bi  
+ 37085    SEDIMENT   212Bi  
+ 37086    SEDIMENT   212Bi  
+ 37087    SEDIMENT   212Bi  
+ 37088    SEDIMENT   212Bi  
+ 
+ [37089 rows x 15 columns],
+ 'biota':            lon        lat  smp_depth        time  bio_group  species  \
+ 0      11.5000  54.080002        0.0   908755200         11       96   
+ 1      11.5000  54.080002        0.0   900547200         11       96   
+ 2      11.5000  54.080002        0.0   874540800         14      129   
+ 3      11.5000  54.080002        0.0   865900800         14      129   
+ 4      11.5000  54.080002        0.0   874886400         11       96   
+ ...        ...        ...        ...         ...        ...      ...   
+ 14868  12.0742  57.335201        0.0  1253145600         11       96   
+ 14869  12.0742  57.335201        0.0  1225670400         11       96   
+ 14870  12.0742  57.335201        0.0  1160352000         11       96   
+ 14871  12.0742  57.335201        0.0  1380240000         11       96   
+ 14872  12.0742  57.335201        0.0  1409788800         11       96   
+ 
+        body_part  sample nuclide   value      _unc  _dl  _unit  \
+ 0             54     150     be7  46.500  1.813500    1      4   
+ 1             54     159     be7  66.500  6.317500    1      4   
+ 2              1     168     be7   5.430  1.574700    1      4   
+ 3              1     177     be7  13.700  4.384000    1      4   
+ 4             54     183     be7  11.300  0.000000    2      4   
+ ...          ...     ...     ...     ...       ...  ...    ...   
+ 14868         54   11586   tl208   0.880  0.079200    1      4   
+ 14869         54   11598   tl208   0.770  0.069300    1      4   
+ 14870         54   11620   tl208   1.310  0.142790    1      4   
+ 14871         54   11766   tl208   0.668  0.057448    1      4   
+ 14872         54   11775   tl208   0.684  0.072504    1      4   
+ 
+       Sampling start date Sampling start time Sample type Nuclide  
+ 0             19-Oct-1998            00:00:00       BIOTA     7Be  
+ 1             16-Jul-1998            00:00:00       BIOTA     7Be  
+ 2             18-Sep-1997            00:00:00       BIOTA     7Be  
+ 3             10-Jun-1997            00:00:00       BIOTA     7Be  
+ 4             22-Sep-1997            00:00:00       BIOTA     7Be  
+ ...                   ...                 ...         ...     ...  
+ 14868         17-Sep-2009            00:00:00       BIOTA   208Tl  
+ 14869         03-Nov-2008            00:00:00       BIOTA   208Tl  
+ 14870         09-Oct-2006            00:00:00       BIOTA   208Tl  
+ 14871         27-Sep-2013            00:00:00       BIOTA   208Tl  
+ 14872         04-Sep-2014            00:00:00       BIOTA   208Tl  
+ 
+ [14873 rows x 17 columns]}
+
+
+
+
tfm.dfs['biota']['Nuclide'].unique()
+
+
array(['7Be', '40K', '54Mn', '57Co', '58Co', '60Co', '65Zn', '89Sr',
+       '90Sr', '95Zr', '95Nb', '99Tc', '103Ru', '106Ru', '108mAg',
+       '110mAg', '124Sb', '125Sb', '129mTe', '131I', '134Cs', '137Cs',
+       '140Ba', '140La', '141Ce', '144Ce', '155Eu', '210Pb', '212Pb',
+       '214Pb', '214Bi', '210Po', '223Ra', '224Ra', '226Ra', '228Ra',
+       '228Ac', '228Th', '232Th', '235U', '238Pu', '241Am', '134_137Cs',
+       '239_240Pu', '152Eu', '59Fe', '153Gd', '86Rb', '46Sc', '113Sn',
+       '117mSn', '208Tl'], dtype=object)
+
+
+
+
+
+

Format : Longitude and Latitude

+

Convert from Longitude and Latitude DDD.DDDDD° to degrees, minutes, seconds and direction.

+
+

source

+
+
+

deg_to_dms

+
+
 deg_to_dms (deg, coordinate='lat')
+
+

Convert from decimal degrees to degrees, minutes, seconds.

+
+

source

+
+
+

ConvertLonLatCB

+
+
 ConvertLonLatCB (fn_convert=<function deg_to_dms>)
+
+

Convert from Longitude and Latitude DDD.DDDDD° to degrees, minutes, seconds and direction.

+
+
dfs = netcdf4_to_df(fname_in)
+tfm = Transformer(dfs, cbs=[ReshapeWideToLong(),
+                            LookupTimeFromEncodedTime(cfg()),
+                            GetSampleTypeCB(),
+                            LookupNuclideByIdCB(),
+                            ConvertLonLatCB()
+                            ])
+tfm()
+
+
{'seawater':              lon        lat  smp_depth  tot_depth        time  sample  \
+ 0      14.199800  54.006001        0.0       11.0  1497744000      78   
+ 1      14.202300  54.006199        0.0       12.0  1339632000      83   
+ 2      14.199500  54.006302        0.0       12.0  1402876800      86   
+ 3      14.201000  54.006500        0.0       12.0  1278460800      91   
+ 4      14.200500  54.006668        0.0       12.0  1309910400     101   
+ ...          ...        ...        ...        ...         ...     ...   
+ 20237  20.030001  57.343300        0.0      236.0   524620800   14175   
+ 20238  21.500000  59.433300        0.0      156.0   555033600   15712   
+ 20239  21.525801  59.439800        0.0      160.0   585446400   15840   
+ 20240  21.525801  59.439800      150.0      160.0   585446400   15847   
+ 20241  23.555000  65.239998        0.0       73.0   587001600   20130   
+ 
+              nuclide      value       _unc  _dl  ...  Sample type    Nuclide  \
+ 0                 h3   850.0000  59.669998    1  ...     SEAWATER         3H   
+ 1                 h3   970.0000  29.100000    1  ...     SEAWATER         3H   
+ 2                 h3   910.0000  24.570000    1  ...     SEAWATER         3H   
+ 3                 h3  1070.0000  21.400000    1  ...     SEAWATER         3H   
+ 4                 h3  1020.0000  20.400000    1  ...     SEAWATER         3H   
+ ...              ...        ...        ...  ...  ...          ...        ...   
+ 20237  cm243_244_tot     0.0064   0.001280    1  ...     SEAWATER  243_244Cm   
+ 20238  cm243_244_tot     0.0045   0.000900    1  ...     SEAWATER  243_244Cm   
+ 20239  cm243_244_tot     0.0022   0.000660    1  ...     SEAWATER  243_244Cm   
+ 20240  cm243_244_tot     0.0064   0.001920    1  ...     SEAWATER  243_244Cm   
+ 20241  cm243_244_tot     0.0039   0.001170    1  ...     SEAWATER  243_244Cm   
+ 
+        Latitude degrees Latitude minutes Latitude seconds Latitude direction  \
+ 0                    54                0        21.601868                  N   
+ 1                    54                0        22.315979                  N   
+ 2                    54                0        22.686768                  N   
+ 3                    54                0        23.400879                  N   
+ 4                    54                0        24.005127                  N   
+ ...                 ...              ...              ...                ...   
+ 20237                57               20        35.879517                  N   
+ 20238                59               25        59.880066                  N   
+ 20239                59               26        23.280945                  N   
+ 20240                59               26        23.280945                  N   
+ 20241                65               14        23.992310                  N   
+ 
+       Longitude degrees  Longitude minutes  Longitude seconds  \
+ 0                    14                 11          59.278336   
+ 1                    14                 12           8.280258   
+ 2                    14                 11          58.200302   
+ 3                    14                 12           3.600769   
+ 4                    14                 12           1.798325   
+ ...                 ...                ...                ...   
+ 20237                20                  1          48.002472   
+ 20238                21                 30           0.000000   
+ 20239                21                 31          32.882538   
+ 20240                21                 31          32.882538   
+ 20241                23                 33          18.001099   
+ 
+        Longitude direction  
+ 0                        E  
+ 1                        E  
+ 2                        E  
+ 3                        E  
+ 4                        E  
+ ...                    ...  
+ 20237                    E  
+ 20238                    E  
+ 20239                    E  
+ 20240                    E  
+ 20241                    E  
+ 
+ [20242 rows x 25 columns],
+ 'sediment':              lon        lat  tot_depth        time  sed_type  sample nuclide  \
+ 0      10.850000  54.049999       22.0   866592000        58     842     be7   
+ 1      10.203300  54.415001       13.0   811641600        58    4064     be7   
+ 2      10.203300  54.415001       13.0   811641600        58    4069     be7   
+ 3      10.203300  54.415001       13.0   811641600        58    4074     be7   
+ 4      11.750000  54.416698       24.0   838512000        58    4535     be7   
+ ...          ...        ...        ...         ...       ...     ...     ...   
+ 37084  23.391199  65.277496       90.0  1283299200         2   37039   bi212   
+ 37085  23.391199  65.277496       90.0  1283299200         2   37048   bi212   
+ 37086  23.391199  65.277496       90.0  1283299200         2   37065   bi212   
+ 37087  23.391199  65.277496       90.0  1283299200         2   37074   bi212   
+ 37088  23.391199  65.277496       90.0  1283299200         2   37083   bi212   
+ 
+            value    _unc  _dl  ...  Sample type Nuclide Latitude degrees  \
+ 0      24.299999  7.7760    1  ...     SEDIMENT     7Be               54   
+ 1      45.500000  4.5500    1  ...     SEDIMENT     7Be               54   
+ 2       7.000000     NaN    2  ...     SEDIMENT     7Be               54   
+ 3       4.800000     NaN    2  ...     SEDIMENT     7Be               54   
+ 4       6.900000  1.9320    1  ...     SEDIMENT     7Be               54   
+ ...          ...     ...  ...  ...          ...     ...              ...   
+ 37084  42.900002  6.1347    1  ...     SEDIMENT   212Bi               65   
+ 37085  58.400002  6.1904    1  ...     SEDIMENT   212Bi               65   
+ 37086  51.400002  5.9624    1  ...     SEDIMENT   212Bi               65   
+ 37087  41.799999  5.4758    1  ...     SEDIMENT   212Bi               65   
+ 37088  43.700001  3.4523    1  ...     SEDIMENT   212Bi               65   
+ 
+       Latitude minutes Latitude seconds  Latitude direction  \
+ 0                    2        59.997253                   N   
+ 1                   24        54.003296                   N   
+ 2                   24        54.003296                   N   
+ 3                   24        54.003296                   N   
+ 4                   25         0.114441                   N   
+ ...                ...              ...                 ...   
+ 37084               16        38.986816                   N   
+ 37085               16        38.986816                   N   
+ 37086               16        38.986816                   N   
+ 37087               16        38.986816                   N   
+ 37088               16        38.986816                   N   
+ 
+        Longitude degrees  Longitude minutes Longitude seconds  \
+ 0                     10                 51          0.001373   
+ 1                     10                 12         11.881714   
+ 2                     10                 12         11.881714   
+ 3                     10                 12         11.881714   
+ 4                     11                 45          0.000000   
+ ...                  ...                ...               ...   
+ 37084                 23                 23         28.316803   
+ 37085                 23                 23         28.316803   
+ 37086                 23                 23         28.316803   
+ 37087                 23                 23         28.316803   
+ 37088                 23                 23         28.316803   
+ 
+        Longitude direction  
+ 0                        E  
+ 1                        E  
+ 2                        E  
+ 3                        E  
+ 4                        E  
+ ...                    ...  
+ 37084                    E  
+ 37085                    E  
+ 37086                    E  
+ 37087                    E  
+ 37088                    E  
+ 
+ [37089 rows x 23 columns],
+ 'biota':            lon        lat  smp_depth        time  bio_group  species  \
+ 0      11.5000  54.080002        0.0   908755200         11       96   
+ 1      11.5000  54.080002        0.0   900547200         11       96   
+ 2      11.5000  54.080002        0.0   874540800         14      129   
+ 3      11.5000  54.080002        0.0   865900800         14      129   
+ 4      11.5000  54.080002        0.0   874886400         11       96   
+ ...        ...        ...        ...         ...        ...      ...   
+ 14868  12.0742  57.335201        0.0  1253145600         11       96   
+ 14869  12.0742  57.335201        0.0  1225670400         11       96   
+ 14870  12.0742  57.335201        0.0  1160352000         11       96   
+ 14871  12.0742  57.335201        0.0  1380240000         11       96   
+ 14872  12.0742  57.335201        0.0  1409788800         11       96   
+ 
+        body_part  sample nuclide   value  ...  Sample type  Nuclide  \
+ 0             54     150     be7  46.500  ...        BIOTA      7Be   
+ 1             54     159     be7  66.500  ...        BIOTA      7Be   
+ 2              1     168     be7   5.430  ...        BIOTA      7Be   
+ 3              1     177     be7  13.700  ...        BIOTA      7Be   
+ 4             54     183     be7  11.300  ...        BIOTA      7Be   
+ ...          ...     ...     ...     ...  ...          ...      ...   
+ 14868         54   11586   tl208   0.880  ...        BIOTA    208Tl   
+ 14869         54   11598   tl208   0.770  ...        BIOTA    208Tl   
+ 14870         54   11620   tl208   1.310  ...        BIOTA    208Tl   
+ 14871         54   11766   tl208   0.668  ...        BIOTA    208Tl   
+ 14872         54   11775   tl208   0.684  ...        BIOTA    208Tl   
+ 
+        Latitude degrees Latitude minutes Latitude seconds Latitude direction  \
+ 0                    54                4        48.006592                  N   
+ 1                    54                4        48.006592                  N   
+ 2                    54                4        48.006592                  N   
+ 3                    54                4        48.006592                  N   
+ 4                    54                4        48.006592                  N   
+ ...                 ...              ...              ...                ...   
+ 14868                57               20         6.724548                  N   
+ 14869                57               20         6.724548                  N   
+ 14870                57               20         6.724548                  N   
+ 14871                57               20         6.724548                  N   
+ 14872                57               20         6.724548                  N   
+ 
+       Longitude degrees  Longitude minutes  Longitude seconds  \
+ 0                    11                 30           0.000000   
+ 1                    11                 30           0.000000   
+ 2                    11                 30           0.000000   
+ 3                    11                 30           0.000000   
+ 4                    11                 30           0.000000   
+ ...                 ...                ...                ...   
+ 14868                12                  4          27.118835   
+ 14869                12                  4          27.118835   
+ 14870                12                  4          27.118835   
+ 14871                12                  4          27.118835   
+ 14872                12                  4          27.118835   
+ 
+        Longitude direction  
+ 0                        E  
+ 1                        E  
+ 2                        E  
+ 3                        E  
+ 4                        E  
+ ...                    ...  
+ 14868                    E  
+ 14869                    E  
+ 14870                    E  
+ 14871                    E  
+ 14872                    E  
+ 
+ [14873 rows x 25 columns]}
+
+
+
+
tfm.dfs['seawater'].columns
+
+
Index(['lon', 'lat', 'smp_depth', 'tot_depth', 'time', 'sample', 'nuclide',
+       'value', '_unc', '_dl', '_sal', '_temp', '_unit', 'Sampling start date',
+       'Sampling start time', 'Sample type', 'Nuclide', 'Latitude degrees',
+       'Latitude minutes', 'Latitude seconds', 'Latitude direction',
+       'Longitude degrees', 'Longitude minutes', 'Longitude seconds',
+       'Longitude direction'],
+      dtype='object')
+
+
+
+
+
+

Lookup : Units

+
+

source

+
+
+

get_unitnames_lut

+
+
 get_unitnames_lut ()
+
+
+

source

+
+
+

LookupUnitByIdCB

+
+
 LookupUnitByIdCB (fn_lut=<function get_unitnames_lut>)
+
+

Lookup MARIS unit by unit_id.

+
+
dfs = netcdf4_to_df(fname_in)
+tfm = Transformer(dfs, cbs=[ReshapeWideToLong(),
+                            LookupTimeFromEncodedTime(cfg()),
+                            GetSampleTypeCB(),
+                            LookupNuclideByIdCB(),
+                            ConvertLonLatCB(), 
+                            LookupUnitByIdCB()
+                            ])
+tfm()
+
+
{'seawater':              lon        lat  smp_depth  tot_depth        time  sample  \
+ 0      14.199800  54.006001        0.0       11.0  1497744000      78   
+ 1      14.202300  54.006199        0.0       12.0  1339632000      83   
+ 2      14.199500  54.006302        0.0       12.0  1402876800      86   
+ 3      14.201000  54.006500        0.0       12.0  1278460800      91   
+ 4      14.200500  54.006668        0.0       12.0  1309910400     101   
+ ...          ...        ...        ...        ...         ...     ...   
+ 20237  20.030001  57.343300        0.0      236.0   524620800   14175   
+ 20238  21.500000  59.433300        0.0      156.0   555033600   15712   
+ 20239  21.525801  59.439800        0.0      160.0   585446400   15840   
+ 20240  21.525801  59.439800      150.0      160.0   585446400   15847   
+ 20241  23.555000  65.239998        0.0       73.0   587001600   20130   
+ 
+              nuclide      value       _unc  _dl  ...    Nuclide  \
+ 0                 h3   850.0000  59.669998    1  ...         3H   
+ 1                 h3   970.0000  29.100000    1  ...         3H   
+ 2                 h3   910.0000  24.570000    1  ...         3H   
+ 3                 h3  1070.0000  21.400000    1  ...         3H   
+ 4                 h3  1020.0000  20.400000    1  ...         3H   
+ ...              ...        ...        ...  ...  ...        ...   
+ 20237  cm243_244_tot     0.0064   0.001280    1  ...  243_244Cm   
+ 20238  cm243_244_tot     0.0045   0.000900    1  ...  243_244Cm   
+ 20239  cm243_244_tot     0.0022   0.000660    1  ...  243_244Cm   
+ 20240  cm243_244_tot     0.0064   0.001920    1  ...  243_244Cm   
+ 20241  cm243_244_tot     0.0039   0.001170    1  ...  243_244Cm   
+ 
+        Latitude degrees  Latitude minutes Latitude seconds Latitude direction  \
+ 0                    54                 0        21.601868                  N   
+ 1                    54                 0        22.315979                  N   
+ 2                    54                 0        22.686768                  N   
+ 3                    54                 0        23.400879                  N   
+ 4                    54                 0        24.005127                  N   
+ ...                 ...               ...              ...                ...   
+ 20237                57                20        35.879517                  N   
+ 20238                59                25        59.880066                  N   
+ 20239                59                26        23.280945                  N   
+ 20240                59                26        23.280945                  N   
+ 20241                65                14        23.992310                  N   
+ 
+       Longitude degrees Longitude minutes  Longitude seconds  \
+ 0                    14                11          59.278336   
+ 1                    14                12           8.280258   
+ 2                    14                11          58.200302   
+ 3                    14                12           3.600769   
+ 4                    14                12           1.798325   
+ ...                 ...               ...                ...   
+ 20237                20                 1          48.002472   
+ 20238                21                30           0.000000   
+ 20239                21                31          32.882538   
+ 20240                21                31          32.882538   
+ 20241                23                33          18.001099   
+ 
+        Longitude direction   Unit  
+ 0                        E  Bq/m3  
+ 1                        E  Bq/m3  
+ 2                        E  Bq/m3  
+ 3                        E  Bq/m3  
+ 4                        E  Bq/m3  
+ ...                    ...    ...  
+ 20237                    E  Bq/m3  
+ 20238                    E  Bq/m3  
+ 20239                    E  Bq/m3  
+ 20240                    E  Bq/m3  
+ 20241                    E  Bq/m3  
+ 
+ [20242 rows x 26 columns],
+ 'sediment':              lon        lat  tot_depth        time  sed_type  sample nuclide  \
+ 0      10.850000  54.049999       22.0   866592000        58     842     be7   
+ 1      10.203300  54.415001       13.0   811641600        58    4064     be7   
+ 2      10.203300  54.415001       13.0   811641600        58    4069     be7   
+ 3      10.203300  54.415001       13.0   811641600        58    4074     be7   
+ 4      11.750000  54.416698       24.0   838512000        58    4535     be7   
+ ...          ...        ...        ...         ...       ...     ...     ...   
+ 37084  23.391199  65.277496       90.0  1283299200         2   37039   bi212   
+ 37085  23.391199  65.277496       90.0  1283299200         2   37048   bi212   
+ 37086  23.391199  65.277496       90.0  1283299200         2   37065   bi212   
+ 37087  23.391199  65.277496       90.0  1283299200         2   37074   bi212   
+ 37088  23.391199  65.277496       90.0  1283299200         2   37083   bi212   
+ 
+            value    _unc  _dl  ...  Nuclide Latitude degrees Latitude minutes  \
+ 0      24.299999  7.7760    1  ...      7Be               54                2   
+ 1      45.500000  4.5500    1  ...      7Be               54               24   
+ 2       7.000000     NaN    2  ...      7Be               54               24   
+ 3       4.800000     NaN    2  ...      7Be               54               24   
+ 4       6.900000  1.9320    1  ...      7Be               54               25   
+ ...          ...     ...  ...  ...      ...              ...              ...   
+ 37084  42.900002  6.1347    1  ...    212Bi               65               16   
+ 37085  58.400002  6.1904    1  ...    212Bi               65               16   
+ 37086  51.400002  5.9624    1  ...    212Bi               65               16   
+ 37087  41.799999  5.4758    1  ...    212Bi               65               16   
+ 37088  43.700001  3.4523    1  ...    212Bi               65               16   
+ 
+       Latitude seconds Latitude direction  Longitude degrees  \
+ 0            59.997253                  N                 10   
+ 1            54.003296                  N                 10   
+ 2            54.003296                  N                 10   
+ 3            54.003296                  N                 10   
+ 4             0.114441                  N                 11   
+ ...                ...                ...                ...   
+ 37084        38.986816                  N                 23   
+ 37085        38.986816                  N                 23   
+ 37086        38.986816                  N                 23   
+ 37087        38.986816                  N                 23   
+ 37088        38.986816                  N                 23   
+ 
+        Longitude minutes  Longitude seconds Longitude direction    Unit  
+ 0                     51           0.001373                   E  Bq/kgd  
+ 1                     12          11.881714                   E  Bq/kgd  
+ 2                     12          11.881714                   E  Bq/kgd  
+ 3                     12          11.881714                   E  Bq/kgd  
+ 4                     45           0.000000                   E  Bq/kgd  
+ ...                  ...                ...                 ...     ...  
+ 37084                 23          28.316803                   E  Bq/kgd  
+ 37085                 23          28.316803                   E  Bq/kgd  
+ 37086                 23          28.316803                   E  Bq/kgd  
+ 37087                 23          28.316803                   E  Bq/kgd  
+ 37088                 23          28.316803                   E  Bq/kgd  
+ 
+ [37089 rows x 24 columns],
+ 'biota':            lon        lat  smp_depth        time  bio_group  species  \
+ 0      11.5000  54.080002        0.0   908755200         11       96   
+ 1      11.5000  54.080002        0.0   900547200         11       96   
+ 2      11.5000  54.080002        0.0   874540800         14      129   
+ 3      11.5000  54.080002        0.0   865900800         14      129   
+ 4      11.5000  54.080002        0.0   874886400         11       96   
+ ...        ...        ...        ...         ...        ...      ...   
+ 14868  12.0742  57.335201        0.0  1253145600         11       96   
+ 14869  12.0742  57.335201        0.0  1225670400         11       96   
+ 14870  12.0742  57.335201        0.0  1160352000         11       96   
+ 14871  12.0742  57.335201        0.0  1380240000         11       96   
+ 14872  12.0742  57.335201        0.0  1409788800         11       96   
+ 
+        body_part  sample nuclide   value  ...  Nuclide  Latitude degrees  \
+ 0             54     150     be7  46.500  ...      7Be                54   
+ 1             54     159     be7  66.500  ...      7Be                54   
+ 2              1     168     be7   5.430  ...      7Be                54   
+ 3              1     177     be7  13.700  ...      7Be                54   
+ 4             54     183     be7  11.300  ...      7Be                54   
+ ...          ...     ...     ...     ...  ...      ...               ...   
+ 14868         54   11586   tl208   0.880  ...    208Tl                57   
+ 14869         54   11598   tl208   0.770  ...    208Tl                57   
+ 14870         54   11620   tl208   1.310  ...    208Tl                57   
+ 14871         54   11766   tl208   0.668  ...    208Tl                57   
+ 14872         54   11775   tl208   0.684  ...    208Tl                57   
+ 
+        Latitude minutes Latitude seconds Latitude direction Longitude degrees  \
+ 0                     4        48.006592                  N                11   
+ 1                     4        48.006592                  N                11   
+ 2                     4        48.006592                  N                11   
+ 3                     4        48.006592                  N                11   
+ 4                     4        48.006592                  N                11   
+ ...                 ...              ...                ...               ...   
+ 14868                20         6.724548                  N                12   
+ 14869                20         6.724548                  N                12   
+ 14870                20         6.724548                  N                12   
+ 14871                20         6.724548                  N                12   
+ 14872                20         6.724548                  N                12   
+ 
+       Longitude minutes  Longitude seconds  Longitude direction    Unit  
+ 0                    30           0.000000                    E  Bq/kgd  
+ 1                    30           0.000000                    E  Bq/kgd  
+ 2                    30           0.000000                    E  Bq/kgd  
+ 3                    30           0.000000                    E  Bq/kgd  
+ 4                    30           0.000000                    E  Bq/kgd  
+ ...                 ...                ...                  ...     ...  
+ 14868                 4          27.118835                    E  Bq/kgd  
+ 14869                 4          27.118835                    E  Bq/kgd  
+ 14870                 4          27.118835                    E  Bq/kgd  
+ 14871                 4          27.118835                    E  Bq/kgd  
+ 14872                 4          27.118835                    E  Bq/kgd  
+ 
+ [14873 rows x 26 columns]}
+
+
+
+
tfm.dfs['seawater'].columns
+
+
Index(['lon', 'lat', 'smp_depth', 'tot_depth', 'time', 'sample', 'nuclide',
+       'value', '_unc', '_dl', '_sal', '_temp', '_unit', 'Sampling start date',
+       'Sampling start time', 'Sample type', 'Nuclide', 'Latitude degrees',
+       'Latitude minutes', 'Latitude seconds', 'Latitude direction',
+       'Longitude degrees', 'Longitude minutes', 'Longitude seconds',
+       'Longitude direction', 'Unit'],
+      dtype='object')
+
+
+
+
+
+

Lookup : Value type (_dl)

+
+

source

+
+
+

get_detectionlimitnames_lut

+
+
 get_detectionlimitnames_lut ()
+
+
+

source

+
+
+

LookupValueTypeByIdCB

+
+
 LookupValueTypeByIdCB (fn_lut=<function get_detectionlimitnames_lut>)
+
+

Lookup MARIS Value Type.

+
+
dfs = netcdf4_to_df(fname_in)
+tfm = Transformer(dfs, cbs=[ReshapeWideToLong(),
+                            LookupTimeFromEncodedTime(cfg()),
+                            GetSampleTypeCB(),
+                            LookupNuclideByIdCB(),
+                            ConvertLonLatCB(), 
+                            LookupUnitByIdCB(),
+                            LookupValueTypeByIdCB()
+                            ])
+tfm()
+
+
{'seawater':              lon        lat  smp_depth  tot_depth        time  sample  \
+ 0      14.199800  54.006001        0.0       11.0  1497744000      78   
+ 1      14.202300  54.006199        0.0       12.0  1339632000      83   
+ 2      14.199500  54.006302        0.0       12.0  1402876800      86   
+ 3      14.201000  54.006500        0.0       12.0  1278460800      91   
+ 4      14.200500  54.006668        0.0       12.0  1309910400     101   
+ ...          ...        ...        ...        ...         ...     ...   
+ 20237  20.030001  57.343300        0.0      236.0   524620800   14175   
+ 20238  21.500000  59.433300        0.0      156.0   555033600   15712   
+ 20239  21.525801  59.439800        0.0      160.0   585446400   15840   
+ 20240  21.525801  59.439800      150.0      160.0   585446400   15847   
+ 20241  23.555000  65.239998        0.0       73.0   587001600   20130   
+ 
+              nuclide      value       _unc  _dl  ...  Latitude degrees  \
+ 0                 h3   850.0000  59.669998    1  ...                54   
+ 1                 h3   970.0000  29.100000    1  ...                54   
+ 2                 h3   910.0000  24.570000    1  ...                54   
+ 3                 h3  1070.0000  21.400000    1  ...                54   
+ 4                 h3  1020.0000  20.400000    1  ...                54   
+ ...              ...        ...        ...  ...  ...               ...   
+ 20237  cm243_244_tot     0.0064   0.001280    1  ...                57   
+ 20238  cm243_244_tot     0.0045   0.000900    1  ...                59   
+ 20239  cm243_244_tot     0.0022   0.000660    1  ...                59   
+ 20240  cm243_244_tot     0.0064   0.001920    1  ...                59   
+ 20241  cm243_244_tot     0.0039   0.001170    1  ...                65   
+ 
+        Latitude minutes  Latitude seconds Latitude direction  \
+ 0                     0         21.601868                  N   
+ 1                     0         22.315979                  N   
+ 2                     0         22.686768                  N   
+ 3                     0         23.400879                  N   
+ 4                     0         24.005127                  N   
+ ...                 ...               ...                ...   
+ 20237                20         35.879517                  N   
+ 20238                25         59.880066                  N   
+ 20239                26         23.280945                  N   
+ 20240                26         23.280945                  N   
+ 20241                14         23.992310                  N   
+ 
+       Longitude degrees Longitude minutes Longitude seconds  \
+ 0                    14                11         59.278336   
+ 1                    14                12          8.280258   
+ 2                    14                11         58.200302   
+ 3                    14                12          3.600769   
+ 4                    14                12          1.798325   
+ ...                 ...               ...               ...   
+ 20237                20                 1         48.002472   
+ 20238                21                30          0.000000   
+ 20239                21                31         32.882538   
+ 20240                21                31         32.882538   
+ 20241                23                33         18.001099   
+ 
+        Longitude direction   Unit  Value type  
+ 0                        E  Bq/m3           =  
+ 1                        E  Bq/m3           =  
+ 2                        E  Bq/m3           =  
+ 3                        E  Bq/m3           =  
+ 4                        E  Bq/m3           =  
+ ...                    ...    ...         ...  
+ 20237                    E  Bq/m3           =  
+ 20238                    E  Bq/m3           =  
+ 20239                    E  Bq/m3           =  
+ 20240                    E  Bq/m3           =  
+ 20241                    E  Bq/m3           =  
+ 
+ [20242 rows x 27 columns],
+ 'sediment':              lon        lat  tot_depth        time  sed_type  sample nuclide  \
+ 0      10.850000  54.049999       22.0   866592000        58     842     be7   
+ 1      10.203300  54.415001       13.0   811641600        58    4064     be7   
+ 2      10.203300  54.415001       13.0   811641600        58    4069     be7   
+ 3      10.203300  54.415001       13.0   811641600        58    4074     be7   
+ 4      11.750000  54.416698       24.0   838512000        58    4535     be7   
+ ...          ...        ...        ...         ...       ...     ...     ...   
+ 37084  23.391199  65.277496       90.0  1283299200         2   37039   bi212   
+ 37085  23.391199  65.277496       90.0  1283299200         2   37048   bi212   
+ 37086  23.391199  65.277496       90.0  1283299200         2   37065   bi212   
+ 37087  23.391199  65.277496       90.0  1283299200         2   37074   bi212   
+ 37088  23.391199  65.277496       90.0  1283299200         2   37083   bi212   
+ 
+            value    _unc  _dl  ...  Latitude degrees Latitude minutes  \
+ 0      24.299999  7.7760    1  ...                54                2   
+ 1      45.500000  4.5500    1  ...                54               24   
+ 2       7.000000     NaN    2  ...                54               24   
+ 3       4.800000     NaN    2  ...                54               24   
+ 4       6.900000  1.9320    1  ...                54               25   
+ ...          ...     ...  ...  ...               ...              ...   
+ 37084  42.900002  6.1347    1  ...                65               16   
+ 37085  58.400002  6.1904    1  ...                65               16   
+ 37086  51.400002  5.9624    1  ...                65               16   
+ 37087  41.799999  5.4758    1  ...                65               16   
+ 37088  43.700001  3.4523    1  ...                65               16   
+ 
+       Latitude seconds Latitude direction Longitude degrees  \
+ 0            59.997253                  N                10   
+ 1            54.003296                  N                10   
+ 2            54.003296                  N                10   
+ 3            54.003296                  N                10   
+ 4             0.114441                  N                11   
+ ...                ...                ...               ...   
+ 37084        38.986816                  N                23   
+ 37085        38.986816                  N                23   
+ 37086        38.986816                  N                23   
+ 37087        38.986816                  N                23   
+ 37088        38.986816                  N                23   
+ 
+        Longitude minutes  Longitude seconds  Longitude direction    Unit  \
+ 0                     51           0.001373                    E  Bq/kgd   
+ 1                     12          11.881714                    E  Bq/kgd   
+ 2                     12          11.881714                    E  Bq/kgd   
+ 3                     12          11.881714                    E  Bq/kgd   
+ 4                     45           0.000000                    E  Bq/kgd   
+ ...                  ...                ...                  ...     ...   
+ 37084                 23          28.316803                    E  Bq/kgd   
+ 37085                 23          28.316803                    E  Bq/kgd   
+ 37086                 23          28.316803                    E  Bq/kgd   
+ 37087                 23          28.316803                    E  Bq/kgd   
+ 37088                 23          28.316803                    E  Bq/kgd   
+ 
+        Value type  
+ 0               =  
+ 1               =  
+ 2               <  
+ 3               <  
+ 4               =  
+ ...           ...  
+ 37084           =  
+ 37085           =  
+ 37086           =  
+ 37087           =  
+ 37088           =  
+ 
+ [37089 rows x 25 columns],
+ 'biota':            lon        lat  smp_depth        time  bio_group  species  \
+ 0      11.5000  54.080002        0.0   908755200         11       96   
+ 1      11.5000  54.080002        0.0   900547200         11       96   
+ 2      11.5000  54.080002        0.0   874540800         14      129   
+ 3      11.5000  54.080002        0.0   865900800         14      129   
+ 4      11.5000  54.080002        0.0   874886400         11       96   
+ ...        ...        ...        ...         ...        ...      ...   
+ 14868  12.0742  57.335201        0.0  1253145600         11       96   
+ 14869  12.0742  57.335201        0.0  1225670400         11       96   
+ 14870  12.0742  57.335201        0.0  1160352000         11       96   
+ 14871  12.0742  57.335201        0.0  1380240000         11       96   
+ 14872  12.0742  57.335201        0.0  1409788800         11       96   
+ 
+        body_part  sample nuclide   value  ...  Latitude degrees  \
+ 0             54     150     be7  46.500  ...                54   
+ 1             54     159     be7  66.500  ...                54   
+ 2              1     168     be7   5.430  ...                54   
+ 3              1     177     be7  13.700  ...                54   
+ 4             54     183     be7  11.300  ...                54   
+ ...          ...     ...     ...     ...  ...               ...   
+ 14868         54   11586   tl208   0.880  ...                57   
+ 14869         54   11598   tl208   0.770  ...                57   
+ 14870         54   11620   tl208   1.310  ...                57   
+ 14871         54   11766   tl208   0.668  ...                57   
+ 14872         54   11775   tl208   0.684  ...                57   
+ 
+        Latitude minutes  Latitude seconds Latitude direction  \
+ 0                     4         48.006592                  N   
+ 1                     4         48.006592                  N   
+ 2                     4         48.006592                  N   
+ 3                     4         48.006592                  N   
+ 4                     4         48.006592                  N   
+ ...                 ...               ...                ...   
+ 14868                20          6.724548                  N   
+ 14869                20          6.724548                  N   
+ 14870                20          6.724548                  N   
+ 14871                20          6.724548                  N   
+ 14872                20          6.724548                  N   
+ 
+       Longitude degrees Longitude minutes Longitude seconds  \
+ 0                    11                30          0.000000   
+ 1                    11                30          0.000000   
+ 2                    11                30          0.000000   
+ 3                    11                30          0.000000   
+ 4                    11                30          0.000000   
+ ...                 ...               ...               ...   
+ 14868                12                 4         27.118835   
+ 14869                12                 4         27.118835   
+ 14870                12                 4         27.118835   
+ 14871                12                 4         27.118835   
+ 14872                12                 4         27.118835   
+ 
+        Longitude direction    Unit  Value type  
+ 0                        E  Bq/kgd           =  
+ 1                        E  Bq/kgd           =  
+ 2                        E  Bq/kgd           =  
+ 3                        E  Bq/kgd           =  
+ 4                        E  Bq/kgd           <  
+ ...                    ...     ...         ...  
+ 14868                    E  Bq/kgd           =  
+ 14869                    E  Bq/kgd           =  
+ 14870                    E  Bq/kgd           =  
+ 14871                    E  Bq/kgd           =  
+ 14872                    E  Bq/kgd           =  
+ 
+ [14873 rows x 27 columns]}
+
+
+
+
+
+

Lookup : Biogroup

+

Biogroup is in netcdf but not in OPEN REfINE csv format. Should we include this in Netcdf?

+
+
+
+

Lookup : Species

+
+

source

+
+
+

get_species_lut

+
+
 get_species_lut ()
+
+
+

source

+
+
+

LookupSpeciesByIdCB

+
+
 LookupSpeciesByIdCB (fn_lut=<function get_species_lut>)
+
+

Lookup MARIS species by species_id.

+
+
dfs = netcdf4_to_df(fname_in)
+tfm = Transformer(dfs, cbs=[ReshapeWideToLong(),
+                            LookupTimeFromEncodedTime(cfg()),
+                            GetSampleTypeCB(),
+                            LookupNuclideByIdCB(),
+                            ConvertLonLatCB(), 
+                            LookupUnitByIdCB(),
+                            LookupValueTypeByIdCB(),
+                            LookupSpeciesByIdCB()
+                            ])
+tfm()
+
+
{'seawater':              lon        lat  smp_depth  tot_depth        time  sample  \
+ 0      14.199800  54.006001        0.0       11.0  1497744000      78   
+ 1      14.202300  54.006199        0.0       12.0  1339632000      83   
+ 2      14.199500  54.006302        0.0       12.0  1402876800      86   
+ 3      14.201000  54.006500        0.0       12.0  1278460800      91   
+ 4      14.200500  54.006668        0.0       12.0  1309910400     101   
+ ...          ...        ...        ...        ...         ...     ...   
+ 20237  20.030001  57.343300        0.0      236.0   524620800   14175   
+ 20238  21.500000  59.433300        0.0      156.0   555033600   15712   
+ 20239  21.525801  59.439800        0.0      160.0   585446400   15840   
+ 20240  21.525801  59.439800      150.0      160.0   585446400   15847   
+ 20241  23.555000  65.239998        0.0       73.0   587001600   20130   
+ 
+              nuclide      value       _unc  _dl  ...  Latitude degrees  \
+ 0                 h3   850.0000  59.669998    1  ...                54   
+ 1                 h3   970.0000  29.100000    1  ...                54   
+ 2                 h3   910.0000  24.570000    1  ...                54   
+ 3                 h3  1070.0000  21.400000    1  ...                54   
+ 4                 h3  1020.0000  20.400000    1  ...                54   
+ ...              ...        ...        ...  ...  ...               ...   
+ 20237  cm243_244_tot     0.0064   0.001280    1  ...                57   
+ 20238  cm243_244_tot     0.0045   0.000900    1  ...                59   
+ 20239  cm243_244_tot     0.0022   0.000660    1  ...                59   
+ 20240  cm243_244_tot     0.0064   0.001920    1  ...                59   
+ 20241  cm243_244_tot     0.0039   0.001170    1  ...                65   
+ 
+        Latitude minutes  Latitude seconds Latitude direction  \
+ 0                     0         21.601868                  N   
+ 1                     0         22.315979                  N   
+ 2                     0         22.686768                  N   
+ 3                     0         23.400879                  N   
+ 4                     0         24.005127                  N   
+ ...                 ...               ...                ...   
+ 20237                20         35.879517                  N   
+ 20238                25         59.880066                  N   
+ 20239                26         23.280945                  N   
+ 20240                26         23.280945                  N   
+ 20241                14         23.992310                  N   
+ 
+       Longitude degrees Longitude minutes Longitude seconds  \
+ 0                    14                11         59.278336   
+ 1                    14                12          8.280258   
+ 2                    14                11         58.200302   
+ 3                    14                12          3.600769   
+ 4                    14                12          1.798325   
+ ...                 ...               ...               ...   
+ 20237                20                 1         48.002472   
+ 20238                21                30          0.000000   
+ 20239                21                31         32.882538   
+ 20240                21                31         32.882538   
+ 20241                23                33         18.001099   
+ 
+        Longitude direction   Unit  Value type  
+ 0                        E  Bq/m3           =  
+ 1                        E  Bq/m3           =  
+ 2                        E  Bq/m3           =  
+ 3                        E  Bq/m3           =  
+ 4                        E  Bq/m3           =  
+ ...                    ...    ...         ...  
+ 20237                    E  Bq/m3           =  
+ 20238                    E  Bq/m3           =  
+ 20239                    E  Bq/m3           =  
+ 20240                    E  Bq/m3           =  
+ 20241                    E  Bq/m3           =  
+ 
+ [20242 rows x 27 columns],
+ 'sediment':              lon        lat  tot_depth        time  sed_type  sample nuclide  \
+ 0      10.850000  54.049999       22.0   866592000        58     842     be7   
+ 1      10.203300  54.415001       13.0   811641600        58    4064     be7   
+ 2      10.203300  54.415001       13.0   811641600        58    4069     be7   
+ 3      10.203300  54.415001       13.0   811641600        58    4074     be7   
+ 4      11.750000  54.416698       24.0   838512000        58    4535     be7   
+ ...          ...        ...        ...         ...       ...     ...     ...   
+ 37084  23.391199  65.277496       90.0  1283299200         2   37039   bi212   
+ 37085  23.391199  65.277496       90.0  1283299200         2   37048   bi212   
+ 37086  23.391199  65.277496       90.0  1283299200         2   37065   bi212   
+ 37087  23.391199  65.277496       90.0  1283299200         2   37074   bi212   
+ 37088  23.391199  65.277496       90.0  1283299200         2   37083   bi212   
+ 
+            value    _unc  _dl  ...  Latitude degrees Latitude minutes  \
+ 0      24.299999  7.7760    1  ...                54                2   
+ 1      45.500000  4.5500    1  ...                54               24   
+ 2       7.000000     NaN    2  ...                54               24   
+ 3       4.800000     NaN    2  ...                54               24   
+ 4       6.900000  1.9320    1  ...                54               25   
+ ...          ...     ...  ...  ...               ...              ...   
+ 37084  42.900002  6.1347    1  ...                65               16   
+ 37085  58.400002  6.1904    1  ...                65               16   
+ 37086  51.400002  5.9624    1  ...                65               16   
+ 37087  41.799999  5.4758    1  ...                65               16   
+ 37088  43.700001  3.4523    1  ...                65               16   
+ 
+       Latitude seconds Latitude direction Longitude degrees  \
+ 0            59.997253                  N                10   
+ 1            54.003296                  N                10   
+ 2            54.003296                  N                10   
+ 3            54.003296                  N                10   
+ 4             0.114441                  N                11   
+ ...                ...                ...               ...   
+ 37084        38.986816                  N                23   
+ 37085        38.986816                  N                23   
+ 37086        38.986816                  N                23   
+ 37087        38.986816                  N                23   
+ 37088        38.986816                  N                23   
+ 
+        Longitude minutes  Longitude seconds  Longitude direction    Unit  \
+ 0                     51           0.001373                    E  Bq/kgd   
+ 1                     12          11.881714                    E  Bq/kgd   
+ 2                     12          11.881714                    E  Bq/kgd   
+ 3                     12          11.881714                    E  Bq/kgd   
+ 4                     45           0.000000                    E  Bq/kgd   
+ ...                  ...                ...                  ...     ...   
+ 37084                 23          28.316803                    E  Bq/kgd   
+ 37085                 23          28.316803                    E  Bq/kgd   
+ 37086                 23          28.316803                    E  Bq/kgd   
+ 37087                 23          28.316803                    E  Bq/kgd   
+ 37088                 23          28.316803                    E  Bq/kgd   
+ 
+        Value type  
+ 0               =  
+ 1               =  
+ 2               <  
+ 3               <  
+ 4               =  
+ ...           ...  
+ 37084           =  
+ 37085           =  
+ 37086           =  
+ 37087           =  
+ 37088           =  
+ 
+ [37089 rows x 25 columns],
+ 'biota':            lon        lat  smp_depth        time  bio_group  species  \
+ 0      11.5000  54.080002        0.0   908755200         11       96   
+ 1      11.5000  54.080002        0.0   900547200         11       96   
+ 2      11.5000  54.080002        0.0   874540800         14      129   
+ 3      11.5000  54.080002        0.0   865900800         14      129   
+ 4      11.5000  54.080002        0.0   874886400         11       96   
+ ...        ...        ...        ...         ...        ...      ...   
+ 14868  12.0742  57.335201        0.0  1253145600         11       96   
+ 14869  12.0742  57.335201        0.0  1225670400         11       96   
+ 14870  12.0742  57.335201        0.0  1160352000         11       96   
+ 14871  12.0742  57.335201        0.0  1380240000         11       96   
+ 14872  12.0742  57.335201        0.0  1409788800         11       96   
+ 
+        body_part  sample nuclide   value  ...  Latitude minutes  \
+ 0             54     150     be7  46.500  ...                 4   
+ 1             54     159     be7  66.500  ...                 4   
+ 2              1     168     be7   5.430  ...                 4   
+ 3              1     177     be7  13.700  ...                 4   
+ 4             54     183     be7  11.300  ...                 4   
+ ...          ...     ...     ...     ...  ...               ...   
+ 14868         54   11586   tl208   0.880  ...                20   
+ 14869         54   11598   tl208   0.770  ...                20   
+ 14870         54   11620   tl208   1.310  ...                20   
+ 14871         54   11766   tl208   0.668  ...                20   
+ 14872         54   11775   tl208   0.684  ...                20   
+ 
+        Latitude seconds  Latitude direction Longitude degrees  \
+ 0             48.006592                   N                11   
+ 1             48.006592                   N                11   
+ 2             48.006592                   N                11   
+ 3             48.006592                   N                11   
+ 4             48.006592                   N                11   
+ ...                 ...                 ...               ...   
+ 14868          6.724548                   N                12   
+ 14869          6.724548                   N                12   
+ 14870          6.724548                   N                12   
+ 14871          6.724548                   N                12   
+ 14872          6.724548                   N                12   
+ 
+       Longitude minutes Longitude seconds Longitude direction    Unit  \
+ 0                    30          0.000000                   E  Bq/kgd   
+ 1                    30          0.000000                   E  Bq/kgd   
+ 2                    30          0.000000                   E  Bq/kgd   
+ 3                    30          0.000000                   E  Bq/kgd   
+ 4                    30          0.000000                   E  Bq/kgd   
+ ...                 ...               ...                 ...     ...   
+ 14868                 4         27.118835                   E  Bq/kgd   
+ 14869                 4         27.118835                   E  Bq/kgd   
+ 14870                 4         27.118835                   E  Bq/kgd   
+ 14871                 4         27.118835                   E  Bq/kgd   
+ 14872                 4         27.118835                   E  Bq/kgd   
+ 
+        Value type            Species  
+ 0               =  Fucus vesiculosus  
+ 1               =  Fucus vesiculosus  
+ 2               =     Mytilus edulis  
+ 3               =     Mytilus edulis  
+ 4               <  Fucus vesiculosus  
+ ...           ...                ...  
+ 14868           =  Fucus vesiculosus  
+ 14869           =  Fucus vesiculosus  
+ 14870           =  Fucus vesiculosus  
+ 14871           =  Fucus vesiculosus  
+ 14872           =  Fucus vesiculosus  
+ 
+ [14873 rows x 28 columns]}
+
+
+
+
+
+

Lookup : Body part

+
+

source

+
+
+

get_bodypart_lut

+
+
 get_bodypart_lut ()
+
+
+

source

+
+
+

LookupBodypartByIdCB

+
+
 LookupBodypartByIdCB (fn_lut=<function get_bodypart_lut>)
+
+

Lookup MARIS bodypart by bodypar_id.

+
+
dfs = netcdf4_to_df(fname_in)
+tfm = Transformer(dfs, cbs=[ReshapeWideToLong(),
+                            LookupTimeFromEncodedTime(cfg()),
+                            GetSampleTypeCB(),
+                            LookupNuclideByIdCB(),
+                            ConvertLonLatCB(), 
+                            LookupUnitByIdCB(),
+                            LookupValueTypeByIdCB(),
+                            LookupSpeciesByIdCB(),
+                            LookupBodypartByIdCB()
+                            ])
+tfm()
+
+
{'seawater':              lon        lat  smp_depth  tot_depth        time  sample  \
+ 0      14.199800  54.006001        0.0       11.0  1497744000      78   
+ 1      14.202300  54.006199        0.0       12.0  1339632000      83   
+ 2      14.199500  54.006302        0.0       12.0  1402876800      86   
+ 3      14.201000  54.006500        0.0       12.0  1278460800      91   
+ 4      14.200500  54.006668        0.0       12.0  1309910400     101   
+ ...          ...        ...        ...        ...         ...     ...   
+ 20237  20.030001  57.343300        0.0      236.0   524620800   14175   
+ 20238  21.500000  59.433300        0.0      156.0   555033600   15712   
+ 20239  21.525801  59.439800        0.0      160.0   585446400   15840   
+ 20240  21.525801  59.439800      150.0      160.0   585446400   15847   
+ 20241  23.555000  65.239998        0.0       73.0   587001600   20130   
+ 
+              nuclide      value       _unc  _dl  ...  Latitude degrees  \
+ 0                 h3   850.0000  59.669998    1  ...                54   
+ 1                 h3   970.0000  29.100000    1  ...                54   
+ 2                 h3   910.0000  24.570000    1  ...                54   
+ 3                 h3  1070.0000  21.400000    1  ...                54   
+ 4                 h3  1020.0000  20.400000    1  ...                54   
+ ...              ...        ...        ...  ...  ...               ...   
+ 20237  cm243_244_tot     0.0064   0.001280    1  ...                57   
+ 20238  cm243_244_tot     0.0045   0.000900    1  ...                59   
+ 20239  cm243_244_tot     0.0022   0.000660    1  ...                59   
+ 20240  cm243_244_tot     0.0064   0.001920    1  ...                59   
+ 20241  cm243_244_tot     0.0039   0.001170    1  ...                65   
+ 
+        Latitude minutes  Latitude seconds Latitude direction  \
+ 0                     0         21.601868                  N   
+ 1                     0         22.315979                  N   
+ 2                     0         22.686768                  N   
+ 3                     0         23.400879                  N   
+ 4                     0         24.005127                  N   
+ ...                 ...               ...                ...   
+ 20237                20         35.879517                  N   
+ 20238                25         59.880066                  N   
+ 20239                26         23.280945                  N   
+ 20240                26         23.280945                  N   
+ 20241                14         23.992310                  N   
+ 
+       Longitude degrees Longitude minutes Longitude seconds  \
+ 0                    14                11         59.278336   
+ 1                    14                12          8.280258   
+ 2                    14                11         58.200302   
+ 3                    14                12          3.600769   
+ 4                    14                12          1.798325   
+ ...                 ...               ...               ...   
+ 20237                20                 1         48.002472   
+ 20238                21                30          0.000000   
+ 20239                21                31         32.882538   
+ 20240                21                31         32.882538   
+ 20241                23                33         18.001099   
+ 
+        Longitude direction   Unit  Value type  
+ 0                        E  Bq/m3           =  
+ 1                        E  Bq/m3           =  
+ 2                        E  Bq/m3           =  
+ 3                        E  Bq/m3           =  
+ 4                        E  Bq/m3           =  
+ ...                    ...    ...         ...  
+ 20237                    E  Bq/m3           =  
+ 20238                    E  Bq/m3           =  
+ 20239                    E  Bq/m3           =  
+ 20240                    E  Bq/m3           =  
+ 20241                    E  Bq/m3           =  
+ 
+ [20242 rows x 27 columns],
+ 'sediment':              lon        lat  tot_depth        time  sed_type  sample nuclide  \
+ 0      10.850000  54.049999       22.0   866592000        58     842     be7   
+ 1      10.203300  54.415001       13.0   811641600        58    4064     be7   
+ 2      10.203300  54.415001       13.0   811641600        58    4069     be7   
+ 3      10.203300  54.415001       13.0   811641600        58    4074     be7   
+ 4      11.750000  54.416698       24.0   838512000        58    4535     be7   
+ ...          ...        ...        ...         ...       ...     ...     ...   
+ 37084  23.391199  65.277496       90.0  1283299200         2   37039   bi212   
+ 37085  23.391199  65.277496       90.0  1283299200         2   37048   bi212   
+ 37086  23.391199  65.277496       90.0  1283299200         2   37065   bi212   
+ 37087  23.391199  65.277496       90.0  1283299200         2   37074   bi212   
+ 37088  23.391199  65.277496       90.0  1283299200         2   37083   bi212   
+ 
+            value    _unc  _dl  ...  Latitude degrees Latitude minutes  \
+ 0      24.299999  7.7760    1  ...                54                2   
+ 1      45.500000  4.5500    1  ...                54               24   
+ 2       7.000000     NaN    2  ...                54               24   
+ 3       4.800000     NaN    2  ...                54               24   
+ 4       6.900000  1.9320    1  ...                54               25   
+ ...          ...     ...  ...  ...               ...              ...   
+ 37084  42.900002  6.1347    1  ...                65               16   
+ 37085  58.400002  6.1904    1  ...                65               16   
+ 37086  51.400002  5.9624    1  ...                65               16   
+ 37087  41.799999  5.4758    1  ...                65               16   
+ 37088  43.700001  3.4523    1  ...                65               16   
+ 
+       Latitude seconds Latitude direction Longitude degrees  \
+ 0            59.997253                  N                10   
+ 1            54.003296                  N                10   
+ 2            54.003296                  N                10   
+ 3            54.003296                  N                10   
+ 4             0.114441                  N                11   
+ ...                ...                ...               ...   
+ 37084        38.986816                  N                23   
+ 37085        38.986816                  N                23   
+ 37086        38.986816                  N                23   
+ 37087        38.986816                  N                23   
+ 37088        38.986816                  N                23   
+ 
+        Longitude minutes  Longitude seconds  Longitude direction    Unit  \
+ 0                     51           0.001373                    E  Bq/kgd   
+ 1                     12          11.881714                    E  Bq/kgd   
+ 2                     12          11.881714                    E  Bq/kgd   
+ 3                     12          11.881714                    E  Bq/kgd   
+ 4                     45           0.000000                    E  Bq/kgd   
+ ...                  ...                ...                  ...     ...   
+ 37084                 23          28.316803                    E  Bq/kgd   
+ 37085                 23          28.316803                    E  Bq/kgd   
+ 37086                 23          28.316803                    E  Bq/kgd   
+ 37087                 23          28.316803                    E  Bq/kgd   
+ 37088                 23          28.316803                    E  Bq/kgd   
+ 
+        Value type  
+ 0               =  
+ 1               =  
+ 2               <  
+ 3               <  
+ 4               =  
+ ...           ...  
+ 37084           =  
+ 37085           =  
+ 37086           =  
+ 37087           =  
+ 37088           =  
+ 
+ [37089 rows x 25 columns],
+ 'biota':            lon        lat  smp_depth        time  bio_group  species  \
+ 0      11.5000  54.080002        0.0   908755200         11       96   
+ 1      11.5000  54.080002        0.0   900547200         11       96   
+ 2      11.5000  54.080002        0.0   874540800         14      129   
+ 3      11.5000  54.080002        0.0   865900800         14      129   
+ 4      11.5000  54.080002        0.0   874886400         11       96   
+ ...        ...        ...        ...         ...        ...      ...   
+ 14868  12.0742  57.335201        0.0  1253145600         11       96   
+ 14869  12.0742  57.335201        0.0  1225670400         11       96   
+ 14870  12.0742  57.335201        0.0  1160352000         11       96   
+ 14871  12.0742  57.335201        0.0  1380240000         11       96   
+ 14872  12.0742  57.335201        0.0  1409788800         11       96   
+ 
+        body_part  sample nuclide   value  ...  Latitude seconds  \
+ 0             54     150     be7  46.500  ...         48.006592   
+ 1             54     159     be7  66.500  ...         48.006592   
+ 2              1     168     be7   5.430  ...         48.006592   
+ 3              1     177     be7  13.700  ...         48.006592   
+ 4             54     183     be7  11.300  ...         48.006592   
+ ...          ...     ...     ...     ...  ...               ...   
+ 14868         54   11586   tl208   0.880  ...          6.724548   
+ 14869         54   11598   tl208   0.770  ...          6.724548   
+ 14870         54   11620   tl208   1.310  ...          6.724548   
+ 14871         54   11766   tl208   0.668  ...          6.724548   
+ 14872         54   11775   tl208   0.684  ...          6.724548   
+ 
+        Latitude direction  Longitude degrees Longitude minutes  \
+ 0                       N                 11                30   
+ 1                       N                 11                30   
+ 2                       N                 11                30   
+ 3                       N                 11                30   
+ 4                       N                 11                30   
+ ...                   ...                ...               ...   
+ 14868                   N                 12                 4   
+ 14869                   N                 12                 4   
+ 14870                   N                 12                 4   
+ 14871                   N                 12                 4   
+ 14872                   N                 12                 4   
+ 
+       Longitude seconds Longitude direction    Unit  Value type  \
+ 0              0.000000                   E  Bq/kgd           =   
+ 1              0.000000                   E  Bq/kgd           =   
+ 2              0.000000                   E  Bq/kgd           =   
+ 3              0.000000                   E  Bq/kgd           =   
+ 4              0.000000                   E  Bq/kgd           <   
+ ...                 ...                 ...     ...         ...   
+ 14868         27.118835                   E  Bq/kgd           =   
+ 14869         27.118835                   E  Bq/kgd           =   
+ 14870         27.118835                   E  Bq/kgd           =   
+ 14871         27.118835                   E  Bq/kgd           =   
+ 14872         27.118835                   E  Bq/kgd           =   
+ 
+                  Species                 Body part  
+ 0      Fucus vesiculosus  Whole haptophytic plants  
+ 1      Fucus vesiculosus  Whole haptophytic plants  
+ 2         Mytilus edulis              Whole animal  
+ 3         Mytilus edulis              Whole animal  
+ 4      Fucus vesiculosus  Whole haptophytic plants  
+ ...                  ...                       ...  
+ 14868  Fucus vesiculosus  Whole haptophytic plants  
+ 14869  Fucus vesiculosus  Whole haptophytic plants  
+ 14870  Fucus vesiculosus  Whole haptophytic plants  
+ 14871  Fucus vesiculosus  Whole haptophytic plants  
+ 14872  Fucus vesiculosus  Whole haptophytic plants  
+ 
+ [14873 rows x 29 columns]}
+
+
+
+
+
+

Lookup : Sediment type

+
+

source

+
+
+

get_sediments_lut

+
+
 get_sediments_lut ()
+
+
+

source

+
+
+

LookupSedimentTypeByIdCB

+
+
 LookupSedimentTypeByIdCB (fn_lut=<function get_sediments_lut>)
+
+

Lookup MARIS sedtype by sedtype_id.

+
+
dfs = netcdf4_to_df(fname_in)
+tfm = Transformer(dfs, cbs=[ReshapeWideToLong(),
+                            LookupTimeFromEncodedTime(cfg()),
+                            GetSampleTypeCB(),
+                            LookupNuclideByIdCB(),
+                            ConvertLonLatCB(), 
+                            LookupUnitByIdCB(),
+                            LookupValueTypeByIdCB(),
+                            LookupSpeciesByIdCB(),
+                            LookupBodypartByIdCB(),
+                            LookupSedimentTypeByIdCB()
+                            ])
+tfm()
+
+
{'seawater':              lon        lat  smp_depth  tot_depth        time  sample  \
+ 0      14.199800  54.006001        0.0       11.0  1497744000      78   
+ 1      14.202300  54.006199        0.0       12.0  1339632000      83   
+ 2      14.199500  54.006302        0.0       12.0  1402876800      86   
+ 3      14.201000  54.006500        0.0       12.0  1278460800      91   
+ 4      14.200500  54.006668        0.0       12.0  1309910400     101   
+ ...          ...        ...        ...        ...         ...     ...   
+ 20237  20.030001  57.343300        0.0      236.0   524620800   14175   
+ 20238  21.500000  59.433300        0.0      156.0   555033600   15712   
+ 20239  21.525801  59.439800        0.0      160.0   585446400   15840   
+ 20240  21.525801  59.439800      150.0      160.0   585446400   15847   
+ 20241  23.555000  65.239998        0.0       73.0   587001600   20130   
+ 
+              nuclide      value       _unc  _dl  ...  Latitude degrees  \
+ 0                 h3   850.0000  59.669998    1  ...                54   
+ 1                 h3   970.0000  29.100000    1  ...                54   
+ 2                 h3   910.0000  24.570000    1  ...                54   
+ 3                 h3  1070.0000  21.400000    1  ...                54   
+ 4                 h3  1020.0000  20.400000    1  ...                54   
+ ...              ...        ...        ...  ...  ...               ...   
+ 20237  cm243_244_tot     0.0064   0.001280    1  ...                57   
+ 20238  cm243_244_tot     0.0045   0.000900    1  ...                59   
+ 20239  cm243_244_tot     0.0022   0.000660    1  ...                59   
+ 20240  cm243_244_tot     0.0064   0.001920    1  ...                59   
+ 20241  cm243_244_tot     0.0039   0.001170    1  ...                65   
+ 
+        Latitude minutes  Latitude seconds Latitude direction  \
+ 0                     0         21.601868                  N   
+ 1                     0         22.315979                  N   
+ 2                     0         22.686768                  N   
+ 3                     0         23.400879                  N   
+ 4                     0         24.005127                  N   
+ ...                 ...               ...                ...   
+ 20237                20         35.879517                  N   
+ 20238                25         59.880066                  N   
+ 20239                26         23.280945                  N   
+ 20240                26         23.280945                  N   
+ 20241                14         23.992310                  N   
+ 
+       Longitude degrees Longitude minutes Longitude seconds  \
+ 0                    14                11         59.278336   
+ 1                    14                12          8.280258   
+ 2                    14                11         58.200302   
+ 3                    14                12          3.600769   
+ 4                    14                12          1.798325   
+ ...                 ...               ...               ...   
+ 20237                20                 1         48.002472   
+ 20238                21                30          0.000000   
+ 20239                21                31         32.882538   
+ 20240                21                31         32.882538   
+ 20241                23                33         18.001099   
+ 
+        Longitude direction   Unit  Value type  
+ 0                        E  Bq/m3           =  
+ 1                        E  Bq/m3           =  
+ 2                        E  Bq/m3           =  
+ 3                        E  Bq/m3           =  
+ 4                        E  Bq/m3           =  
+ ...                    ...    ...         ...  
+ 20237                    E  Bq/m3           =  
+ 20238                    E  Bq/m3           =  
+ 20239                    E  Bq/m3           =  
+ 20240                    E  Bq/m3           =  
+ 20241                    E  Bq/m3           =  
+ 
+ [20242 rows x 27 columns],
+ 'sediment':              lon        lat  tot_depth        time  sed_type  sample nuclide  \
+ 0      10.850000  54.049999       22.0   866592000        58     842     be7   
+ 1      10.203300  54.415001       13.0   811641600        58    4064     be7   
+ 2      10.203300  54.415001       13.0   811641600        58    4069     be7   
+ 3      10.203300  54.415001       13.0   811641600        58    4074     be7   
+ 4      11.750000  54.416698       24.0   838512000        58    4535     be7   
+ ...          ...        ...        ...         ...       ...     ...     ...   
+ 37084  23.391199  65.277496       90.0  1283299200         2   37039   bi212   
+ 37085  23.391199  65.277496       90.0  1283299200         2   37048   bi212   
+ 37086  23.391199  65.277496       90.0  1283299200         2   37065   bi212   
+ 37087  23.391199  65.277496       90.0  1283299200         2   37074   bi212   
+ 37088  23.391199  65.277496       90.0  1283299200         2   37083   bi212   
+ 
+            value    _unc  _dl  ...  Latitude minutes Latitude seconds  \
+ 0      24.299999  7.7760    1  ...                 2        59.997253   
+ 1      45.500000  4.5500    1  ...                24        54.003296   
+ 2       7.000000     NaN    2  ...                24        54.003296   
+ 3       4.800000     NaN    2  ...                24        54.003296   
+ 4       6.900000  1.9320    1  ...                25         0.114441   
+ ...          ...     ...  ...  ...               ...              ...   
+ 37084  42.900002  6.1347    1  ...                16        38.986816   
+ 37085  58.400002  6.1904    1  ...                16        38.986816   
+ 37086  51.400002  5.9624    1  ...                16        38.986816   
+ 37087  41.799999  5.4758    1  ...                16        38.986816   
+ 37088  43.700001  3.4523    1  ...                16        38.986816   
+ 
+       Latitude direction Longitude degrees Longitude minutes  \
+ 0                      N                10                51   
+ 1                      N                10                12   
+ 2                      N                10                12   
+ 3                      N                10                12   
+ 4                      N                11                45   
+ ...                  ...               ...               ...   
+ 37084                  N                23                23   
+ 37085                  N                23                23   
+ 37086                  N                23                23   
+ 37087                  N                23                23   
+ 37088                  N                23                23   
+ 
+        Longitude seconds  Longitude direction    Unit Value type  \
+ 0               0.001373                    E  Bq/kgd          =   
+ 1              11.881714                    E  Bq/kgd          =   
+ 2              11.881714                    E  Bq/kgd          <   
+ 3              11.881714                    E  Bq/kgd          <   
+ 4               0.000000                    E  Bq/kgd          =   
+ ...                  ...                  ...     ...        ...   
+ 37084          28.316803                    E  Bq/kgd          =   
+ 37085          28.316803                    E  Bq/kgd          =   
+ 37086          28.316803                    E  Bq/kgd          =   
+ 37087          28.316803                    E  Bq/kgd          =   
+ 37088          28.316803                    E  Bq/kgd          =   
+ 
+        Sediment type  
+ 0           Pure mud  
+ 1           Pure mud  
+ 2           Pure mud  
+ 3           Pure mud  
+ 4           Pure mud  
+ ...              ...  
+ 37084         Gravel  
+ 37085         Gravel  
+ 37086         Gravel  
+ 37087         Gravel  
+ 37088         Gravel  
+ 
+ [37089 rows x 26 columns],
+ 'biota':            lon        lat  smp_depth        time  bio_group  species  \
+ 0      11.5000  54.080002        0.0   908755200         11       96   
+ 1      11.5000  54.080002        0.0   900547200         11       96   
+ 2      11.5000  54.080002        0.0   874540800         14      129   
+ 3      11.5000  54.080002        0.0   865900800         14      129   
+ 4      11.5000  54.080002        0.0   874886400         11       96   
+ ...        ...        ...        ...         ...        ...      ...   
+ 14868  12.0742  57.335201        0.0  1253145600         11       96   
+ 14869  12.0742  57.335201        0.0  1225670400         11       96   
+ 14870  12.0742  57.335201        0.0  1160352000         11       96   
+ 14871  12.0742  57.335201        0.0  1380240000         11       96   
+ 14872  12.0742  57.335201        0.0  1409788800         11       96   
+ 
+        body_part  sample nuclide   value  ...  Latitude seconds  \
+ 0             54     150     be7  46.500  ...         48.006592   
+ 1             54     159     be7  66.500  ...         48.006592   
+ 2              1     168     be7   5.430  ...         48.006592   
+ 3              1     177     be7  13.700  ...         48.006592   
+ 4             54     183     be7  11.300  ...         48.006592   
+ ...          ...     ...     ...     ...  ...               ...   
+ 14868         54   11586   tl208   0.880  ...          6.724548   
+ 14869         54   11598   tl208   0.770  ...          6.724548   
+ 14870         54   11620   tl208   1.310  ...          6.724548   
+ 14871         54   11766   tl208   0.668  ...          6.724548   
+ 14872         54   11775   tl208   0.684  ...          6.724548   
+ 
+        Latitude direction  Longitude degrees Longitude minutes  \
+ 0                       N                 11                30   
+ 1                       N                 11                30   
+ 2                       N                 11                30   
+ 3                       N                 11                30   
+ 4                       N                 11                30   
+ ...                   ...                ...               ...   
+ 14868                   N                 12                 4   
+ 14869                   N                 12                 4   
+ 14870                   N                 12                 4   
+ 14871                   N                 12                 4   
+ 14872                   N                 12                 4   
+ 
+       Longitude seconds Longitude direction    Unit  Value type  \
+ 0              0.000000                   E  Bq/kgd           =   
+ 1              0.000000                   E  Bq/kgd           =   
+ 2              0.000000                   E  Bq/kgd           =   
+ 3              0.000000                   E  Bq/kgd           =   
+ 4              0.000000                   E  Bq/kgd           <   
+ ...                 ...                 ...     ...         ...   
+ 14868         27.118835                   E  Bq/kgd           =   
+ 14869         27.118835                   E  Bq/kgd           =   
+ 14870         27.118835                   E  Bq/kgd           =   
+ 14871         27.118835                   E  Bq/kgd           =   
+ 14872         27.118835                   E  Bq/kgd           =   
+ 
+                  Species                 Body part  
+ 0      Fucus vesiculosus  Whole haptophytic plants  
+ 1      Fucus vesiculosus  Whole haptophytic plants  
+ 2         Mytilus edulis              Whole animal  
+ 3         Mytilus edulis              Whole animal  
+ 4      Fucus vesiculosus  Whole haptophytic plants  
+ ...                  ...                       ...  
+ 14868  Fucus vesiculosus  Whole haptophytic plants  
+ 14869  Fucus vesiculosus  Whole haptophytic plants  
+ 14870  Fucus vesiculosus  Whole haptophytic plants  
+ 14871  Fucus vesiculosus  Whole haptophytic plants  
+ 14872  Fucus vesiculosus  Whole haptophytic plants  
+ 
+ [14873 rows x 29 columns]}
+
+
+
+
+
+

Rename columns

+
+

source

+
+
+

get_renaming_rules_netcdf2OpenRefine

+
+
 get_renaming_rules_netcdf2OpenRefine ()
+
+
+
class SelectAndRenameColumnCB(Callback):
+    def __init__(self,
+                 fn_renaming_rules,
+                ):
+        fc.store_attr()
+    def __call__(self, tfm):
+        renaming = self.fn_renaming_rules()
+        for grp in tfm.dfs.keys():            
+            # get columns related to the grp (e.g. 'biota').
+            coi = [v for k, v in renaming.items() if grp in k]
+            # Join cols of interest
+            coi_rename = {}
+            for d in coi:
+                for k, v in d.items(): 
+                    coi_rename[k]=v
+            # list cols
+            cols = list(coi_rename.keys()) 
+            # select cols in df 
+            tfm.dfs[grp] = tfm.dfs[grp].loc[:, cols]
+            # Rename cols
+            tfm.dfs[grp].rename(columns=coi_rename, inplace=True)
+
+
+
dfs = netcdf4_to_df(fname_in)
+tfm = Transformer(dfs, cbs=[ReshapeWideToLong(),
+                            LookupTimeFromEncodedTime(cfg()),
+                            GetSampleTypeCB(),
+                            LookupNuclideByIdCB(),
+                            ConvertLonLatCB(), 
+                            LookupUnitByIdCB(),
+                            LookupValueTypeByIdCB(),
+                            LookupSpeciesByIdCB(),
+                            LookupBodypartByIdCB(),
+                            LookupSedimentTypeByIdCB(),
+                            SelectAndRenameColumnCB(get_renaming_rules_netcdf2OpenRefine)
+                            ])
+tfm()
+
+
{'seawater':       Sample type  Latitude degrees  Latitude minutes  Latitude seconds  \
+ 0        SEAWATER                54                 0         21.601868   
+ 1        SEAWATER                54                 0         22.315979   
+ 2        SEAWATER                54                 0         22.686768   
+ 3        SEAWATER                54                 0         23.400879   
+ 4        SEAWATER                54                 0         24.005127   
+ ...           ...               ...               ...               ...   
+ 20237    SEAWATER                57                20         35.879517   
+ 20238    SEAWATER                59                25         59.880066   
+ 20239    SEAWATER                59                26         23.280945   
+ 20240    SEAWATER                59                26         23.280945   
+ 20241    SEAWATER                65                14         23.992310   
+ 
+       Latitude direction  Longitude degrees  Longitude minutes  \
+ 0                      N                 14                 11   
+ 1                      N                 14                 12   
+ 2                      N                 14                 11   
+ 3                      N                 14                 12   
+ 4                      N                 14                 12   
+ ...                  ...                ...                ...   
+ 20237                  N                 20                  1   
+ 20238                  N                 21                 30   
+ 20239                  N                 21                 31   
+ 20240                  N                 21                 31   
+ 20241                  N                 23                 33   
+ 
+        Longitude seconds Longitude direction  Latitude decimal  ...  \
+ 0              59.278336                   E         54.006001  ...   
+ 1               8.280258                   E         54.006199  ...   
+ 2              58.200302                   E         54.006302  ...   
+ 3               3.600769                   E         54.006500  ...   
+ 4               1.798325                   E         54.006668  ...   
+ ...                  ...                 ...               ...  ...   
+ 20237          48.002472                   E         57.343300  ...   
+ 20238           0.000000                   E         59.433300  ...   
+ 20239          32.882538                   E         59.439800  ...   
+ 20240          32.882538                   E         59.439800  ...   
+ 20241          18.001099                   E         65.239998  ...   
+ 
+        Sampling start time    Nuclide Value type   Unit Activity or MDA  \
+ 0                 00:00:00         3H          =  Bq/m3        850.0000   
+ 1                 00:00:00         3H          =  Bq/m3        970.0000   
+ 2                 00:00:00         3H          =  Bq/m3        910.0000   
+ 3                 00:00:00         3H          =  Bq/m3       1070.0000   
+ 4                 00:00:00         3H          =  Bq/m3       1020.0000   
+ ...                    ...        ...        ...    ...             ...   
+ 20237             00:00:00  243_244Cm          =  Bq/m3          0.0064   
+ 20238             00:00:00  243_244Cm          =  Bq/m3          0.0045   
+ 20239             00:00:00  243_244Cm          =  Bq/m3          0.0022   
+ 20240             00:00:00  243_244Cm          =  Bq/m3          0.0064   
+ 20241             00:00:00  243_244Cm          =  Bq/m3          0.0039   
+ 
+       Uncertainty  Total depth  Sampling depth  Salinity  Temperature  
+ 0       59.669998         11.0             0.0      7.50          NaN  
+ 1       29.100000         12.0             0.0      6.77          NaN  
+ 2       24.570000         12.0             0.0      6.80          NaN  
+ 3       21.400000         12.0             0.0      5.82          NaN  
+ 4       20.400000         12.0             0.0      5.40          NaN  
+ ...           ...          ...             ...       ...          ...  
+ 20237    0.001280        236.0             0.0      6.90          NaN  
+ 20238    0.000900        156.0             0.0      6.75          NaN  
+ 20239    0.000660        160.0             0.0      5.83         20.4  
+ 20240    0.001920        160.0           150.0      9.77          3.9  
+ 20241    0.001170         73.0             0.0      3.10         15.6  
+ 
+ [20242 rows x 22 columns],
+ 'sediment':       Sample type  Latitude degrees  Latitude minutes  Latitude seconds  \
+ 0        SEDIMENT                54                 2         59.997253   
+ 1        SEDIMENT                54                24         54.003296   
+ 2        SEDIMENT                54                24         54.003296   
+ 3        SEDIMENT                54                24         54.003296   
+ 4        SEDIMENT                54                25          0.114441   
+ ...           ...               ...               ...               ...   
+ 37084    SEDIMENT                65                16         38.986816   
+ 37085    SEDIMENT                65                16         38.986816   
+ 37086    SEDIMENT                65                16         38.986816   
+ 37087    SEDIMENT                65                16         38.986816   
+ 37088    SEDIMENT                65                16         38.986816   
+ 
+       Latitude direction  Longitude degrees  Longitude minutes  \
+ 0                      N                 10                 51   
+ 1                      N                 10                 12   
+ 2                      N                 10                 12   
+ 3                      N                 10                 12   
+ 4                      N                 11                 45   
+ ...                  ...                ...                ...   
+ 37084                  N                 23                 23   
+ 37085                  N                 23                 23   
+ 37086                  N                 23                 23   
+ 37087                  N                 23                 23   
+ 37088                  N                 23                 23   
+ 
+        Longitude seconds Longitude direction  Latitude decimal  \
+ 0               0.001373                   E         54.049999   
+ 1              11.881714                   E         54.415001   
+ 2              11.881714                   E         54.415001   
+ 3              11.881714                   E         54.415001   
+ 4               0.000000                   E         54.416698   
+ ...                  ...                 ...               ...   
+ 37084          28.316803                   E         65.277496   
+ 37085          28.316803                   E         65.277496   
+ 37086          28.316803                   E         65.277496   
+ 37087          28.316803                   E         65.277496   
+ 37088          28.316803                   E         65.277496   
+ 
+        Longitude decimal Sampling start date Sampling start time Nuclide  \
+ 0              10.850000         18-Jun-1997            00:00:00     7Be   
+ 1              10.203300         21-Sep-1995            00:00:00     7Be   
+ 2              10.203300         21-Sep-1995            00:00:00     7Be   
+ 3              10.203300         21-Sep-1995            00:00:00     7Be   
+ 4              11.750000         28-Jul-1996            00:00:00     7Be   
+ ...                  ...                 ...                 ...     ...   
+ 37084          23.391199         01-Sep-2010            00:00:00   212Bi   
+ 37085          23.391199         01-Sep-2010            00:00:00   212Bi   
+ 37086          23.391199         01-Sep-2010            00:00:00   212Bi   
+ 37087          23.391199         01-Sep-2010            00:00:00   212Bi   
+ 37088          23.391199         01-Sep-2010            00:00:00   212Bi   
+ 
+       Value type    Unit  Activity or MDA  Uncertainty  Total depth  \
+ 0              =  Bq/kgd        24.299999       7.7760         22.0   
+ 1              =  Bq/kgd        45.500000       4.5500         13.0   
+ 2              <  Bq/kgd         7.000000          NaN         13.0   
+ 3              <  Bq/kgd         4.800000          NaN         13.0   
+ 4              =  Bq/kgd         6.900000       1.9320         24.0   
+ ...          ...     ...              ...          ...          ...   
+ 37084          =  Bq/kgd        42.900002       6.1347         90.0   
+ 37085          =  Bq/kgd        58.400002       6.1904         90.0   
+ 37086          =  Bq/kgd        51.400002       5.9624         90.0   
+ 37087          =  Bq/kgd        41.799999       5.4758         90.0   
+ 37088          =  Bq/kgd        43.700001       3.4523         90.0   
+ 
+       Sediment type  
+ 0          Pure mud  
+ 1          Pure mud  
+ 2          Pure mud  
+ 3          Pure mud  
+ 4          Pure mud  
+ ...             ...  
+ 37084        Gravel  
+ 37085        Gravel  
+ 37086        Gravel  
+ 37087        Gravel  
+ 37088        Gravel  
+ 
+ [37089 rows x 20 columns],
+ 'biota':       Sample type  Latitude degrees  Latitude minutes  Latitude seconds  \
+ 0           BIOTA                54                 4         48.006592   
+ 1           BIOTA                54                 4         48.006592   
+ 2           BIOTA                54                 4         48.006592   
+ 3           BIOTA                54                 4         48.006592   
+ 4           BIOTA                54                 4         48.006592   
+ ...           ...               ...               ...               ...   
+ 14868       BIOTA                57                20          6.724548   
+ 14869       BIOTA                57                20          6.724548   
+ 14870       BIOTA                57                20          6.724548   
+ 14871       BIOTA                57                20          6.724548   
+ 14872       BIOTA                57                20          6.724548   
+ 
+       Latitude direction  Longitude degrees  Longitude minutes  \
+ 0                      N                 11                 30   
+ 1                      N                 11                 30   
+ 2                      N                 11                 30   
+ 3                      N                 11                 30   
+ 4                      N                 11                 30   
+ ...                  ...                ...                ...   
+ 14868                  N                 12                  4   
+ 14869                  N                 12                  4   
+ 14870                  N                 12                  4   
+ 14871                  N                 12                  4   
+ 14872                  N                 12                  4   
+ 
+        Longitude seconds Longitude direction  Latitude decimal  ...  \
+ 0               0.000000                   E         54.080002  ...   
+ 1               0.000000                   E         54.080002  ...   
+ 2               0.000000                   E         54.080002  ...   
+ 3               0.000000                   E         54.080002  ...   
+ 4               0.000000                   E         54.080002  ...   
+ ...                  ...                 ...               ...  ...   
+ 14868          27.118835                   E         57.335201  ...   
+ 14869          27.118835                   E         57.335201  ...   
+ 14870          27.118835                   E         57.335201  ...   
+ 14871          27.118835                   E         57.335201  ...   
+ 14872          27.118835                   E         57.335201  ...   
+ 
+        Sampling start date Sampling start time Nuclide Value type    Unit  \
+ 0              19-Oct-1998            00:00:00     7Be          =  Bq/kgd   
+ 1              16-Jul-1998            00:00:00     7Be          =  Bq/kgd   
+ 2              18-Sep-1997            00:00:00     7Be          =  Bq/kgd   
+ 3              10-Jun-1997            00:00:00     7Be          =  Bq/kgd   
+ 4              22-Sep-1997            00:00:00     7Be          <  Bq/kgd   
+ ...                    ...                 ...     ...        ...     ...   
+ 14868          17-Sep-2009            00:00:00   208Tl          =  Bq/kgd   
+ 14869          03-Nov-2008            00:00:00   208Tl          =  Bq/kgd   
+ 14870          09-Oct-2006            00:00:00   208Tl          =  Bq/kgd   
+ 14871          27-Sep-2013            00:00:00   208Tl          =  Bq/kgd   
+ 14872          04-Sep-2014            00:00:00   208Tl          =  Bq/kgd   
+ 
+       Activity or MDA  Uncertainty            Species  \
+ 0              46.500     1.813500  Fucus vesiculosus   
+ 1              66.500     6.317500  Fucus vesiculosus   
+ 2               5.430     1.574700     Mytilus edulis   
+ 3              13.700     4.384000     Mytilus edulis   
+ 4              11.300     0.000000  Fucus vesiculosus   
+ ...               ...          ...                ...   
+ 14868           0.880     0.079200  Fucus vesiculosus   
+ 14869           0.770     0.069300  Fucus vesiculosus   
+ 14870           1.310     0.142790  Fucus vesiculosus   
+ 14871           0.668     0.057448  Fucus vesiculosus   
+ 14872           0.684     0.072504  Fucus vesiculosus   
+ 
+                       Body part bio_group  
+ 0      Whole haptophytic plants        11  
+ 1      Whole haptophytic plants        11  
+ 2                  Whole animal        14  
+ 3                  Whole animal        14  
+ 4      Whole haptophytic plants        11  
+ ...                         ...       ...  
+ 14868  Whole haptophytic plants        11  
+ 14869  Whole haptophytic plants        11  
+ 14870  Whole haptophytic plants        11  
+ 14871  Whole haptophytic plants        11  
+ 14872  Whole haptophytic plants        11  
+ 
+ [14873 rows x 21 columns]}
+
+
+
+
+
+

Encoding

+
+

source

+
+
+

encode

+
+
 encode (fname_in, fname_out, ref_id=-1, **kwargs)
+
+
+
encode(fname_in, fname_out, ref_id, verbose=False)
+
+
<marisco.serializers.OpenRefineCsvEncoder>
+
+
+
+
+
+

TODO

+

TODO Review Maris Nuclides lut. Cs127?

+

TODO: Should the var be called ‘detection limit’? Is ‘value type’ more appropriate?

+

TODO Biogroup not used in OPEN REfINE csv format. Confirm this

+

TODO Ask about Species dbo. Paul said there is a larger one.

+

TODO: Maintain sample (i.e. index) in the output.

+ + +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/img/logo.png b/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d211f4d6f82d2c6e59ee57faee3f18edb9ca8e3a GIT binary patch literal 106866 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 z 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 literal 0 HcmV?d00001 diff --git a/index.html b/index.html new file mode 100644 index 0000000..f1feed7 --- /dev/null +++ b/index.html @@ -0,0 +1,815 @@ + + + + + + + + + + +MARISCO – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

MARISCO

+
+ +
+
+ IAEA/MARIS data NetCDF encoders +
+
+ + +
+ + + + +
+ + + +
+ + + +

The IAEA Marine Radioactivity Information System (MARIS) allows free access to users to search and download the results of measurements of radioactivity in seawater, biota, sediment and suspended matter. MARIS is maintained and developed by the IAEA Environmental Laboratories in Monaco.

+

The current Python package offers command-line utilities for encoding MARIS harvested datasets into NetCDF or .csv formats. This allows to convert MARIS data into a format that is compatible with a wide range of scientific and data analysis tools.

+
+

Install

+

Now, to install marisco simply run

+
pip install marisco
+

Once successfully installed, run the following command:

+
maris_init
+

This command:

+
    +
  1. creates a .marisco/ directory containing various configuration/configurable files ((below)) in your /home directory
  2. +
  3. creates a configs.toml file containing default but configurable settings (default paths, …)
  4. +
  5. creates a configurable cdl.toml file used to generate a MARIS NetCDF4 CDL (Common Data Language) template;
  6. +
  7. downloads several MARIS DB nomenclature/lookup table into .marisco/lut/ directory
  8. +
  9. generate maris-template.nc, the MARIS NetCDF4 template generated from cdl.toml and use to encode MARIS datasets
  10. +
+ +
+

Zotero API key

+

Upon conversion, marisco will automatically retrieve the bibliographic metadata of each MARIS dataset from Zotero. To do so, you need to define the following environment variable ZOTERO_API_KEY containing the MARIS Zotero API key. Please contact the MARIS team to get your API key.

+
+
+
+

Getting started

+
+

Command line utilities

+

All commands accept a -h argument to get access to its documentation.

+
+

maris_init

+

Create configuration files, MARIS NetCDF CDL (Common Data Language) and donwload required lookup tables (nomenclatures).

+
+
+

maris_create_nc_template

+

Generate MARIS NetCDF template to be used when encoding datasets

+
+
+

maris_netcdfy

+

Encode MARIS dataset as NetCDF

+

Positional arguments:

+
    +
  • handler_name: Handler’s name (e.g helcom, …)
  • +
  • str: Path to dataset to encode
  • +
  • dest: Path to converted NetCDF4
  • +
+

Example:

+
maris_netcdfy helcom _data/accdb/mors/csv _data/output/helcom.nc
+
+
+
+
+

Development

+
+

FAQ

+
+

How is cdl.toml created & what it is used for?

+

A Python dictionary named CONFIGS_CDL specifying MARIS NetCDF attributes, variables, dimensions, … is defined in nbs/api/configs.ipynb in the first instance. Running the command maris_init will generate a toml version of it named .marisco/cdl.toml further used to create a MARIS NetCDF template named in .marisco/maris-template.nc.

+

Once marisco installed, further customization of the MARIS NetCDF template can be done directly through .marisco/cdl.toml file then running the command maris_create_nc_template.

+ + +
+
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..27675a7 --- /dev/null +++ b/robots.txt @@ -0,0 +1 @@ +Sitemap: https://franckalbinet.github.io/marisco/sitemap.xml diff --git a/search.json b/search.json new file mode 100644 index 0000000..2fb0db3 --- /dev/null +++ b/search.json @@ -0,0 +1,844 @@ +[ + { + "objectID": "handlers/maris_legacy.html", + "href": "handlers/maris_legacy.html", + "title": "MARIS Legacy", + "section": "", + "text": "Exported source\nfrom tqdm import tqdm\nfrom pathlib import Path\nimport fastcore.all as fc\nimport pandas as pd\nimport numpy as np\n\nfrom marisco.callbacks import (Callback, Transformer, SanitizeLonLatCB, EncodeTimeCB, ReshapeLongToWide)\nfrom marisco.metadata import (GlobAttrsFeeder, BboxCB, DepthRangeCB, TimeRangeCB, ZoteroCB, KeyValuePairCB)\nfrom marisco.configs import lut_path, cdl_cfg, cfg, nc_tpl_path, Enums, get_lut\nfrom marisco.serializers import NetCDFEncoder", + "crumbs": [ + "Handlers", + "MARIS Legacy" + ] + }, + { + "objectID": "handlers/maris_legacy.html#packages-import", + "href": "handlers/maris_legacy.html#packages-import", + "title": "MARIS Legacy", + "section": "", + "text": "Exported source\nfrom tqdm import tqdm\nfrom pathlib import Path\nimport fastcore.all as fc\nimport pandas as pd\nimport numpy as np\n\nfrom marisco.callbacks import (Callback, Transformer, SanitizeLonLatCB, EncodeTimeCB, ReshapeLongToWide)\nfrom marisco.metadata import (GlobAttrsFeeder, BboxCB, DepthRangeCB, TimeRangeCB, ZoteroCB, KeyValuePairCB)\nfrom marisco.configs import lut_path, cdl_cfg, cfg, nc_tpl_path, Enums, get_lut\nfrom marisco.serializers import NetCDFEncoder", + "crumbs": [ + "Handlers", + "MARIS Legacy" + ] + }, + { + "objectID": "handlers/maris_legacy.html#configuration-and-file-paths", + "href": "handlers/maris_legacy.html#configuration-and-file-paths", + "title": "MARIS Legacy", + "section": "Configuration and file paths", + "text": "Configuration and file paths\n\n\nExported source\nfname_in = Path().home() / 'pro/data/maris/MARIS_exportSample_20240313.txt'\ndir_dest = '../../_data/output/dump'", + "crumbs": [ + "Handlers", + "MARIS Legacy" + ] + }, + { + "objectID": "handlers/maris_legacy.html#utils", + "href": "handlers/maris_legacy.html#utils", + "title": "MARIS Legacy", + "section": "Utils", + "text": "Utils\n\nsource\n\nDataLoader\n\n DataLoader (fname:str)\n\nLoad specific MARIS dataset through its ref_id.\n\n\n\n\nType\nDetails\n\n\n\n\nfname\nstr\nPath to the MARIS global dump file\n\n\n\n\n\nExported source\nclass DataLoader:\n LUT = {\n 'Sediment': 'sediment', 'Seawater': 'seawater',\n 'Suspended matter': 'suspended-matter', 'Biota': 'biota'}\n\n def __init__(self, \n fname: str # Path to the MARIS global dump file\n ):\n \"Load specific MARIS dataset through its ref_id.\"\n self.fname = fname\n self.df = None # Lazy loading\n\n def _load_data(self):\n if self.df is None:\n self.df = pd.read_csv(self.fname, sep='\\t', encoding='ISO-8859-1')\n\n def __call__(self, \n ref_id: int # Reference ID of interest\n ) -> dict: # Dictionary of dataframes\n self._load_data()\n filtered_df = self.df[self.df.ref_id == ref_id]\n return {\n self.LUT[name]: grp\n for name, grp in filtered_df.groupby('samptype')\n if name in self.LUT\n }\n\n\n\nsource\n\n\nget_fname\n\n get_fname (dfs)\n\n\n\nExported source\ndef get_zotero_key(dfs):\n return dfs[next(iter(dfs))][['zoterourl']].iloc[0].values[0].split('/')[-1]\n\ndef get_fname(dfs):\n id, name = dfs[next(iter(dfs))][['ref_id', 'displaytext']].iloc[0]\n name = name.replace(',', '').replace('.', '').replace('-', ' ').split(' ')\n return '-'.join(([str(id)] + name)) + '.nc'\n\n\n\nsource\n\n\nget_zotero_key\n\n get_zotero_key (dfs)", + "crumbs": [ + "Handlers", + "MARIS Legacy" + ] + }, + { + "objectID": "handlers/maris_legacy.html#load-data", + "href": "handlers/maris_legacy.html#load-data", + "title": "MARIS Legacy", + "section": "Load data", + "text": "Load data\nLet’s get a quick look at the input MARIS dump:\n\ndf = pd.read_csv(fname_in, sep='\\t', encoding='ISO-8859-1')\n\nprint('# of unique refs: ', len(df.ref_id.unique()))\nprint('columns: ', df.columns)\ndf.head()\n\n# of unique refs: 526\ncolumns: Index(['ref_id', 'displaytext', 'samptype', 'nuclide_id', 'latitude',\n 'longitude', 'begperiod', 'endperiod', 'sampdepth', 'totdepth',\n 'uncertaint', 'unit_id', 'detection', 'area_id', 'species_id',\n 'biogroup_id', 'bodypar_id', 'sedtype_id', 'volume', 'salinity',\n 'temperatur', 'sampmet_id', 'prepmet_id', 'counmet_id', 'activity',\n 'zoterourl'],\n dtype='object')\n\n\n\n\n\n\n\n\n\nref_id\ndisplaytext\nsamptype\nnuclide_id\nlatitude\nlongitude\nbegperiod\nendperiod\nsampdepth\ntotdepth\n...\nbodypar_id\nsedtype_id\nvolume\nsalinity\ntemperatur\nsampmet_id\nprepmet_id\ncounmet_id\nactivity\nzoterourl\n\n\n\n\n0\n182\nUrban et al., 2015\nBiota\n33\n-35.140833\n117.604444\n2014-05-06 00:00:00\nNaN\n-1.0\nNaN\n...\n52\n0\nNaN\nNaN\nNaN\n0\n6\n20\n0.387\nhttps://www.zotero.org/groups/2432820/maris/it...\n\n\n1\n182\nUrban et al., 2015\nBiota\n47\n-35.140833\n117.604444\n2014-05-06 00:00:00\nNaN\n-1.0\nNaN\n...\n52\n0\nNaN\nNaN\nNaN\n0\n6\n5\n1.44\nhttps://www.zotero.org/groups/2432820/maris/it...\n\n\n2\n182\nUrban et al., 2015\nBiota\n31\n-16.466944\n123.535833\n2014-02-27 00:00:00\nNaN\n-1.0\nNaN\n...\n52\n0\nNaN\nNaN\nNaN\n0\n6\n20\n0.042\nhttps://www.zotero.org/groups/2432820/maris/it...\n\n\n3\n182\nUrban et al., 2015\nBiota\n33\n-16.466944\n123.535833\n2014-02-27 00:00:00\nNaN\n-1.0\nNaN\n...\n52\n0\nNaN\nNaN\nNaN\n0\n6\n20\n0.075\nhttps://www.zotero.org/groups/2432820/maris/it...\n\n\n4\n182\nUrban et al., 2015\nBiota\n47\n-16.466944\n123.535833\n2014-02-27 00:00:00\nNaN\n-1.0\nNaN\n...\n52\n0\nNaN\nNaN\nNaN\n0\n6\n5\n0.069\nhttps://www.zotero.org/groups/2432820/maris/it...\n\n\n\n\n5 rows × 26 columns\n\n\n\nLet’s checkout if we retrieve the expected keys (sample types) and associated dataframes:\n\ndataloader = DataLoader(fname_in)\nref_id = 100 # Some other ref_id examples: OSPAR: 191, HELCOM: 100, 717 (only seawater)\n\ndfs = dataloader(ref_id=ref_id)\nprint(f'keys: {dfs.keys()}')\ndfs['sediment'].head()\n\nkeys: dict_keys(['biota', 'seawater', 'sediment'])\n\n\n\n\n\n\n\n\n\nref_id\ndisplaytext\nsamptype\nnuclide_id\nlatitude\nlongitude\nbegperiod\nendperiod\nsampdepth\ntotdepth\n...\nbodypar_id\nsedtype_id\nvolume\nsalinity\ntemperatur\nsampmet_id\nprepmet_id\ncounmet_id\nactivity\nzoterourl\n\n\n\n\n549778\n100\nHELCOM MORS, 2018\nSediment\n17\n54.838333\n9.9\n1989-06-14 00:00:00\nNaN\n-1.0\n24.0\n...\n0\n59\nNaN\nNaN\nNaN\n0\n0\n0\n26.6\nhttps://www.zotero.org/groups/2432820/maris/it...\n\n\n549779\n100\nHELCOM MORS, 2018\nSediment\n24\n54.838333\n9.9\n1989-06-14 00:00:00\nNaN\n-1.0\n24.0\n...\n0\n59\nNaN\nNaN\nNaN\n0\n0\n0\n134.0\nhttps://www.zotero.org/groups/2432820/maris/it...\n\n\n549780\n100\nHELCOM MORS, 2018\nSediment\n24\n54.838333\n9.9\n1989-06-14 00:00:00\nNaN\n-1.0\n24.0\n...\n0\n59\nNaN\nNaN\nNaN\n0\n0\n0\n18.6\nhttps://www.zotero.org/groups/2432820/maris/it...\n\n\n549781\n100\nHELCOM MORS, 2018\nSediment\n31\n54.838333\n9.9\n1989-06-14 00:00:00\nNaN\n-1.0\n24.0\n...\n0\n59\nNaN\nNaN\nNaN\n0\n0\n0\n42.5\nhttps://www.zotero.org/groups/2432820/maris/it...\n\n\n549782\n100\nHELCOM MORS, 2018\nSediment\n31\n54.838333\n9.9\n1989-06-14 00:00:00\nNaN\n-1.0\n24.0\n...\n0\n59\nNaN\nNaN\nNaN\n0\n0\n0\n5.9\nhttps://www.zotero.org/groups/2432820/maris/it...\n\n\n\n\n5 rows × 26 columns", + "crumbs": [ + "Handlers", + "MARIS Legacy" + ] + }, + { + "objectID": "handlers/maris_legacy.html#data-transformation-pipeline", + "href": "handlers/maris_legacy.html#data-transformation-pipeline", + "title": "MARIS Legacy", + "section": "Data transformation pipeline", + "text": "Data transformation pipeline\n\nNormalize nuclide names\nRemap nuclide_id to MARIS radionuclide standard names:\n\nsource\n\n\nRemapRdnNameCB\n\n RemapRdnNameCB (fn_lut=<function <lambda>>)\n\nRemap to MARIS radionuclide names.\n\n\nExported source\nnuclide_id_to_name = lambda: get_lut(lut_path(), 'dbo_nuclide.xlsx', \n key='nc_name', value='nuclide_id',\n reverse=True)\n\n\n\n\nExported source\nclass RemapRdnNameCB(Callback):\n \"Remap to MARIS radionuclide names.\"\n def __init__(self, fn_lut=nuclide_id_to_name): fc.store_attr()\n def __call__(self, tfm):\n lut = self.fn_lut()\n for k in tfm.dfs.keys():\n tfm.dfs[k]['nuclide_id'] = tfm.dfs[k]['nuclide_id'].replace(lut)\n\n\n\ndfs = dataloader(ref_id=ref_id)\ntfm = Transformer(dfs, cbs=[RemapRdnNameCB()])\n\nprint(tfm()['sediment']['nuclide_id'].unique())\n\n['ru106' 'sb125' 'cs134' 'cs137' 'k40' 'co60' 'ag110m' 'ra226' 'th232'\n 'pb212' 'pb214' 'pu238' 'am241' 'pu239_240_tot' 'zr95' 'mn54' 'ac228'\n 'u235' 'tl208' 'be7' 'bi214' 'ra223' 'ru103' 'sr90' 'eu155' 'ba140'\n 'co58' 'ra224' 'po210' 'ra228' 'th228' 'ce144' 'cs134_137_tot' 'pb210'\n 'pu239' 'cd109' 'bi212' 'pu238_240_tot' 'nb95' 'ir192' 'sb124' 'zn65'\n 'th234' 'pu241']\n\n\n\n\nRename columns\nRename MARIS dump columns to MARIS netCDF standard names:\n\ndfs['sediment'].columns\n\nIndex(['ref_id', 'displaytext', 'samptype', 'nuclide_id', 'latitude',\n 'longitude', 'begperiod', 'endperiod', 'sampdepth', 'totdepth',\n 'uncertaint', 'unit_id', 'detection', 'area_id', 'species_id',\n 'biogroup_id', 'bodypar_id', 'sedtype_id', 'volume', 'salinity',\n 'temperatur', 'sampmet_id', 'prepmet_id', 'counmet_id', 'activity',\n 'zoterourl'],\n dtype='object')\n\n\n\nsource\n\n\nrenaming_rules\n\n renaming_rules ()\n\nRename MARIS dump columns to MARIS netCDF standard names.\n\n\nExported source\ndef renaming_rules():\n \"Rename MARIS dump columns to MARIS netCDF standard names.\"\n vars = cdl_cfg()['vars']\n return {\n 'latitude': vars['defaults']['lat']['name'],\n 'longitude': vars['defaults']['lon']['name'],\n 'begperiod': vars['defaults']['time']['name'],\n 'sampdepth': vars['defaults']['smp_depth']['name'],\n 'totdepth': vars['defaults']['tot_depth']['name'],\n 'uncertaint': vars['suffixes']['uncertainty']['name'],\n 'unit_id': vars['suffixes']['unit']['name'],\n 'detection': vars['suffixes']['detection_limit']['name'],\n 'area_id': vars['defaults']['area']['name'], \n 'species_id': vars['bio']['species']['name'],\n 'biogroup_id': vars['bio']['bio_group']['name'],\n 'bodypar_id': vars['bio']['body_part']['name'],\n 'sedtype_id': vars['sed']['sed_type']['name'],\n 'volume': vars['suffixes']['volume']['name'],\n 'salinity': vars['suffixes']['salinity']['name'],\n 'temperatur': vars['suffixes']['temperature']['name'],\n 'sampmet_id': vars['suffixes']['sampling_method']['name'],\n 'prepmet_id': vars['suffixes']['preparation_method']['name'],\n 'counmet_id': vars['suffixes']['counting_method']['name'],\n 'activity': 'value',\n 'nuclide_id': 'nuclide'\n }\n\n\n\nsource\n\n\nRenameColumnCB\n\n RenameColumnCB (renaming_rules=<function renaming_rules>)\n\nRenaming variables to MARIS standard names.\n\n\nExported source\nclass RenameColumnCB(Callback):\n \"Renaming variables to MARIS standard names.\"\n def __init__(self, renaming_rules=renaming_rules): fc.store_attr()\n def __call__(self, tfm):\n lut = renaming_rules()\n coi = lut.keys()\n for k in tfm.dfs.keys():\n tfm.dfs[k] = tfm.dfs[k].loc[:, coi]\n tfm.dfs[k].rename(columns=lut, inplace=True)\n\n\n\ndfs = dataloader(ref_id=ref_id)\ntfm = Transformer(dfs, cbs=[\n RemapRdnNameCB(),\n RenameColumnCB()\n ])\n\nprint(tfm()['sediment'])\n\n lat lon time smp_depth tot_depth \\\n549778 54.838333 9.9 1989-06-14 00:00:00 -1.0 24.0 \n549779 54.838333 9.9 1989-06-14 00:00:00 -1.0 24.0 \n549780 54.838333 9.9 1989-06-14 00:00:00 -1.0 24.0 \n549781 54.838333 9.9 1989-06-14 00:00:00 -1.0 24.0 \n549782 54.838333 9.9 1989-06-14 00:00:00 -1.0 24.0 \n... ... ... ... ... ... \n1532415 57.619722 23.621389 2005-12-02 00:00:00 -1.0 55.0 \n1532416 57.619722 23.621389 2005-12-02 00:00:00 -1.0 55.0 \n1532417 57.619722 23.621389 2005-12-02 00:00:00 -1.0 55.0 \n1532418 57.619722 23.621389 2005-12-02 00:00:00 -1.0 55.0 \n1532419 57.619722 23.621389 2005-12-02 00:00:00 -1.0 55.0 \n\n _unc _unit _dl area species ... body_part sed_type _vol _sal \\\n549778 3.99 4 = 2374 0 ... 0 59 NaN NaN \n549779 NaN 2 = 2374 0 ... 0 59 NaN NaN \n549780 1.674 4 = 2374 0 ... 0 59 NaN NaN \n549781 NaN 2 = 2374 0 ... 0 59 NaN NaN \n549782 1.829 4 = 2374 0 ... 0 59 NaN NaN \n... ... ... .. ... ... ... ... ... ... ... \n1532415 86.2836 4 = 2409 0 ... 0 58 NaN NaN \n1532416 NaN 2 = 2409 0 ... 0 58 NaN NaN \n1532417 24.45552 4 = 2409 0 ... 0 58 NaN NaN \n1532418 NaN 2 = 2409 0 ... 0 58 NaN NaN \n1532419 123.2568 4 = 2409 0 ... 0 58 NaN NaN \n\n _temp _sampmet _prepmet _counmet value nuclide \n549778 NaN 0 0 0 26.6 ru106 \n549779 NaN 0 0 0 134.0 sb125 \n549780 NaN 0 0 0 18.6 sb125 \n549781 NaN 0 0 0 42.5 cs134 \n549782 NaN 0 0 0 5.9 cs134 \n... ... ... ... ... ... ... \n1532415 NaN 0 0 0 1106.2 k40 \n1532416 NaN 0 0 0 991.023 cs137 \n1532417 NaN 0 0 0 550.8 cs137 \n1532418 NaN 0 0 0 2461.36 k40 \n1532419 NaN 0 0 0 1368.0 k40 \n\n[123196 rows x 21 columns]\n\n\n\n\nDrop NaN only columns\n\nsource\n\n\nDropNAColumnsCB\n\n DropNAColumnsCB (na_value=0)\n\nDrop variable containing only NaN or ‘Not available’ (id=0 in MARIS lookup tables).\n\n\nExported source\nclass DropNAColumnsCB(Callback):\n \"Drop variable containing only NaN or 'Not available' (id=0 in MARIS lookup tables).\"\n def __init__(self, na_value=0): fc.store_attr()\n def isMarisNA(self, col): \n return len(col.unique()) == 1 and col.iloc[0] == self.na_value\n \n def dropMarisNA(self, df):\n na_cols = [col for col in df.columns if self.isMarisNA(df[col])]\n return df.drop(labels=na_cols, axis=1)\n \n def __call__(self, tfm):\n for k in tfm.dfs.keys():\n tfm.dfs[k] = tfm.dfs[k].dropna(axis=1, how='all')\n tfm.dfs[k] = self.dropMarisNA(tfm.dfs[k])\n\n\n\ndfs = dataloader(ref_id=ref_id)\ntfm = Transformer(dfs, cbs=[\n RemapRdnNameCB(),\n RenameColumnCB(),\n DropNAColumnsCB()\n ])\n\nprint(tfm()['sediment'])\n\n lat lon time smp_depth tot_depth \\\n549778 54.838333 9.9 1989-06-14 00:00:00 -1.0 24.0 \n549779 54.838333 9.9 1989-06-14 00:00:00 -1.0 24.0 \n549780 54.838333 9.9 1989-06-14 00:00:00 -1.0 24.0 \n549781 54.838333 9.9 1989-06-14 00:00:00 -1.0 24.0 \n549782 54.838333 9.9 1989-06-14 00:00:00 -1.0 24.0 \n... ... ... ... ... ... \n1532415 57.619722 23.621389 2005-12-02 00:00:00 -1.0 55.0 \n1532416 57.619722 23.621389 2005-12-02 00:00:00 -1.0 55.0 \n1532417 57.619722 23.621389 2005-12-02 00:00:00 -1.0 55.0 \n1532418 57.619722 23.621389 2005-12-02 00:00:00 -1.0 55.0 \n1532419 57.619722 23.621389 2005-12-02 00:00:00 -1.0 55.0 \n\n _unc _unit _dl area sed_type _sampmet _prepmet value nuclide \n549778 3.99 4 = 2374 59 0 0 26.6 ru106 \n549779 NaN 2 = 2374 59 0 0 134.0 sb125 \n549780 1.674 4 = 2374 59 0 0 18.6 sb125 \n549781 NaN 2 = 2374 59 0 0 42.5 cs134 \n549782 1.829 4 = 2374 59 0 0 5.9 cs134 \n... ... ... .. ... ... ... ... ... ... \n1532415 86.2836 4 = 2409 58 0 0 1106.2 k40 \n1532416 NaN 2 = 2409 58 0 0 991.023 cs137 \n1532417 24.45552 4 = 2409 58 0 0 550.8 cs137 \n1532418 NaN 2 = 2409 58 0 0 2461.36 k40 \n1532419 123.2568 4 = 2409 58 0 0 1368.0 k40 \n\n[123196 rows x 14 columns]\n\n\n\n\nRemap detection limit values\n\n\nExported source\ndl_name_to_id = lambda: get_lut(lut_path(), 'dbo_detectlimit.xlsx', key='name', value='id')\n\n\n\ndl_name_to_id()\n\n{'Not applicable': -1, 'Not Available': 0, '=': 1, '<': 2, 'ND': 3, 'DE': 4}\n\n\n\nsource\n\n\nSanitizeDetectionLimitCB\n\n SanitizeDetectionLimitCB (fn_lut=<function <lambda>>)\n\nAssign Detection Limit name to its id based on MARIS nomenclature.\n\n\nExported source\nclass SanitizeDetectionLimitCB(Callback):\n \"Assign Detection Limit name to its id based on MARIS nomenclature.\"\n def __init__(self,\n fn_lut=dl_name_to_id):\n fc.store_attr()\n self.var_name = cdl_cfg()['vars']['suffixes']['detection_limit']['name']\n\n def __call__(self, tfm):\n lut = self.fn_lut()\n for k in tfm.dfs.keys():\n tfm.dfs[k][self.var_name] = tfm.dfs[k][self.var_name].replace(lut)\n\n\n\ndfs = dataloader(ref_id=ref_id)\ntfm = Transformer(dfs, cbs=[\n RemapRdnNameCB(),\n RenameColumnCB(),\n DropNAColumnsCB(),\n SanitizeDetectionLimitCB()\n ])\n\nprint(tfm()['sediment']['_dl'])\n\n549778 1\n549779 1\n549780 1\n549781 1\n549782 1\n ..\n1532415 1\n1532416 1\n1532417 1\n1532418 1\n1532419 1\nName: _dl, Length: 123196, dtype: int64\n\n\n\n\nParse and encode time\nWe remind that in netCDF format time need to be encoded as integer representing the number of seconds since a time of reference. In our case we chose 1970-01-01 00:00:00.0 as defined in configs.ipynb.\n\nsource\n\n\nParseTimeCB\n\n ParseTimeCB ()\n\nBase class for callbacks.\n\n\nExported source\nclass ParseTimeCB(Callback):\n def __call__(self, tfm):\n for k in tfm.dfs.keys():\n tfm.dfs[k]['time'] = pd.to_datetime(tfm.dfs[k].time, format='ISO8601')\n\n\n\ndfs = dataloader(ref_id=ref_id)\ntfm = Transformer(dfs, cbs=[\n RemapRdnNameCB(),\n RenameColumnCB(),\n DropNAColumnsCB(),\n SanitizeDetectionLimitCB(),\n ParseTimeCB(),\n EncodeTimeCB(cfg())\n ])\n\nprint(tfm()['sediment'])\n\n lat lon time smp_depth tot_depth _unc _unit \\\n549778 54.838333 9.9 613785600 -1.0 24.0 3.99 4 \n549779 54.838333 9.9 613785600 -1.0 24.0 NaN 2 \n549780 54.838333 9.9 613785600 -1.0 24.0 1.674 4 \n549781 54.838333 9.9 613785600 -1.0 24.0 NaN 2 \n549782 54.838333 9.9 613785600 -1.0 24.0 1.829 4 \n... ... ... ... ... ... ... ... \n1532415 57.619722 23.621389 1133481600 -1.0 55.0 86.2836 4 \n1532416 57.619722 23.621389 1133481600 -1.0 55.0 NaN 2 \n1532417 57.619722 23.621389 1133481600 -1.0 55.0 24.45552 4 \n1532418 57.619722 23.621389 1133481600 -1.0 55.0 NaN 2 \n1532419 57.619722 23.621389 1133481600 -1.0 55.0 123.2568 4 \n\n _dl area sed_type _sampmet _prepmet value nuclide \n549778 1 2374 59 0 0 26.6 ru106 \n549779 1 2374 59 0 0 134.0 sb125 \n549780 1 2374 59 0 0 18.6 sb125 \n549781 1 2374 59 0 0 42.5 cs134 \n549782 1 2374 59 0 0 5.9 cs134 \n... ... ... ... ... ... ... ... \n1532415 1 2409 58 0 0 1106.2 k40 \n1532416 1 2409 58 0 0 991.023 cs137 \n1532417 1 2409 58 0 0 550.8 cs137 \n1532418 1 2409 58 0 0 2461.36 k40 \n1532419 1 2409 58 0 0 1368.0 k40 \n\n[123196 rows x 14 columns]\n\n\n\n\nReshape: long to wide\n\ndfs = dataloader(ref_id=ref_id)\ntfm = Transformer(dfs, cbs=[\n RemapRdnNameCB(),\n RenameColumnCB(),\n DropNAColumnsCB(),\n SanitizeDetectionLimitCB(),\n ParseTimeCB(),\n EncodeTimeCB(cfg()),\n ReshapeLongToWide()\n ])\n\nprint(tfm()['sediment'])\n\n lon time area lat smp_depth tot_depth \\\norg_index \n549834 9.633333 544838400 2374 54.850000 -1.0 16.0 \n549835 9.633333 544838400 2374 54.850000 -1.0 16.0 \n549836 9.633333 544838400 2374 54.850000 -1.0 16.0 \n549837 9.633333 544838400 2374 54.850000 -1.0 16.0 \n549838 9.633333 544838400 2374 54.850000 -1.0 16.0 \n... ... ... ... ... ... ... \n1518808 29.833333 1128211200 2407 59.983333 -1.0 0.0 \n1518809 29.833333 1128211200 2407 59.983333 -1.0 0.0 \n1518810 29.833333 1128211200 2407 59.983333 -1.0 0.0 \n1528756 29.833333 1128211200 2407 59.983333 -1.0 0.0 \n1528757 29.833333 1128211200 2407 59.983333 -1.0 0.0 \n\n sed_type ac228_dl ag110m_dl am241_dl ... sb124 sb125 sr90 \\\norg_index ... \n549834 58 NaN NaN NaN ... NaN NaN NaN \n549835 58 NaN NaN NaN ... NaN NaN NaN \n549836 58 NaN NaN NaN ... NaN NaN NaN \n549837 58 NaN NaN NaN ... NaN NaN NaN \n549838 58 NaN NaN NaN ... NaN NaN NaN \n... ... ... ... ... ... ... ... ... \n1518808 2 NaN NaN NaN ... NaN NaN NaN \n1518809 2 NaN NaN NaN ... NaN NaN NaN \n1518810 2 NaN NaN NaN ... NaN NaN NaN \n1528756 2 NaN NaN NaN ... NaN NaN NaN \n1528757 2 NaN NaN NaN ... NaN NaN NaN \n\n th228 th232 th234 tl208 u235 zn65 zr95 \norg_index \n549834 NaN NaN NaN NaN NaN NaN NaN \n549835 NaN NaN NaN NaN NaN NaN NaN \n549836 NaN NaN NaN NaN NaN NaN NaN \n549837 NaN NaN NaN NaN NaN NaN NaN \n549838 NaN NaN NaN NaN NaN NaN NaN \n... ... ... ... ... ... ... ... \n1518808 NaN NaN NaN NaN NaN NaN NaN \n1518809 NaN NaN NaN NaN NaN NaN NaN \n1518810 NaN NaN NaN NaN NaN NaN NaN \n1528756 NaN NaN NaN NaN NaN NaN NaN \n1528757 NaN NaN NaN NaN NaN NaN NaN \n\n[123196 rows x 270 columns]\n\n\n\n\nSanitize coordinates\n\ndfs = dataloader(ref_id=ref_id)\ntfm = Transformer(dfs, cbs=[\n RemapRdnNameCB(),\n RenameColumnCB(),\n DropNAColumnsCB(),\n SanitizeDetectionLimitCB(),\n ParseTimeCB(),\n EncodeTimeCB(cfg()),\n ReshapeLongToWide(),\n SanitizeLonLatCB()\n ])\n\ntfm()['sediment']\n\n\n\n\n\n\n\n\nlon\ntime\narea\nlat\nsmp_depth\ntot_depth\nsed_type\nac228_dl\nag110m_dl\nam241_dl\n...\nsb124\nsb125\nsr90\nth228\nth232\nth234\ntl208\nu235\nzn65\nzr95\n\n\norg_index\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n549834\n9.633333\n544838400\n2374\n54.850000\n-1.0\n16.0\n58\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n549835\n9.633333\n544838400\n2374\n54.850000\n-1.0\n16.0\n58\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n549836\n9.633333\n544838400\n2374\n54.850000\n-1.0\n16.0\n58\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n549837\n9.633333\n544838400\n2374\n54.850000\n-1.0\n16.0\n58\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n549838\n9.633333\n544838400\n2374\n54.850000\n-1.0\n16.0\n58\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n\n\n1518808\n29.833333\n1128211200\n2407\n59.983333\n-1.0\n0.0\n2\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n1518809\n29.833333\n1128211200\n2407\n59.983333\n-1.0\n0.0\n2\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n1518810\n29.833333\n1128211200\n2407\n59.983333\n-1.0\n0.0\n2\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n1528756\n29.833333\n1128211200\n2407\n59.983333\n-1.0\n0.0\n2\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n1528757\n29.833333\n1128211200\n2407\n59.983333\n-1.0\n0.0\n2\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n\n\n123196 rows × 270 columns", + "crumbs": [ + "Handlers", + "MARIS Legacy" + ] + }, + { + "objectID": "handlers/maris_legacy.html#encode-to-netcdf", + "href": "handlers/maris_legacy.html#encode-to-netcdf", + "title": "MARIS Legacy", + "section": "Encode to NetCDF", + "text": "Encode to NetCDF\n\ndfs = dataloader(ref_id=ref_id)\ntfm = Transformer(dfs, cbs=[\n RemapRdnNameCB(),\n RenameColumnCB(),\n DropNAColumnsCB(),\n SanitizeDetectionLimitCB(),\n ParseTimeCB(),\n EncodeTimeCB(cfg()),\n ReshapeLongToWide(),\n SanitizeLonLatCB()\n ])\n\ndfs_tfm = tfm()\ntfm.logs\n\n['Remap to MARIS radionuclide names.',\n 'Renaming variables to MARIS standard names.',\n \"Drop variable containing only NaN or 'Not available' (id=0 in MARIS lookup tables).\",\n 'Assign Detection Limit name to its id based on MARIS nomenclature.',\n 'Encode time as `int` representing seconds since xxx',\n 'Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator.']\n\n\n\nsource\n\nget_attrs\n\n get_attrs (tfm, zotero_key, kw=['oceanography', 'Earth Science > Oceans >\n Ocean Chemistry> Radionuclides', 'Earth Science > Human\n Dimensions > Environmental Impacts > Nuclear Radiation\n Exposure', 'Earth Science > Oceans > Ocean Chemistry > Ocean\n Tracers, Earth Science > Oceans > Marine Sediments', 'Earth\n Science > Oceans > Ocean Chemistry, Earth Science > Oceans >\n Sea Ice > Isotopes', 'Earth Science > Oceans > Water Quality >\n Ocean Contaminants', 'Earth Science > Biological\n Classification > Animals/Vertebrates > Fish', 'Earth Science >\n Biosphere > Ecosystems > Marine Ecosystems', 'Earth Science >\n Biological Classification > Animals/Invertebrates > Mollusks',\n 'Earth Science > Biological Classification >\n Animals/Invertebrates > Arthropods > Crustaceans', 'Earth\n Science > Biological Classification > Plants > Macroalgae\n (Seaweeds)'])\n\nRetrieve global attributes from MARIS dump.\n\n\nExported source\nkw = ['oceanography', 'Earth Science > Oceans > Ocean Chemistry> Radionuclides',\n 'Earth Science > Human Dimensions > Environmental Impacts > Nuclear Radiation Exposure',\n 'Earth Science > Oceans > Ocean Chemistry > Ocean Tracers, Earth Science > Oceans > Marine Sediments',\n 'Earth Science > Oceans > Ocean Chemistry, Earth Science > Oceans > Sea Ice > Isotopes',\n 'Earth Science > Oceans > Water Quality > Ocean Contaminants',\n 'Earth Science > Biological Classification > Animals/Vertebrates > Fish',\n 'Earth Science > Biosphere > Ecosystems > Marine Ecosystems',\n 'Earth Science > Biological Classification > Animals/Invertebrates > Mollusks',\n 'Earth Science > Biological Classification > Animals/Invertebrates > Arthropods > Crustaceans',\n 'Earth Science > Biological Classification > Plants > Macroalgae (Seaweeds)']\n\n\n\n\nExported source\ndef get_attrs(tfm, zotero_key, kw=kw):\n \"Retrieve global attributes from MARIS dump.\"\n return GlobAttrsFeeder(tfm.dfs, cbs=[\n BboxCB(),\n DepthRangeCB(),\n TimeRangeCB(cfg()),\n ZoteroCB(zotero_key, cfg=cfg()),\n KeyValuePairCB('keywords', ', '.join(kw)),\n KeyValuePairCB('publisher_postprocess_logs', ', '.join(tfm.logs))\n ])()\n\n\n\nget_attrs(tfm, zotero_key='3W354SQG', kw=kw)\n\n{'geospatial_lat_min': '30.435833333333335',\n 'geospatial_lat_max': '65.75',\n 'geospatial_lon_min': '9.633333333333333',\n 'geospatial_lon_max': '53.5',\n 'geospatial_bounds': 'POLYGON ((9.633333333333333 53.5, 30.435833333333335 53.5, 30.435833333333335 65.75, 9.633333333333333 65.75, 9.633333333333333 53.5))',\n 'time_coverage_start': '1984-01-10T00:00:00',\n 'time_coverage_end': '2018-12-14T00:00:00',\n 'title': 'Radioactivity Monitoring of the Irish Marine Environment 1991 and 1992',\n 'summary': '',\n 'creator_name': '[{\"creatorType\": \"author\", \"firstName\": \"A.\", \"lastName\": \"McGarry\"}, {\"creatorType\": \"author\", \"firstName\": \"S.\", \"lastName\": \"Lyons\"}, {\"creatorType\": \"author\", \"firstName\": \"C.\", \"lastName\": \"McEnri\"}, {\"creatorType\": \"author\", \"firstName\": \"T.\", \"lastName\": \"Ryan\"}, {\"creatorType\": \"author\", \"firstName\": \"M.\", \"lastName\": \"O\\'Colmain\"}, {\"creatorType\": \"author\", \"firstName\": \"J.D.\", \"lastName\": \"Cunningham\"}]',\n 'keywords': 'oceanography, Earth Science > Oceans > Ocean Chemistry> Radionuclides, Earth Science > Human Dimensions > Environmental Impacts > Nuclear Radiation Exposure, Earth Science > Oceans > Ocean Chemistry > Ocean Tracers, Earth Science > Oceans > Marine Sediments, Earth Science > Oceans > Ocean Chemistry, Earth Science > Oceans > Sea Ice > Isotopes, Earth Science > Oceans > Water Quality > Ocean Contaminants, Earth Science > Biological Classification > Animals/Vertebrates > Fish, Earth Science > Biosphere > Ecosystems > Marine Ecosystems, Earth Science > Biological Classification > Animals/Invertebrates > Mollusks, Earth Science > Biological Classification > Animals/Invertebrates > Arthropods > Crustaceans, Earth Science > Biological Classification > Plants > Macroalgae (Seaweeds)',\n 'publisher_postprocess_logs': \"Remap to MARIS radionuclide names., Renaming variables to MARIS standard names., Drop variable containing only NaN or 'Not available' (id=0 in MARIS lookup tables)., Assign Detection Limit name to its id based on MARIS nomenclature., Encode time as `int` representing seconds since xxx, Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator.\"}\n\n\n\nsource\n\n\nenums_xtra\n\n enums_xtra (tfm, vars)\n\nRetrieve a subset of the lengthy enum as species_t for instance\n\n\nExported source\ndef enums_xtra(tfm, vars):\n \"Retrieve a subset of the lengthy enum as `species_t` for instance\"\n enums = Enums(lut_src_dir=lut_path(), cdl_enums=cdl_cfg()['enums'])\n xtras = {}\n for var in vars:\n unique_vals = tfm.unique(var)\n if unique_vals.any():\n xtras[f'{var}_t'] = enums.filter(f'{var}_t', unique_vals)\n return xtras\n\n\n\nsource\n\n\nencode\n\n encode (fname_in, fname_out, nc_tpl_path, **kwargs)\n\n\n\nExported source\ndef encode(fname_in, fname_out, nc_tpl_path, **kwargs):\n dataloader = DataLoader(fname_in)\n ref_ids = kwargs.get('ref_ids', df.ref_id.unique())\n print('Encoding ...')\n for ref_id in tqdm(ref_ids, leave=False):\n dfs = dataloader(ref_id=ref_id)\n print(get_fname(dfs))\n tfm = Transformer(dfs, cbs=[\n RemapRdnNameCB(),\n RenameColumnCB(),\n DropNAColumnsCB(),\n SanitizeDetectionLimitCB(),\n ParseTimeCB(),\n EncodeTimeCB(cfg()),\n ReshapeLongToWide(),\n SanitizeLonLatCB(verbose=True)\n ])\n \n tfm()\n encoder = NetCDFEncoder(tfm.dfs, \n src_fname=nc_tpl_path,\n dest_fname=Path(fname_out) / get_fname(dfs), \n global_attrs=get_attrs(tfm, zotero_key=get_zotero_key(dfs), kw=kw),\n verbose=kwargs.get('verbose', False),\n enums_xtra=enums_xtra(tfm, vars=['species', 'body_part'])\n )\n encoder.encode()\n\n\n\n\nSingle dataset\n\ntfm = Transformer(dfs, cbs=[\n RemapRdnNameCB(),\n RenameColumnCB(),\n DropNAColumnsCB(),\n SanitizeDetectionLimitCB(),\n ParseTimeCB(),\n EncodeTimeCB(cfg()),\n ReshapeLongToWide(),\n SanitizeLonLatCB(verbose=True)\n ])\n\ndfs_test = tfm()\n\n\nref_id = 100\nencode(fname_in, dir_dest, nc_tpl_path(), verbose=True, ref_ids=[ref_id])\n\nEncoding ...\n\n\n 0%| | 0/1 [00:00<?, ?it/s]\n\n\n100-HELCOM-MORS-2018.nc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: lon\n--------------------------------------------------------------------------------\nGroup: biota, Variable: lat\n--------------------------------------------------------------------------------\nGroup: biota, Variable: smp_depth\n--------------------------------------------------------------------------------\nGroup: biota, Variable: time\n--------------------------------------------------------------------------------\nGroup: biota, Variable: area\n--------------------------------------------------------------------------------\nGroup: biota, Variable: bio_group\n--------------------------------------------------------------------------------\nGroup: biota, Variable: species\n--------------------------------------------------------------------------------\nGroup: biota, Variable: body_part\n--------------------------------------------------------------------------------\nGroup: biota, Variable: be7\n--------------------------------------------------------------------------------\nGroup: biota, Variable: be7_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: be7_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: be7_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: be7_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: be7_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: k40\n--------------------------------------------------------------------------------\nGroup: biota, Variable: k40_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: k40_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: k40_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: k40_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: k40_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: mn54\n--------------------------------------------------------------------------------\nGroup: biota, Variable: mn54_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: mn54_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: mn54_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: mn54_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: mn54_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co57\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co57_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co57_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co57_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co57_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co57_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co58\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co58_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co58_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co58_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co58_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co58_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co60\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co60_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co60_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co60_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co60_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: co60_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: zn65\n--------------------------------------------------------------------------------\nGroup: biota, Variable: zn65_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: zn65_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: zn65_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: zn65_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: zn65_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sr89\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sr89_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sr89_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sr89_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sr89_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sr89_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sr90\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sr90_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sr90_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sr90_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sr90_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sr90_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: zr95\n--------------------------------------------------------------------------------\nGroup: biota, Variable: zr95_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: zr95_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: zr95_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: zr95_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: zr95_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: nb95\n--------------------------------------------------------------------------------\nGroup: biota, Variable: nb95_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: nb95_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: nb95_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: nb95_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: nb95_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: tc99\n--------------------------------------------------------------------------------\nGroup: biota, Variable: tc99_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: tc99_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: tc99_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: tc99_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: tc99_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ru103\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ru103_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ru103_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ru103_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ru103_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ru103_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ru106\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ru106_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ru106_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ru106_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ru106_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ru106_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ag108m\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ag108m_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ag108m_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ag108m_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ag108m_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ag108m_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ag110m\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ag110m_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ag110m_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ag110m_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ag110m_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ag110m_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sb124\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sb124_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sb124_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sb124_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sb124_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sb124_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sb125\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sb125_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sb125_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sb125_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sb125_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sb125_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: te129m\n--------------------------------------------------------------------------------\nGroup: biota, Variable: te129m_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: te129m_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: te129m_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: te129m_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: i131\n--------------------------------------------------------------------------------\nGroup: biota, Variable: i131_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: i131_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: i131_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: i131_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs134\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs134_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs134_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs134_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs134_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs134_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs137\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs137_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs137_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs137_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs137_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs137_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ba140\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ba140_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ba140_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ba140_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ba140_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: la140\n--------------------------------------------------------------------------------\nGroup: biota, Variable: la140_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: la140_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: la140_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: la140_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ce141\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ce141_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ce141_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ce141_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ce141_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ce141_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ce144\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ce144_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ce144_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ce144_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ce144_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ce144_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: eu155\n--------------------------------------------------------------------------------\nGroup: biota, Variable: eu155_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: eu155_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: eu155_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: eu155_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: eu155_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb210\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb210_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb210_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb210_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb210_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb210_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb212\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb212_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb212_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb212_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb212_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb212_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb214\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb214_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb214_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb214_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb214_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pb214_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: bi214\n--------------------------------------------------------------------------------\nGroup: biota, Variable: bi214_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: bi214_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: bi214_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: bi214_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: bi214_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: po210\n--------------------------------------------------------------------------------\nGroup: biota, Variable: po210_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: po210_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: po210_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: po210_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: po210_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra223\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra223_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra223_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra223_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra223_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra223_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra224\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra224_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra224_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra224_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra224_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra224_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra226\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra226_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra226_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra226_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra226_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra226_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra228\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra228_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra228_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra228_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra228_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ra228_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ac228\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ac228_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ac228_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ac228_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ac228_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: ac228_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: th228\n--------------------------------------------------------------------------------\nGroup: biota, Variable: th228_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: th228_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: th228_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: th228_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: th228_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: th232\n--------------------------------------------------------------------------------\nGroup: biota, Variable: th232_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: th232_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: th232_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: th232_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: th232_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: u235\n--------------------------------------------------------------------------------\nGroup: biota, Variable: u235_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: u235_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: u235_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: u235_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: u235_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pu238\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pu238_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pu238_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pu238_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pu238_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pu238_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: am241\n--------------------------------------------------------------------------------\nGroup: biota, Variable: am241_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: am241_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: am241_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: am241_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: am241_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs134_137_tot\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs134_137_tot_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs134_137_tot_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs134_137_tot_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs134_137_tot_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: cs134_137_tot_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pu239_240_tot\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pu239_240_tot_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pu239_240_tot_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pu239_240_tot_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pu239_240_tot_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: pu239_240_tot_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: eu152\n--------------------------------------------------------------------------------\nGroup: biota, Variable: eu152_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: eu152_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: eu152_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: eu152_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: eu152_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: fe59\n--------------------------------------------------------------------------------\nGroup: biota, Variable: fe59_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: fe59_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: fe59_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: fe59_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: fe59_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: gd153\n--------------------------------------------------------------------------------\nGroup: biota, Variable: gd153_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: gd153_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: gd153_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: gd153_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: gd153_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: rb86\n--------------------------------------------------------------------------------\nGroup: biota, Variable: rb86_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: rb86_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: rb86_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: rb86_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: rb86_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sc46\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sc46_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sc46_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sc46_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sc46_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sc46_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sn113\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sn113_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sn113_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sn113_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sn113_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sn113_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sn117m\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sn117m_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sn117m_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sn117m_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sn117m_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: sn117m_unit\n--------------------------------------------------------------------------------\nGroup: biota, Variable: tl208\n--------------------------------------------------------------------------------\nGroup: biota, Variable: tl208_unc\n--------------------------------------------------------------------------------\nGroup: biota, Variable: tl208_dl\n--------------------------------------------------------------------------------\nGroup: biota, Variable: tl208_counmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: tl208_prepmet\n--------------------------------------------------------------------------------\nGroup: biota, Variable: tl208_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: lon\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: lat\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: smp_depth\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: tot_depth\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: time\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: area\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: h3\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: h3_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: h3_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: h3_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: h3_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: h3_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: h3_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: h3_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: h3_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: k40\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: k40_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: k40_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: k40_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: k40_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: k40_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: k40_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: k40_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: k40_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: mn54\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: mn54_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: mn54_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: mn54_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: mn54_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: mn54_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: mn54_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: mn54_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: co60\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: co60_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: co60_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: co60_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: co60_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: co60_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: co60_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: co60_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: co60_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr89\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr89_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr89_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr89_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr89_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr89_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr89_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr89_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr90\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr90_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr90_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr90_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr90_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr90_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr90_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr90_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sr90_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: zr95\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: zr95_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: zr95_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: zr95_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: zr95_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: zr95_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: zr95_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: zr95_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: nb95\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: nb95_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: nb95_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: nb95_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: nb95_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: nb95_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: nb95_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: nb95_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: nb95_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: tc99\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: tc99_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: tc99_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: tc99_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: tc99_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: tc99_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: tc99_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: tc99_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: tc99_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru103\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru103_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru103_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru103_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru103_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru103_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru103_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru103_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru103_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru106\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru106_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru106_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru106_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru106_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru106_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru106_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru106_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ru106_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ag110m\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ag110m_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ag110m_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ag110m_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ag110m_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ag110m_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ag110m_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ag110m_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sb125\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sb125_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sb125_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sb125_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sb125_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sb125_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sb125_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sb125_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: sb125_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs134\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs134_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs134_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs134_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs134_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs134_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs134_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs134_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs134_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs137\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs137_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs137_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs137_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs137_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs137_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs137_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs137_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cs137_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ba140\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ba140_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ba140_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ba140_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ba140_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ba140_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ba140_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ba140_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ce144\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ce144_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ce144_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ce144_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ce144_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ce144_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ce144_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: ce144_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pb210\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pb210_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pb210_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pb210_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pb210_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pb210_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pb210_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pb210_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pb210_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: po210\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: po210_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: po210_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: po210_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: po210_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: po210_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: po210_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: po210_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: po210_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u234\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u234_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u234_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u234_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u234_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u234_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u234_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u234_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u238\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u238_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u238_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u238_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u238_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u238_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u238_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: u238_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: np237\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: np237_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: np237_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: np237_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: np237_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: np237_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: np237_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: np237_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu238\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu238_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu238_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu238_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu238_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu238_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu238_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu238_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu238_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu240\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu240_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu240_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu240_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu240_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu240_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu240_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu240_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: am241\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: am241_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: am241_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: am241_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: am241_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: am241_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: am241_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: am241_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: am241_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm242\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm242_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm242_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm242_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm242_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm242_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm242_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm242_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm242_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm244\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm244_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm244_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm244_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm244_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm244_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm244_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm244_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm244_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_240_tot\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_240_tot_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_240_tot_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_240_tot_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_240_tot_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_240_tot_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_240_tot_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_240_tot_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: pu239_240_tot_unit\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm243_244_tot\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm243_244_tot_unc\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm243_244_tot_dl\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm243_244_tot_sal\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm243_244_tot_temp\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm243_244_tot_counmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm243_244_tot_sampmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm243_244_tot_prepmet\n--------------------------------------------------------------------------------\nGroup: seawater, Variable: cm243_244_tot_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: lon\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: lat\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: smp_depth\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: tot_depth\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: time\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: area\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sed_type\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: be7\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: be7_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: be7_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: be7_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: be7_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: be7_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: k40\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: k40_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: k40_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: k40_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: k40_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: k40_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: mn54\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: mn54_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: mn54_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: mn54_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: mn54_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: mn54_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: co58\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: co58_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: co58_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: co58_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: co58_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: co58_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: co60\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: co60_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: co60_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: co60_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: co60_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: co60_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: zn65\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: zn65_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: zn65_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: zn65_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: zn65_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: zn65_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sr90\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sr90_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sr90_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sr90_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sr90_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sr90_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: zr95\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: zr95_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: zr95_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: zr95_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: zr95_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: zr95_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: nb95\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: nb95_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: nb95_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: nb95_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: nb95_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: nb95_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ru103\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ru103_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ru103_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ru103_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ru103_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ru103_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ru106\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ru106_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ru106_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ru106_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ru106_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ru106_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ag110m\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ag110m_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ag110m_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ag110m_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ag110m_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ag110m_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sb124\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sb124_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sb124_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sb124_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sb124_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sb124_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sb125\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sb125_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sb125_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sb125_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sb125_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: sb125_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs134\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs134_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs134_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs134_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs134_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs134_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs137\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs137_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs137_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs137_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs137_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs137_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ba140\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ba140_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ba140_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ba140_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ba140_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ba140_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ce144\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ce144_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ce144_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ce144_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ce144_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ce144_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: eu155\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: eu155_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: eu155_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: eu155_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: eu155_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: eu155_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb210\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb210_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb210_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb210_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb210_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb210_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb212\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb212_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb212_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb212_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb212_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb212_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb214\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb214_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb214_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb214_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb214_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pb214_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: bi214\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: bi214_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: bi214_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: bi214_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: bi214_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: bi214_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: po210\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: po210_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: po210_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: po210_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: po210_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: po210_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra223\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra223_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra223_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra223_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra223_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra223_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra224\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra224_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra224_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra224_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra224_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra224_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra226\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra226_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra226_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra226_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra226_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra226_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra228\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra228_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra228_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra228_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra228_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ra228_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ac228\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ac228_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ac228_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ac228_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ac228_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ac228_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th228\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th228_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th228_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th228_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th228_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th228_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th232\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th232_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th232_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th232_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th232_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th232_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th234\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th234_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th234_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th234_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th234_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: th234_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: u235\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: u235_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: u235_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: u235_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: u235_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: u235_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu238\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu238_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu238_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu238_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu238_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu238_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu239\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu239_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu239_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu239_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu239_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu239_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu241\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu241_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu241_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu241_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu241_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu241_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: am241\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: am241_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: am241_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: am241_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: am241_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: am241_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs134_137_tot\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs134_137_tot_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs134_137_tot_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs134_137_tot_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs134_137_tot_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cs134_137_tot_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu239_240_tot\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu239_240_tot_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu239_240_tot_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu239_240_tot_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu239_240_tot_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu239_240_tot_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cd109\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cd109_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cd109_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cd109_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cd109_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: cd109_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ir192\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ir192_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ir192_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ir192_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ir192_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: ir192_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu238_240_tot\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu238_240_tot_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu238_240_tot_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu238_240_tot_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: pu238_240_tot_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: tl208\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: tl208_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: tl208_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: tl208_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: tl208_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: tl208_unit\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: bi212\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: bi212_unc\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: bi212_dl\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: bi212_sampmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: bi212_prepmet\n--------------------------------------------------------------------------------\nGroup: sediment, Variable: bi212_unit\n\n\n \n\n\n\n\nAll datasets\n\nencode(fname_in, dir_dest, nc_tpl_path(), verbose=False)", + "crumbs": [ + "Handlers", + "MARIS Legacy" + ] + }, + { + "objectID": "handlers/netcdf_to_csv.html#packages-import", + "href": "handlers/netcdf_to_csv.html#packages-import", + "title": "NetCDF to Open Refine CSV (WIP)", + "section": "Packages import", + "text": "Packages import\nGet the current working directory (cwd). .\n\nPath.cwd()\n\nPath('/Users/franckalbinet/pro/IAEA/MARIS/marisco/nbs/handlers')" + }, + { + "objectID": "handlers/netcdf_to_csv.html#load-netcdf", + "href": "handlers/netcdf_to_csv.html#load-netcdf", + "title": "NetCDF to Open Refine CSV (WIP)", + "section": "Load NetCDF", + "text": "Load NetCDF\n\nsource\n\nnetcdf4_to_df\n\n netcdf4_to_df (fname_in)\n\n\ndfs = netcdf4_to_df(fname_in)\ndfs\n\n\ndfs['seawater']\n\n\n\n\n\n\n\n\nlon\nlat\nsmp_depth\ntot_depth\ntime\nh3\nh3_unc\nh3_dl\nh3_sal\nh3_temp\n...\npu239_240_tot_dl\npu239_240_tot_sal\npu239_240_tot_temp\npu239_240_tot_unit\ncm243_244_tot\ncm243_244_tot_unc\ncm243_244_tot_dl\ncm243_244_tot_sal\ncm243_244_tot_temp\ncm243_244_tot_unit\n\n\nsample\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n0\n14.257800\n53.942200\n0.0\n10.0\n1339545600\nNaN\nNaN\n-1\nNaN\nNaN\n...\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\n\n\n1\n14.257800\n53.942200\n8.0\n10.0\n1339545600\nNaN\nNaN\n-1\nNaN\nNaN\n...\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\n\n\n2\n14.257800\n53.942200\n0.0\n10.0\n1339545600\nNaN\nNaN\n-1\nNaN\nNaN\n...\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\n\n\n3\n14.257800\n53.942200\n8.0\n10.0\n1339545600\nNaN\nNaN\n-1\nNaN\nNaN\n...\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\n\n\n4\n14.257800\n53.942200\n0.0\n9.0\n1370390400\nNaN\nNaN\n-1\nNaN\nNaN\n...\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\n\n\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n\n\n20237\n24.334999\n65.634697\n0.0\n17.0\n773971200\nNaN\nNaN\n-1\nNaN\nNaN\n...\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\n\n\n20238\n24.334999\n65.634697\n0.0\n17.0\n773971200\nNaN\nNaN\n-1\nNaN\nNaN\n...\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\n\n\n20239\n24.334999\n65.634697\n0.0\n17.0\n773971200\nNaN\nNaN\n-1\nNaN\nNaN\n...\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\n\n\n20240\n24.334999\n65.634697\n0.0\n17.0\n841190400\nNaN\nNaN\n-1\nNaN\nNaN\n...\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\n\n\n20241\n24.334999\n65.634697\n0.0\n17.0\n841190400\nNaN\nNaN\n-1\nNaN\nNaN\n...\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\nNaN\nNaN\n-1\n\n\n\n\n20242 rows × 175 columns\n\n\n\n\ndfs['biota']\n\n\n\n\n\n\n\n\nlon\nlat\nsmp_depth\ntime\nbio_group\nspecies\nbody_part\nbe7\nbe7_unc\nbe7_dl\n...\nsn113_dl\nsn113_unit\nsn117m\nsn117m_unc\nsn117m_dl\nsn117m_unit\ntl208\ntl208_unc\ntl208_dl\ntl208_unit\n\n\nsample\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n0\n14.300000\n53.500000\nNaN\n1443052800\n4\n247\n52\nNaN\nNaN\n-1\n...\n-1\n-1\nNaN\nNaN\n-1\n-1\nNaN\nNaN\n-1\n-1\n\n\n1\n14.300000\n53.500000\nNaN\n1443052800\n4\n247\n52\nNaN\nNaN\n-1\n...\n-1\n-1\nNaN\nNaN\n-1\n-1\nNaN\nNaN\n-1\n-1\n\n\n2\n14.300000\n53.500000\nNaN\n1443052800\n4\n247\n52\nNaN\nNaN\n-1\n...\n-1\n-1\nNaN\nNaN\n-1\n-1\nNaN\nNaN\n-1\n-1\n\n\n3\n14.300000\n53.500000\nNaN\n1443052800\n4\n247\n52\nNaN\nNaN\n-1\n...\n-1\n-1\nNaN\nNaN\n-1\n-1\nNaN\nNaN\n-1\n-1\n\n\n4\n14.300000\n53.500000\nNaN\n1443052800\n4\n247\n52\nNaN\nNaN\n-1\n...\n-1\n-1\nNaN\nNaN\n-1\n-1\nNaN\nNaN\n-1\n-1\n\n\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n\n\n14868\n23.000000\n65.716698\n0.0\n1127606400\n4\n50\n52\nNaN\nNaN\n-1\n...\n-1\n-1\nNaN\nNaN\n-1\n-1\nNaN\nNaN\n-1\n-1\n\n\n14869\n23.049999\n65.716698\n0.0\n1064016000\n4\n50\n52\nNaN\nNaN\n-1\n...\n-1\n-1\nNaN\nNaN\n-1\n-1\nNaN\nNaN\n-1\n-1\n\n\n14870\n23.049999\n65.716698\n0.0\n1064016000\n4\n50\n52\nNaN\nNaN\n-1\n...\n-1\n-1\nNaN\nNaN\n-1\n-1\nNaN\nNaN\n-1\n-1\n\n\n14871\n23.000000\n65.750000\n0.0\n1284940800\n4\n50\n52\nNaN\nNaN\n-1\n...\n-1\n-1\nNaN\nNaN\n-1\n-1\nNaN\nNaN\n-1\n-1\n\n\n14872\n23.000000\n65.750000\n0.0\n1284940800\n4\n50\n52\nNaN\nNaN\n-1\n...\n-1\n-1\nNaN\nNaN\n-1\n-1\nNaN\nNaN\n-1\n-1\n\n\n\n\n14873 rows × 211 columns" + }, + { + "objectID": "handlers/netcdf_to_csv.html#transform-data", + "href": "handlers/netcdf_to_csv.html#transform-data", + "title": "NetCDF to Open Refine CSV (WIP)", + "section": "Transform data", + "text": "Transform data\n\nReshape: wide to long\n\nsource\n\n\nReshapeWideToLong\n\n ReshapeWideToLong (columns='nuclide', values=['value'])\n\nConvert data from wide to long with renamed columns.\n\ndfs = netcdf4_to_df(fname_in)\ntfm = Transformer(dfs, cbs=[ReshapeWideToLong()])\ntfm()\n\n{'seawater': lon lat smp_depth tot_depth time sample \\\n 0 14.199800 54.006001 0.0 11.0 1497744000 78 \n 1 14.202300 54.006199 0.0 12.0 1339632000 83 \n 2 14.199500 54.006302 0.0 12.0 1402876800 86 \n 3 14.201000 54.006500 0.0 12.0 1278460800 91 \n 4 14.200500 54.006668 0.0 12.0 1309910400 101 \n ... ... ... ... ... ... ... \n 20237 20.030001 57.343300 0.0 236.0 524620800 14175 \n 20238 21.500000 59.433300 0.0 156.0 555033600 15712 \n 20239 21.525801 59.439800 0.0 160.0 585446400 15840 \n 20240 21.525801 59.439800 150.0 160.0 585446400 15847 \n 20241 23.555000 65.239998 0.0 73.0 587001600 20130 \n \n nuclide value _unc _dl _sal _temp _unit \n 0 h3 850.0000 59.669998 1 7.50 NaN 1 \n 1 h3 970.0000 29.100000 1 6.77 NaN 1 \n 2 h3 910.0000 24.570000 1 6.80 NaN 1 \n 3 h3 1070.0000 21.400000 1 5.82 NaN 1 \n 4 h3 1020.0000 20.400000 1 5.40 NaN 1 \n ... ... ... ... ... ... ... ... \n 20237 cm243_244_tot 0.0064 0.001280 1 6.90 NaN 1 \n 20238 cm243_244_tot 0.0045 0.000900 1 6.75 NaN 1 \n 20239 cm243_244_tot 0.0022 0.000660 1 5.83 20.4 1 \n 20240 cm243_244_tot 0.0064 0.001920 1 9.77 3.9 1 \n 20241 cm243_244_tot 0.0039 0.001170 1 3.10 15.6 1 \n \n [20242 rows x 13 columns],\n 'sediment': lon lat tot_depth time sed_type sample nuclide \\\n 0 10.850000 54.049999 22.0 866592000 58 842 be7 \n 1 10.203300 54.415001 13.0 811641600 58 4064 be7 \n 2 10.203300 54.415001 13.0 811641600 58 4069 be7 \n 3 10.203300 54.415001 13.0 811641600 58 4074 be7 \n 4 11.750000 54.416698 24.0 838512000 58 4535 be7 \n ... ... ... ... ... ... ... ... \n 37084 23.391199 65.277496 90.0 1283299200 2 37039 bi212 \n 37085 23.391199 65.277496 90.0 1283299200 2 37048 bi212 \n 37086 23.391199 65.277496 90.0 1283299200 2 37065 bi212 \n 37087 23.391199 65.277496 90.0 1283299200 2 37074 bi212 \n 37088 23.391199 65.277496 90.0 1283299200 2 37083 bi212 \n \n value _unc _dl _unit \n 0 24.299999 7.7760 1 4 \n 1 45.500000 4.5500 1 4 \n 2 7.000000 NaN 2 4 \n 3 4.800000 NaN 2 4 \n 4 6.900000 1.9320 1 4 \n ... ... ... ... ... \n 37084 42.900002 6.1347 1 4 \n 37085 58.400002 6.1904 1 4 \n 37086 51.400002 5.9624 1 4 \n 37087 41.799999 5.4758 1 4 \n 37088 43.700001 3.4523 1 4 \n \n [37089 rows x 11 columns],\n 'biota': lon lat smp_depth time bio_group species \\\n 0 11.5000 54.080002 0.0 908755200 11 96 \n 1 11.5000 54.080002 0.0 900547200 11 96 \n 2 11.5000 54.080002 0.0 874540800 14 129 \n 3 11.5000 54.080002 0.0 865900800 14 129 \n 4 11.5000 54.080002 0.0 874886400 11 96 \n ... ... ... ... ... ... ... \n 14868 12.0742 57.335201 0.0 1253145600 11 96 \n 14869 12.0742 57.335201 0.0 1225670400 11 96 \n 14870 12.0742 57.335201 0.0 1160352000 11 96 \n 14871 12.0742 57.335201 0.0 1380240000 11 96 \n 14872 12.0742 57.335201 0.0 1409788800 11 96 \n \n body_part sample nuclide value _unc _dl _unit \n 0 54 150 be7 46.500 1.813500 1 4 \n 1 54 159 be7 66.500 6.317500 1 4 \n 2 1 168 be7 5.430 1.574700 1 4 \n 3 1 177 be7 13.700 4.384000 1 4 \n 4 54 183 be7 11.300 0.000000 2 4 \n ... ... ... ... ... ... ... ... \n 14868 54 11586 tl208 0.880 0.079200 1 4 \n 14869 54 11598 tl208 0.770 0.069300 1 4 \n 14870 54 11620 tl208 1.310 0.142790 1 4 \n 14871 54 11766 tl208 0.668 0.057448 1 4 \n 14872 54 11775 tl208 0.684 0.072504 1 4 \n \n [14873 rows x 13 columns]}\n\n\n\ntfm.dfs['sediment']\n\n\n\n\n\n\n\n\nlon\nlat\ntot_depth\ntime\nsed_type\nsample\nnuclide\nvalue\n_unc\n_dl\n_unit\n\n\n\n\n0\n10.850000\n54.049999\n22.0\n866592000\n58\n842\nbe7\n24.299999\n7.7760\n1\n4\n\n\n1\n10.203300\n54.415001\n13.0\n811641600\n58\n4064\nbe7\n45.500000\n4.5500\n1\n4\n\n\n2\n10.203300\n54.415001\n13.0\n811641600\n58\n4069\nbe7\n7.000000\nNaN\n2\n4\n\n\n3\n10.203300\n54.415001\n13.0\n811641600\n58\n4074\nbe7\n4.800000\nNaN\n2\n4\n\n\n4\n11.750000\n54.416698\n24.0\n838512000\n58\n4535\nbe7\n6.900000\n1.9320\n1\n4\n\n\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n\n\n37084\n23.391199\n65.277496\n90.0\n1283299200\n2\n37039\nbi212\n42.900002\n6.1347\n1\n4\n\n\n37085\n23.391199\n65.277496\n90.0\n1283299200\n2\n37048\nbi212\n58.400002\n6.1904\n1\n4\n\n\n37086\n23.391199\n65.277496\n90.0\n1283299200\n2\n37065\nbi212\n51.400002\n5.9624\n1\n4\n\n\n37087\n23.391199\n65.277496\n90.0\n1283299200\n2\n37074\nbi212\n41.799999\n5.4758\n1\n4\n\n\n37088\n23.391199\n65.277496\n90.0\n1283299200\n2\n37083\nbi212\n43.700001\n3.4523\n1\n4\n\n\n\n\n37089 rows × 11 columns\n\n\n\n\n\n\nFormat: Time\n\nsource\n\n\nLookupTimeFromEncodedTime\n\n LookupTimeFromEncodedTime (cfg)\n\nBase class for callbacks.\n\ndfs = netcdf4_to_df(fname_in)\ntfm = Transformer(dfs, cbs=[ReshapeWideToLong(),\n LookupTimeFromEncodedTime(cfg())])\ntfm()\n\n{'seawater': lon lat smp_depth tot_depth time sample \\\n 0 14.199800 54.006001 0.0 11.0 1497744000 78 \n 1 14.202300 54.006199 0.0 12.0 1339632000 83 \n 2 14.199500 54.006302 0.0 12.0 1402876800 86 \n 3 14.201000 54.006500 0.0 12.0 1278460800 91 \n 4 14.200500 54.006668 0.0 12.0 1309910400 101 \n ... ... ... ... ... ... ... \n 20237 20.030001 57.343300 0.0 236.0 524620800 14175 \n 20238 21.500000 59.433300 0.0 156.0 555033600 15712 \n 20239 21.525801 59.439800 0.0 160.0 585446400 15840 \n 20240 21.525801 59.439800 150.0 160.0 585446400 15847 \n 20241 23.555000 65.239998 0.0 73.0 587001600 20130 \n \n nuclide value _unc _dl _sal _temp _unit \\\n 0 h3 850.0000 59.669998 1 7.50 NaN 1 \n 1 h3 970.0000 29.100000 1 6.77 NaN 1 \n 2 h3 910.0000 24.570000 1 6.80 NaN 1 \n 3 h3 1070.0000 21.400000 1 5.82 NaN 1 \n 4 h3 1020.0000 20.400000 1 5.40 NaN 1 \n ... ... ... ... ... ... ... ... \n 20237 cm243_244_tot 0.0064 0.001280 1 6.90 NaN 1 \n 20238 cm243_244_tot 0.0045 0.000900 1 6.75 NaN 1 \n 20239 cm243_244_tot 0.0022 0.000660 1 5.83 20.4 1 \n 20240 cm243_244_tot 0.0064 0.001920 1 9.77 3.9 1 \n 20241 cm243_244_tot 0.0039 0.001170 1 3.10 15.6 1 \n \n Sampling start date Sampling start time \n 0 18-Jun-2017 00:00:00 \n 1 14-Jun-2012 00:00:00 \n 2 16-Jun-2014 00:00:00 \n 3 07-Jul-2010 00:00:00 \n 4 06-Jul-2011 00:00:00 \n ... ... ... \n 20237 17-Aug-1986 00:00:00 \n 20238 04-Aug-1987 00:00:00 \n 20239 21-Jul-1988 00:00:00 \n 20240 21-Jul-1988 00:00:00 \n 20241 08-Aug-1988 00:00:00 \n \n [20242 rows x 15 columns],\n 'sediment': lon lat tot_depth time sed_type sample nuclide \\\n 0 10.850000 54.049999 22.0 866592000 58 842 be7 \n 1 10.203300 54.415001 13.0 811641600 58 4064 be7 \n 2 10.203300 54.415001 13.0 811641600 58 4069 be7 \n 3 10.203300 54.415001 13.0 811641600 58 4074 be7 \n 4 11.750000 54.416698 24.0 838512000 58 4535 be7 \n ... ... ... ... ... ... ... ... \n 37084 23.391199 65.277496 90.0 1283299200 2 37039 bi212 \n 37085 23.391199 65.277496 90.0 1283299200 2 37048 bi212 \n 37086 23.391199 65.277496 90.0 1283299200 2 37065 bi212 \n 37087 23.391199 65.277496 90.0 1283299200 2 37074 bi212 \n 37088 23.391199 65.277496 90.0 1283299200 2 37083 bi212 \n \n value _unc _dl _unit Sampling start date Sampling start time \n 0 24.299999 7.7760 1 4 18-Jun-1997 00:00:00 \n 1 45.500000 4.5500 1 4 21-Sep-1995 00:00:00 \n 2 7.000000 NaN 2 4 21-Sep-1995 00:00:00 \n 3 4.800000 NaN 2 4 21-Sep-1995 00:00:00 \n 4 6.900000 1.9320 1 4 28-Jul-1996 00:00:00 \n ... ... ... ... ... ... ... \n 37084 42.900002 6.1347 1 4 01-Sep-2010 00:00:00 \n 37085 58.400002 6.1904 1 4 01-Sep-2010 00:00:00 \n 37086 51.400002 5.9624 1 4 01-Sep-2010 00:00:00 \n 37087 41.799999 5.4758 1 4 01-Sep-2010 00:00:00 \n 37088 43.700001 3.4523 1 4 01-Sep-2010 00:00:00 \n \n [37089 rows x 13 columns],\n 'biota': lon lat smp_depth time bio_group species \\\n 0 11.5000 54.080002 0.0 908755200 11 96 \n 1 11.5000 54.080002 0.0 900547200 11 96 \n 2 11.5000 54.080002 0.0 874540800 14 129 \n 3 11.5000 54.080002 0.0 865900800 14 129 \n 4 11.5000 54.080002 0.0 874886400 11 96 \n ... ... ... ... ... ... ... \n 14868 12.0742 57.335201 0.0 1253145600 11 96 \n 14869 12.0742 57.335201 0.0 1225670400 11 96 \n 14870 12.0742 57.335201 0.0 1160352000 11 96 \n 14871 12.0742 57.335201 0.0 1380240000 11 96 \n 14872 12.0742 57.335201 0.0 1409788800 11 96 \n \n body_part sample nuclide value _unc _dl _unit \\\n 0 54 150 be7 46.500 1.813500 1 4 \n 1 54 159 be7 66.500 6.317500 1 4 \n 2 1 168 be7 5.430 1.574700 1 4 \n 3 1 177 be7 13.700 4.384000 1 4 \n 4 54 183 be7 11.300 0.000000 2 4 \n ... ... ... ... ... ... ... ... \n 14868 54 11586 tl208 0.880 0.079200 1 4 \n 14869 54 11598 tl208 0.770 0.069300 1 4 \n 14870 54 11620 tl208 1.310 0.142790 1 4 \n 14871 54 11766 tl208 0.668 0.057448 1 4 \n 14872 54 11775 tl208 0.684 0.072504 1 4 \n \n Sampling start date Sampling start time \n 0 19-Oct-1998 00:00:00 \n 1 16-Jul-1998 00:00:00 \n 2 18-Sep-1997 00:00:00 \n 3 10-Jun-1997 00:00:00 \n 4 22-Sep-1997 00:00:00 \n ... ... ... \n 14868 17-Sep-2009 00:00:00 \n 14869 03-Nov-2008 00:00:00 \n 14870 09-Oct-2006 00:00:00 \n 14871 27-Sep-2013 00:00:00 \n 14872 04-Sep-2014 00:00:00 \n \n [14873 rows x 15 columns]}\n\n\n\ntfm.dfs['seawater']['Sampling start date']\n\n0 18-Jun-2017\n1 14-Jun-2012\n2 16-Jun-2014\n3 07-Jul-2010\n4 06-Jul-2011\n ... \n20237 17-Aug-1986\n20238 04-Aug-1987\n20239 21-Jul-1988\n20240 21-Jul-1988\n20241 08-Aug-1988\nName: Sampling start date, Length: 20242, dtype: object\n\n\n\n\n\nLookup: Sample Type\n\nsource\n\n\nGetSampleTypeCB\n\n GetSampleTypeCB ()\n\nBase class for callbacks.\n\ndfs = netcdf4_to_df(fname_in)\ntfm = Transformer(dfs, cbs=[ReshapeWideToLong(),\n LookupTimeFromEncodedTime(cfg()),\n GetSampleTypeCB()])\ntfm()['biota']['Sample type']\n\n0 BIOTA\n1 BIOTA\n2 BIOTA\n3 BIOTA\n4 BIOTA\n ... \n14868 BIOTA\n14869 BIOTA\n14870 BIOTA\n14871 BIOTA\n14872 BIOTA\nName: Sample type, Length: 14873, dtype: object\n\n\n\n\n\nLookup : Nuclide\n\nsource\n\n\nget_nucnames_lut\n\n get_nucnames_lut ()\n\n\nsource\n\n\nLookupNuclideByIdCB\n\n LookupNuclideByIdCB (fn_lut=<function get_nucnames_lut>)\n\nLookup MARIS nuclide_id.\n\ndfs = netcdf4_to_df(fname_in)\ntfm = Transformer(dfs, cbs=[ReshapeWideToLong(),\n LookupTimeFromEncodedTime(cfg()),\n GetSampleTypeCB(),\n LookupNuclideByIdCB(),\n ])\ntfm()\n\n{'seawater': lon lat smp_depth tot_depth time sample \\\n 0 14.199800 54.006001 0.0 11.0 1497744000 78 \n 1 14.202300 54.006199 0.0 12.0 1339632000 83 \n 2 14.199500 54.006302 0.0 12.0 1402876800 86 \n 3 14.201000 54.006500 0.0 12.0 1278460800 91 \n 4 14.200500 54.006668 0.0 12.0 1309910400 101 \n ... ... ... ... ... ... ... \n 20237 20.030001 57.343300 0.0 236.0 524620800 14175 \n 20238 21.500000 59.433300 0.0 156.0 555033600 15712 \n 20239 21.525801 59.439800 0.0 160.0 585446400 15840 \n 20240 21.525801 59.439800 150.0 160.0 585446400 15847 \n 20241 23.555000 65.239998 0.0 73.0 587001600 20130 \n \n nuclide value _unc _dl _sal _temp _unit \\\n 0 h3 850.0000 59.669998 1 7.50 NaN 1 \n 1 h3 970.0000 29.100000 1 6.77 NaN 1 \n 2 h3 910.0000 24.570000 1 6.80 NaN 1 \n 3 h3 1070.0000 21.400000 1 5.82 NaN 1 \n 4 h3 1020.0000 20.400000 1 5.40 NaN 1 \n ... ... ... ... ... ... ... ... \n 20237 cm243_244_tot 0.0064 0.001280 1 6.90 NaN 1 \n 20238 cm243_244_tot 0.0045 0.000900 1 6.75 NaN 1 \n 20239 cm243_244_tot 0.0022 0.000660 1 5.83 20.4 1 \n 20240 cm243_244_tot 0.0064 0.001920 1 9.77 3.9 1 \n 20241 cm243_244_tot 0.0039 0.001170 1 3.10 15.6 1 \n \n Sampling start date Sampling start time Sample type Nuclide \n 0 18-Jun-2017 00:00:00 SEAWATER 3H \n 1 14-Jun-2012 00:00:00 SEAWATER 3H \n 2 16-Jun-2014 00:00:00 SEAWATER 3H \n 3 07-Jul-2010 00:00:00 SEAWATER 3H \n 4 06-Jul-2011 00:00:00 SEAWATER 3H \n ... ... ... ... ... \n 20237 17-Aug-1986 00:00:00 SEAWATER 243_244Cm \n 20238 04-Aug-1987 00:00:00 SEAWATER 243_244Cm \n 20239 21-Jul-1988 00:00:00 SEAWATER 243_244Cm \n 20240 21-Jul-1988 00:00:00 SEAWATER 243_244Cm \n 20241 08-Aug-1988 00:00:00 SEAWATER 243_244Cm \n \n [20242 rows x 17 columns],\n 'sediment': lon lat tot_depth time sed_type sample nuclide \\\n 0 10.850000 54.049999 22.0 866592000 58 842 be7 \n 1 10.203300 54.415001 13.0 811641600 58 4064 be7 \n 2 10.203300 54.415001 13.0 811641600 58 4069 be7 \n 3 10.203300 54.415001 13.0 811641600 58 4074 be7 \n 4 11.750000 54.416698 24.0 838512000 58 4535 be7 \n ... ... ... ... ... ... ... ... \n 37084 23.391199 65.277496 90.0 1283299200 2 37039 bi212 \n 37085 23.391199 65.277496 90.0 1283299200 2 37048 bi212 \n 37086 23.391199 65.277496 90.0 1283299200 2 37065 bi212 \n 37087 23.391199 65.277496 90.0 1283299200 2 37074 bi212 \n 37088 23.391199 65.277496 90.0 1283299200 2 37083 bi212 \n \n value _unc _dl _unit Sampling start date Sampling start time \\\n 0 24.299999 7.7760 1 4 18-Jun-1997 00:00:00 \n 1 45.500000 4.5500 1 4 21-Sep-1995 00:00:00 \n 2 7.000000 NaN 2 4 21-Sep-1995 00:00:00 \n 3 4.800000 NaN 2 4 21-Sep-1995 00:00:00 \n 4 6.900000 1.9320 1 4 28-Jul-1996 00:00:00 \n ... ... ... ... ... ... ... \n 37084 42.900002 6.1347 1 4 01-Sep-2010 00:00:00 \n 37085 58.400002 6.1904 1 4 01-Sep-2010 00:00:00 \n 37086 51.400002 5.9624 1 4 01-Sep-2010 00:00:00 \n 37087 41.799999 5.4758 1 4 01-Sep-2010 00:00:00 \n 37088 43.700001 3.4523 1 4 01-Sep-2010 00:00:00 \n \n Sample type Nuclide \n 0 SEDIMENT 7Be \n 1 SEDIMENT 7Be \n 2 SEDIMENT 7Be \n 3 SEDIMENT 7Be \n 4 SEDIMENT 7Be \n ... ... ... \n 37084 SEDIMENT 212Bi \n 37085 SEDIMENT 212Bi \n 37086 SEDIMENT 212Bi \n 37087 SEDIMENT 212Bi \n 37088 SEDIMENT 212Bi \n \n [37089 rows x 15 columns],\n 'biota': lon lat smp_depth time bio_group species \\\n 0 11.5000 54.080002 0.0 908755200 11 96 \n 1 11.5000 54.080002 0.0 900547200 11 96 \n 2 11.5000 54.080002 0.0 874540800 14 129 \n 3 11.5000 54.080002 0.0 865900800 14 129 \n 4 11.5000 54.080002 0.0 874886400 11 96 \n ... ... ... ... ... ... ... \n 14868 12.0742 57.335201 0.0 1253145600 11 96 \n 14869 12.0742 57.335201 0.0 1225670400 11 96 \n 14870 12.0742 57.335201 0.0 1160352000 11 96 \n 14871 12.0742 57.335201 0.0 1380240000 11 96 \n 14872 12.0742 57.335201 0.0 1409788800 11 96 \n \n body_part sample nuclide value _unc _dl _unit \\\n 0 54 150 be7 46.500 1.813500 1 4 \n 1 54 159 be7 66.500 6.317500 1 4 \n 2 1 168 be7 5.430 1.574700 1 4 \n 3 1 177 be7 13.700 4.384000 1 4 \n 4 54 183 be7 11.300 0.000000 2 4 \n ... ... ... ... ... ... ... ... \n 14868 54 11586 tl208 0.880 0.079200 1 4 \n 14869 54 11598 tl208 0.770 0.069300 1 4 \n 14870 54 11620 tl208 1.310 0.142790 1 4 \n 14871 54 11766 tl208 0.668 0.057448 1 4 \n 14872 54 11775 tl208 0.684 0.072504 1 4 \n \n Sampling start date Sampling start time Sample type Nuclide \n 0 19-Oct-1998 00:00:00 BIOTA 7Be \n 1 16-Jul-1998 00:00:00 BIOTA 7Be \n 2 18-Sep-1997 00:00:00 BIOTA 7Be \n 3 10-Jun-1997 00:00:00 BIOTA 7Be \n 4 22-Sep-1997 00:00:00 BIOTA 7Be \n ... ... ... ... ... \n 14868 17-Sep-2009 00:00:00 BIOTA 208Tl \n 14869 03-Nov-2008 00:00:00 BIOTA 208Tl \n 14870 09-Oct-2006 00:00:00 BIOTA 208Tl \n 14871 27-Sep-2013 00:00:00 BIOTA 208Tl \n 14872 04-Sep-2014 00:00:00 BIOTA 208Tl \n \n [14873 rows x 17 columns]}\n\n\n\ntfm.dfs['biota']['Nuclide'].unique()\n\narray(['7Be', '40K', '54Mn', '57Co', '58Co', '60Co', '65Zn', '89Sr',\n '90Sr', '95Zr', '95Nb', '99Tc', '103Ru', '106Ru', '108mAg',\n '110mAg', '124Sb', '125Sb', '129mTe', '131I', '134Cs', '137Cs',\n '140Ba', '140La', '141Ce', '144Ce', '155Eu', '210Pb', '212Pb',\n '214Pb', '214Bi', '210Po', '223Ra', '224Ra', '226Ra', '228Ra',\n '228Ac', '228Th', '232Th', '235U', '238Pu', '241Am', '134_137Cs',\n '239_240Pu', '152Eu', '59Fe', '153Gd', '86Rb', '46Sc', '113Sn',\n '117mSn', '208Tl'], dtype=object)\n\n\n\n\n\nFormat : Longitude and Latitude\nConvert from Longitude and Latitude DDD.DDDDD° to degrees, minutes, seconds and direction.\n\nsource\n\n\ndeg_to_dms\n\n deg_to_dms (deg, coordinate='lat')\n\nConvert from decimal degrees to degrees, minutes, seconds.\n\nsource\n\n\nConvertLonLatCB\n\n ConvertLonLatCB (fn_convert=<function deg_to_dms>)\n\nConvert from Longitude and Latitude DDD.DDDDD° to degrees, minutes, seconds and direction.\n\ndfs = netcdf4_to_df(fname_in)\ntfm = Transformer(dfs, cbs=[ReshapeWideToLong(),\n LookupTimeFromEncodedTime(cfg()),\n GetSampleTypeCB(),\n LookupNuclideByIdCB(),\n ConvertLonLatCB()\n ])\ntfm()\n\n{'seawater': lon lat smp_depth tot_depth time sample \\\n 0 14.199800 54.006001 0.0 11.0 1497744000 78 \n 1 14.202300 54.006199 0.0 12.0 1339632000 83 \n 2 14.199500 54.006302 0.0 12.0 1402876800 86 \n 3 14.201000 54.006500 0.0 12.0 1278460800 91 \n 4 14.200500 54.006668 0.0 12.0 1309910400 101 \n ... ... ... ... ... ... ... \n 20237 20.030001 57.343300 0.0 236.0 524620800 14175 \n 20238 21.500000 59.433300 0.0 156.0 555033600 15712 \n 20239 21.525801 59.439800 0.0 160.0 585446400 15840 \n 20240 21.525801 59.439800 150.0 160.0 585446400 15847 \n 20241 23.555000 65.239998 0.0 73.0 587001600 20130 \n \n nuclide value _unc _dl ... Sample type Nuclide \\\n 0 h3 850.0000 59.669998 1 ... SEAWATER 3H \n 1 h3 970.0000 29.100000 1 ... SEAWATER 3H \n 2 h3 910.0000 24.570000 1 ... SEAWATER 3H \n 3 h3 1070.0000 21.400000 1 ... SEAWATER 3H \n 4 h3 1020.0000 20.400000 1 ... SEAWATER 3H \n ... ... ... ... ... ... ... ... \n 20237 cm243_244_tot 0.0064 0.001280 1 ... SEAWATER 243_244Cm \n 20238 cm243_244_tot 0.0045 0.000900 1 ... SEAWATER 243_244Cm \n 20239 cm243_244_tot 0.0022 0.000660 1 ... SEAWATER 243_244Cm \n 20240 cm243_244_tot 0.0064 0.001920 1 ... SEAWATER 243_244Cm \n 20241 cm243_244_tot 0.0039 0.001170 1 ... SEAWATER 243_244Cm \n \n Latitude degrees Latitude minutes Latitude seconds Latitude direction \\\n 0 54 0 21.601868 N \n 1 54 0 22.315979 N \n 2 54 0 22.686768 N \n 3 54 0 23.400879 N \n 4 54 0 24.005127 N \n ... ... ... ... ... \n 20237 57 20 35.879517 N \n 20238 59 25 59.880066 N \n 20239 59 26 23.280945 N \n 20240 59 26 23.280945 N \n 20241 65 14 23.992310 N \n \n Longitude degrees Longitude minutes Longitude seconds \\\n 0 14 11 59.278336 \n 1 14 12 8.280258 \n 2 14 11 58.200302 \n 3 14 12 3.600769 \n 4 14 12 1.798325 \n ... ... ... ... \n 20237 20 1 48.002472 \n 20238 21 30 0.000000 \n 20239 21 31 32.882538 \n 20240 21 31 32.882538 \n 20241 23 33 18.001099 \n \n Longitude direction \n 0 E \n 1 E \n 2 E \n 3 E \n 4 E \n ... ... \n 20237 E \n 20238 E \n 20239 E \n 20240 E \n 20241 E \n \n [20242 rows x 25 columns],\n 'sediment': lon lat tot_depth time sed_type sample nuclide \\\n 0 10.850000 54.049999 22.0 866592000 58 842 be7 \n 1 10.203300 54.415001 13.0 811641600 58 4064 be7 \n 2 10.203300 54.415001 13.0 811641600 58 4069 be7 \n 3 10.203300 54.415001 13.0 811641600 58 4074 be7 \n 4 11.750000 54.416698 24.0 838512000 58 4535 be7 \n ... ... ... ... ... ... ... ... \n 37084 23.391199 65.277496 90.0 1283299200 2 37039 bi212 \n 37085 23.391199 65.277496 90.0 1283299200 2 37048 bi212 \n 37086 23.391199 65.277496 90.0 1283299200 2 37065 bi212 \n 37087 23.391199 65.277496 90.0 1283299200 2 37074 bi212 \n 37088 23.391199 65.277496 90.0 1283299200 2 37083 bi212 \n \n value _unc _dl ... Sample type Nuclide Latitude degrees \\\n 0 24.299999 7.7760 1 ... SEDIMENT 7Be 54 \n 1 45.500000 4.5500 1 ... SEDIMENT 7Be 54 \n 2 7.000000 NaN 2 ... SEDIMENT 7Be 54 \n 3 4.800000 NaN 2 ... SEDIMENT 7Be 54 \n 4 6.900000 1.9320 1 ... SEDIMENT 7Be 54 \n ... ... ... ... ... ... ... ... \n 37084 42.900002 6.1347 1 ... SEDIMENT 212Bi 65 \n 37085 58.400002 6.1904 1 ... SEDIMENT 212Bi 65 \n 37086 51.400002 5.9624 1 ... SEDIMENT 212Bi 65 \n 37087 41.799999 5.4758 1 ... SEDIMENT 212Bi 65 \n 37088 43.700001 3.4523 1 ... SEDIMENT 212Bi 65 \n \n Latitude minutes Latitude seconds Latitude direction \\\n 0 2 59.997253 N \n 1 24 54.003296 N \n 2 24 54.003296 N \n 3 24 54.003296 N \n 4 25 0.114441 N \n ... ... ... ... \n 37084 16 38.986816 N \n 37085 16 38.986816 N \n 37086 16 38.986816 N \n 37087 16 38.986816 N \n 37088 16 38.986816 N \n \n Longitude degrees Longitude minutes Longitude seconds \\\n 0 10 51 0.001373 \n 1 10 12 11.881714 \n 2 10 12 11.881714 \n 3 10 12 11.881714 \n 4 11 45 0.000000 \n ... ... ... ... \n 37084 23 23 28.316803 \n 37085 23 23 28.316803 \n 37086 23 23 28.316803 \n 37087 23 23 28.316803 \n 37088 23 23 28.316803 \n \n Longitude direction \n 0 E \n 1 E \n 2 E \n 3 E \n 4 E \n ... ... \n 37084 E \n 37085 E \n 37086 E \n 37087 E \n 37088 E \n \n [37089 rows x 23 columns],\n 'biota': lon lat smp_depth time bio_group species \\\n 0 11.5000 54.080002 0.0 908755200 11 96 \n 1 11.5000 54.080002 0.0 900547200 11 96 \n 2 11.5000 54.080002 0.0 874540800 14 129 \n 3 11.5000 54.080002 0.0 865900800 14 129 \n 4 11.5000 54.080002 0.0 874886400 11 96 \n ... ... ... ... ... ... ... \n 14868 12.0742 57.335201 0.0 1253145600 11 96 \n 14869 12.0742 57.335201 0.0 1225670400 11 96 \n 14870 12.0742 57.335201 0.0 1160352000 11 96 \n 14871 12.0742 57.335201 0.0 1380240000 11 96 \n 14872 12.0742 57.335201 0.0 1409788800 11 96 \n \n body_part sample nuclide value ... Sample type Nuclide \\\n 0 54 150 be7 46.500 ... BIOTA 7Be \n 1 54 159 be7 66.500 ... BIOTA 7Be \n 2 1 168 be7 5.430 ... BIOTA 7Be \n 3 1 177 be7 13.700 ... BIOTA 7Be \n 4 54 183 be7 11.300 ... BIOTA 7Be \n ... ... ... ... ... ... ... ... \n 14868 54 11586 tl208 0.880 ... BIOTA 208Tl \n 14869 54 11598 tl208 0.770 ... BIOTA 208Tl \n 14870 54 11620 tl208 1.310 ... BIOTA 208Tl \n 14871 54 11766 tl208 0.668 ... BIOTA 208Tl \n 14872 54 11775 tl208 0.684 ... BIOTA 208Tl \n \n Latitude degrees Latitude minutes Latitude seconds Latitude direction \\\n 0 54 4 48.006592 N \n 1 54 4 48.006592 N \n 2 54 4 48.006592 N \n 3 54 4 48.006592 N \n 4 54 4 48.006592 N \n ... ... ... ... ... \n 14868 57 20 6.724548 N \n 14869 57 20 6.724548 N \n 14870 57 20 6.724548 N \n 14871 57 20 6.724548 N \n 14872 57 20 6.724548 N \n \n Longitude degrees Longitude minutes Longitude seconds \\\n 0 11 30 0.000000 \n 1 11 30 0.000000 \n 2 11 30 0.000000 \n 3 11 30 0.000000 \n 4 11 30 0.000000 \n ... ... ... ... \n 14868 12 4 27.118835 \n 14869 12 4 27.118835 \n 14870 12 4 27.118835 \n 14871 12 4 27.118835 \n 14872 12 4 27.118835 \n \n Longitude direction \n 0 E \n 1 E \n 2 E \n 3 E \n 4 E \n ... ... \n 14868 E \n 14869 E \n 14870 E \n 14871 E \n 14872 E \n \n [14873 rows x 25 columns]}\n\n\n\ntfm.dfs['seawater'].columns\n\nIndex(['lon', 'lat', 'smp_depth', 'tot_depth', 'time', 'sample', 'nuclide',\n 'value', '_unc', '_dl', '_sal', '_temp', '_unit', 'Sampling start date',\n 'Sampling start time', 'Sample type', 'Nuclide', 'Latitude degrees',\n 'Latitude minutes', 'Latitude seconds', 'Latitude direction',\n 'Longitude degrees', 'Longitude minutes', 'Longitude seconds',\n 'Longitude direction'],\n dtype='object')\n\n\n\n\n\nLookup : Units\n\nsource\n\n\nget_unitnames_lut\n\n get_unitnames_lut ()\n\n\nsource\n\n\nLookupUnitByIdCB\n\n LookupUnitByIdCB (fn_lut=<function get_unitnames_lut>)\n\nLookup MARIS unit by unit_id.\n\ndfs = netcdf4_to_df(fname_in)\ntfm = Transformer(dfs, cbs=[ReshapeWideToLong(),\n LookupTimeFromEncodedTime(cfg()),\n GetSampleTypeCB(),\n LookupNuclideByIdCB(),\n ConvertLonLatCB(), \n LookupUnitByIdCB()\n ])\ntfm()\n\n{'seawater': lon lat smp_depth tot_depth time sample \\\n 0 14.199800 54.006001 0.0 11.0 1497744000 78 \n 1 14.202300 54.006199 0.0 12.0 1339632000 83 \n 2 14.199500 54.006302 0.0 12.0 1402876800 86 \n 3 14.201000 54.006500 0.0 12.0 1278460800 91 \n 4 14.200500 54.006668 0.0 12.0 1309910400 101 \n ... ... ... ... ... ... ... \n 20237 20.030001 57.343300 0.0 236.0 524620800 14175 \n 20238 21.500000 59.433300 0.0 156.0 555033600 15712 \n 20239 21.525801 59.439800 0.0 160.0 585446400 15840 \n 20240 21.525801 59.439800 150.0 160.0 585446400 15847 \n 20241 23.555000 65.239998 0.0 73.0 587001600 20130 \n \n nuclide value _unc _dl ... Nuclide \\\n 0 h3 850.0000 59.669998 1 ... 3H \n 1 h3 970.0000 29.100000 1 ... 3H \n 2 h3 910.0000 24.570000 1 ... 3H \n 3 h3 1070.0000 21.400000 1 ... 3H \n 4 h3 1020.0000 20.400000 1 ... 3H \n ... ... ... ... ... ... ... \n 20237 cm243_244_tot 0.0064 0.001280 1 ... 243_244Cm \n 20238 cm243_244_tot 0.0045 0.000900 1 ... 243_244Cm \n 20239 cm243_244_tot 0.0022 0.000660 1 ... 243_244Cm \n 20240 cm243_244_tot 0.0064 0.001920 1 ... 243_244Cm \n 20241 cm243_244_tot 0.0039 0.001170 1 ... 243_244Cm \n \n Latitude degrees Latitude minutes Latitude seconds Latitude direction \\\n 0 54 0 21.601868 N \n 1 54 0 22.315979 N \n 2 54 0 22.686768 N \n 3 54 0 23.400879 N \n 4 54 0 24.005127 N \n ... ... ... ... ... \n 20237 57 20 35.879517 N \n 20238 59 25 59.880066 N \n 20239 59 26 23.280945 N \n 20240 59 26 23.280945 N \n 20241 65 14 23.992310 N \n \n Longitude degrees Longitude minutes Longitude seconds \\\n 0 14 11 59.278336 \n 1 14 12 8.280258 \n 2 14 11 58.200302 \n 3 14 12 3.600769 \n 4 14 12 1.798325 \n ... ... ... ... \n 20237 20 1 48.002472 \n 20238 21 30 0.000000 \n 20239 21 31 32.882538 \n 20240 21 31 32.882538 \n 20241 23 33 18.001099 \n \n Longitude direction Unit \n 0 E Bq/m3 \n 1 E Bq/m3 \n 2 E Bq/m3 \n 3 E Bq/m3 \n 4 E Bq/m3 \n ... ... ... \n 20237 E Bq/m3 \n 20238 E Bq/m3 \n 20239 E Bq/m3 \n 20240 E Bq/m3 \n 20241 E Bq/m3 \n \n [20242 rows x 26 columns],\n 'sediment': lon lat tot_depth time sed_type sample nuclide \\\n 0 10.850000 54.049999 22.0 866592000 58 842 be7 \n 1 10.203300 54.415001 13.0 811641600 58 4064 be7 \n 2 10.203300 54.415001 13.0 811641600 58 4069 be7 \n 3 10.203300 54.415001 13.0 811641600 58 4074 be7 \n 4 11.750000 54.416698 24.0 838512000 58 4535 be7 \n ... ... ... ... ... ... ... ... \n 37084 23.391199 65.277496 90.0 1283299200 2 37039 bi212 \n 37085 23.391199 65.277496 90.0 1283299200 2 37048 bi212 \n 37086 23.391199 65.277496 90.0 1283299200 2 37065 bi212 \n 37087 23.391199 65.277496 90.0 1283299200 2 37074 bi212 \n 37088 23.391199 65.277496 90.0 1283299200 2 37083 bi212 \n \n value _unc _dl ... Nuclide Latitude degrees Latitude minutes \\\n 0 24.299999 7.7760 1 ... 7Be 54 2 \n 1 45.500000 4.5500 1 ... 7Be 54 24 \n 2 7.000000 NaN 2 ... 7Be 54 24 \n 3 4.800000 NaN 2 ... 7Be 54 24 \n 4 6.900000 1.9320 1 ... 7Be 54 25 \n ... ... ... ... ... ... ... ... \n 37084 42.900002 6.1347 1 ... 212Bi 65 16 \n 37085 58.400002 6.1904 1 ... 212Bi 65 16 \n 37086 51.400002 5.9624 1 ... 212Bi 65 16 \n 37087 41.799999 5.4758 1 ... 212Bi 65 16 \n 37088 43.700001 3.4523 1 ... 212Bi 65 16 \n \n Latitude seconds Latitude direction Longitude degrees \\\n 0 59.997253 N 10 \n 1 54.003296 N 10 \n 2 54.003296 N 10 \n 3 54.003296 N 10 \n 4 0.114441 N 11 \n ... ... ... ... \n 37084 38.986816 N 23 \n 37085 38.986816 N 23 \n 37086 38.986816 N 23 \n 37087 38.986816 N 23 \n 37088 38.986816 N 23 \n \n Longitude minutes Longitude seconds Longitude direction Unit \n 0 51 0.001373 E Bq/kgd \n 1 12 11.881714 E Bq/kgd \n 2 12 11.881714 E Bq/kgd \n 3 12 11.881714 E Bq/kgd \n 4 45 0.000000 E Bq/kgd \n ... ... ... ... ... \n 37084 23 28.316803 E Bq/kgd \n 37085 23 28.316803 E Bq/kgd \n 37086 23 28.316803 E Bq/kgd \n 37087 23 28.316803 E Bq/kgd \n 37088 23 28.316803 E Bq/kgd \n \n [37089 rows x 24 columns],\n 'biota': lon lat smp_depth time bio_group species \\\n 0 11.5000 54.080002 0.0 908755200 11 96 \n 1 11.5000 54.080002 0.0 900547200 11 96 \n 2 11.5000 54.080002 0.0 874540800 14 129 \n 3 11.5000 54.080002 0.0 865900800 14 129 \n 4 11.5000 54.080002 0.0 874886400 11 96 \n ... ... ... ... ... ... ... \n 14868 12.0742 57.335201 0.0 1253145600 11 96 \n 14869 12.0742 57.335201 0.0 1225670400 11 96 \n 14870 12.0742 57.335201 0.0 1160352000 11 96 \n 14871 12.0742 57.335201 0.0 1380240000 11 96 \n 14872 12.0742 57.335201 0.0 1409788800 11 96 \n \n body_part sample nuclide value ... Nuclide Latitude degrees \\\n 0 54 150 be7 46.500 ... 7Be 54 \n 1 54 159 be7 66.500 ... 7Be 54 \n 2 1 168 be7 5.430 ... 7Be 54 \n 3 1 177 be7 13.700 ... 7Be 54 \n 4 54 183 be7 11.300 ... 7Be 54 \n ... ... ... ... ... ... ... ... \n 14868 54 11586 tl208 0.880 ... 208Tl 57 \n 14869 54 11598 tl208 0.770 ... 208Tl 57 \n 14870 54 11620 tl208 1.310 ... 208Tl 57 \n 14871 54 11766 tl208 0.668 ... 208Tl 57 \n 14872 54 11775 tl208 0.684 ... 208Tl 57 \n \n Latitude minutes Latitude seconds Latitude direction Longitude degrees \\\n 0 4 48.006592 N 11 \n 1 4 48.006592 N 11 \n 2 4 48.006592 N 11 \n 3 4 48.006592 N 11 \n 4 4 48.006592 N 11 \n ... ... ... ... ... \n 14868 20 6.724548 N 12 \n 14869 20 6.724548 N 12 \n 14870 20 6.724548 N 12 \n 14871 20 6.724548 N 12 \n 14872 20 6.724548 N 12 \n \n Longitude minutes Longitude seconds Longitude direction Unit \n 0 30 0.000000 E Bq/kgd \n 1 30 0.000000 E Bq/kgd \n 2 30 0.000000 E Bq/kgd \n 3 30 0.000000 E Bq/kgd \n 4 30 0.000000 E Bq/kgd \n ... ... ... ... ... \n 14868 4 27.118835 E Bq/kgd \n 14869 4 27.118835 E Bq/kgd \n 14870 4 27.118835 E Bq/kgd \n 14871 4 27.118835 E Bq/kgd \n 14872 4 27.118835 E Bq/kgd \n \n [14873 rows x 26 columns]}\n\n\n\ntfm.dfs['seawater'].columns\n\nIndex(['lon', 'lat', 'smp_depth', 'tot_depth', 'time', 'sample', 'nuclide',\n 'value', '_unc', '_dl', '_sal', '_temp', '_unit', 'Sampling start date',\n 'Sampling start time', 'Sample type', 'Nuclide', 'Latitude degrees',\n 'Latitude minutes', 'Latitude seconds', 'Latitude direction',\n 'Longitude degrees', 'Longitude minutes', 'Longitude seconds',\n 'Longitude direction', 'Unit'],\n dtype='object')\n\n\n\n\n\nLookup : Value type (_dl)\n\nsource\n\n\nget_detectionlimitnames_lut\n\n get_detectionlimitnames_lut ()\n\n\nsource\n\n\nLookupValueTypeByIdCB\n\n LookupValueTypeByIdCB (fn_lut=<function get_detectionlimitnames_lut>)\n\nLookup MARIS Value Type.\n\ndfs = netcdf4_to_df(fname_in)\ntfm = Transformer(dfs, cbs=[ReshapeWideToLong(),\n LookupTimeFromEncodedTime(cfg()),\n GetSampleTypeCB(),\n LookupNuclideByIdCB(),\n ConvertLonLatCB(), \n LookupUnitByIdCB(),\n LookupValueTypeByIdCB()\n ])\ntfm()\n\n{'seawater': lon lat smp_depth tot_depth time sample \\\n 0 14.199800 54.006001 0.0 11.0 1497744000 78 \n 1 14.202300 54.006199 0.0 12.0 1339632000 83 \n 2 14.199500 54.006302 0.0 12.0 1402876800 86 \n 3 14.201000 54.006500 0.0 12.0 1278460800 91 \n 4 14.200500 54.006668 0.0 12.0 1309910400 101 \n ... ... ... ... ... ... ... \n 20237 20.030001 57.343300 0.0 236.0 524620800 14175 \n 20238 21.500000 59.433300 0.0 156.0 555033600 15712 \n 20239 21.525801 59.439800 0.0 160.0 585446400 15840 \n 20240 21.525801 59.439800 150.0 160.0 585446400 15847 \n 20241 23.555000 65.239998 0.0 73.0 587001600 20130 \n \n nuclide value _unc _dl ... Latitude degrees \\\n 0 h3 850.0000 59.669998 1 ... 54 \n 1 h3 970.0000 29.100000 1 ... 54 \n 2 h3 910.0000 24.570000 1 ... 54 \n 3 h3 1070.0000 21.400000 1 ... 54 \n 4 h3 1020.0000 20.400000 1 ... 54 \n ... ... ... ... ... ... ... \n 20237 cm243_244_tot 0.0064 0.001280 1 ... 57 \n 20238 cm243_244_tot 0.0045 0.000900 1 ... 59 \n 20239 cm243_244_tot 0.0022 0.000660 1 ... 59 \n 20240 cm243_244_tot 0.0064 0.001920 1 ... 59 \n 20241 cm243_244_tot 0.0039 0.001170 1 ... 65 \n \n Latitude minutes Latitude seconds Latitude direction \\\n 0 0 21.601868 N \n 1 0 22.315979 N \n 2 0 22.686768 N \n 3 0 23.400879 N \n 4 0 24.005127 N \n ... ... ... ... \n 20237 20 35.879517 N \n 20238 25 59.880066 N \n 20239 26 23.280945 N \n 20240 26 23.280945 N \n 20241 14 23.992310 N \n \n Longitude degrees Longitude minutes Longitude seconds \\\n 0 14 11 59.278336 \n 1 14 12 8.280258 \n 2 14 11 58.200302 \n 3 14 12 3.600769 \n 4 14 12 1.798325 \n ... ... ... ... \n 20237 20 1 48.002472 \n 20238 21 30 0.000000 \n 20239 21 31 32.882538 \n 20240 21 31 32.882538 \n 20241 23 33 18.001099 \n \n Longitude direction Unit Value type \n 0 E Bq/m3 = \n 1 E Bq/m3 = \n 2 E Bq/m3 = \n 3 E Bq/m3 = \n 4 E Bq/m3 = \n ... ... ... ... \n 20237 E Bq/m3 = \n 20238 E Bq/m3 = \n 20239 E Bq/m3 = \n 20240 E Bq/m3 = \n 20241 E Bq/m3 = \n \n [20242 rows x 27 columns],\n 'sediment': lon lat tot_depth time sed_type sample nuclide \\\n 0 10.850000 54.049999 22.0 866592000 58 842 be7 \n 1 10.203300 54.415001 13.0 811641600 58 4064 be7 \n 2 10.203300 54.415001 13.0 811641600 58 4069 be7 \n 3 10.203300 54.415001 13.0 811641600 58 4074 be7 \n 4 11.750000 54.416698 24.0 838512000 58 4535 be7 \n ... ... ... ... ... ... ... ... \n 37084 23.391199 65.277496 90.0 1283299200 2 37039 bi212 \n 37085 23.391199 65.277496 90.0 1283299200 2 37048 bi212 \n 37086 23.391199 65.277496 90.0 1283299200 2 37065 bi212 \n 37087 23.391199 65.277496 90.0 1283299200 2 37074 bi212 \n 37088 23.391199 65.277496 90.0 1283299200 2 37083 bi212 \n \n value _unc _dl ... Latitude degrees Latitude minutes \\\n 0 24.299999 7.7760 1 ... 54 2 \n 1 45.500000 4.5500 1 ... 54 24 \n 2 7.000000 NaN 2 ... 54 24 \n 3 4.800000 NaN 2 ... 54 24 \n 4 6.900000 1.9320 1 ... 54 25 \n ... ... ... ... ... ... ... \n 37084 42.900002 6.1347 1 ... 65 16 \n 37085 58.400002 6.1904 1 ... 65 16 \n 37086 51.400002 5.9624 1 ... 65 16 \n 37087 41.799999 5.4758 1 ... 65 16 \n 37088 43.700001 3.4523 1 ... 65 16 \n \n Latitude seconds Latitude direction Longitude degrees \\\n 0 59.997253 N 10 \n 1 54.003296 N 10 \n 2 54.003296 N 10 \n 3 54.003296 N 10 \n 4 0.114441 N 11 \n ... ... ... ... \n 37084 38.986816 N 23 \n 37085 38.986816 N 23 \n 37086 38.986816 N 23 \n 37087 38.986816 N 23 \n 37088 38.986816 N 23 \n \n Longitude minutes Longitude seconds Longitude direction Unit \\\n 0 51 0.001373 E Bq/kgd \n 1 12 11.881714 E Bq/kgd \n 2 12 11.881714 E Bq/kgd \n 3 12 11.881714 E Bq/kgd \n 4 45 0.000000 E Bq/kgd \n ... ... ... ... ... \n 37084 23 28.316803 E Bq/kgd \n 37085 23 28.316803 E Bq/kgd \n 37086 23 28.316803 E Bq/kgd \n 37087 23 28.316803 E Bq/kgd \n 37088 23 28.316803 E Bq/kgd \n \n Value type \n 0 = \n 1 = \n 2 < \n 3 < \n 4 = \n ... ... \n 37084 = \n 37085 = \n 37086 = \n 37087 = \n 37088 = \n \n [37089 rows x 25 columns],\n 'biota': lon lat smp_depth time bio_group species \\\n 0 11.5000 54.080002 0.0 908755200 11 96 \n 1 11.5000 54.080002 0.0 900547200 11 96 \n 2 11.5000 54.080002 0.0 874540800 14 129 \n 3 11.5000 54.080002 0.0 865900800 14 129 \n 4 11.5000 54.080002 0.0 874886400 11 96 \n ... ... ... ... ... ... ... \n 14868 12.0742 57.335201 0.0 1253145600 11 96 \n 14869 12.0742 57.335201 0.0 1225670400 11 96 \n 14870 12.0742 57.335201 0.0 1160352000 11 96 \n 14871 12.0742 57.335201 0.0 1380240000 11 96 \n 14872 12.0742 57.335201 0.0 1409788800 11 96 \n \n body_part sample nuclide value ... Latitude degrees \\\n 0 54 150 be7 46.500 ... 54 \n 1 54 159 be7 66.500 ... 54 \n 2 1 168 be7 5.430 ... 54 \n 3 1 177 be7 13.700 ... 54 \n 4 54 183 be7 11.300 ... 54 \n ... ... ... ... ... ... ... \n 14868 54 11586 tl208 0.880 ... 57 \n 14869 54 11598 tl208 0.770 ... 57 \n 14870 54 11620 tl208 1.310 ... 57 \n 14871 54 11766 tl208 0.668 ... 57 \n 14872 54 11775 tl208 0.684 ... 57 \n \n Latitude minutes Latitude seconds Latitude direction \\\n 0 4 48.006592 N \n 1 4 48.006592 N \n 2 4 48.006592 N \n 3 4 48.006592 N \n 4 4 48.006592 N \n ... ... ... ... \n 14868 20 6.724548 N \n 14869 20 6.724548 N \n 14870 20 6.724548 N \n 14871 20 6.724548 N \n 14872 20 6.724548 N \n \n Longitude degrees Longitude minutes Longitude seconds \\\n 0 11 30 0.000000 \n 1 11 30 0.000000 \n 2 11 30 0.000000 \n 3 11 30 0.000000 \n 4 11 30 0.000000 \n ... ... ... ... \n 14868 12 4 27.118835 \n 14869 12 4 27.118835 \n 14870 12 4 27.118835 \n 14871 12 4 27.118835 \n 14872 12 4 27.118835 \n \n Longitude direction Unit Value type \n 0 E Bq/kgd = \n 1 E Bq/kgd = \n 2 E Bq/kgd = \n 3 E Bq/kgd = \n 4 E Bq/kgd < \n ... ... ... ... \n 14868 E Bq/kgd = \n 14869 E Bq/kgd = \n 14870 E Bq/kgd = \n 14871 E Bq/kgd = \n 14872 E Bq/kgd = \n \n [14873 rows x 27 columns]}\n\n\n\n\n\nLookup : Biogroup\nBiogroup is in netcdf but not in OPEN REfINE csv format. Should we include this in Netcdf?\n\n\n\nLookup : Species\n\nsource\n\n\nget_species_lut\n\n get_species_lut ()\n\n\nsource\n\n\nLookupSpeciesByIdCB\n\n LookupSpeciesByIdCB (fn_lut=<function get_species_lut>)\n\nLookup MARIS species by species_id.\n\ndfs = netcdf4_to_df(fname_in)\ntfm = Transformer(dfs, cbs=[ReshapeWideToLong(),\n LookupTimeFromEncodedTime(cfg()),\n GetSampleTypeCB(),\n LookupNuclideByIdCB(),\n ConvertLonLatCB(), \n LookupUnitByIdCB(),\n LookupValueTypeByIdCB(),\n LookupSpeciesByIdCB()\n ])\ntfm()\n\n{'seawater': lon lat smp_depth tot_depth time sample \\\n 0 14.199800 54.006001 0.0 11.0 1497744000 78 \n 1 14.202300 54.006199 0.0 12.0 1339632000 83 \n 2 14.199500 54.006302 0.0 12.0 1402876800 86 \n 3 14.201000 54.006500 0.0 12.0 1278460800 91 \n 4 14.200500 54.006668 0.0 12.0 1309910400 101 \n ... ... ... ... ... ... ... \n 20237 20.030001 57.343300 0.0 236.0 524620800 14175 \n 20238 21.500000 59.433300 0.0 156.0 555033600 15712 \n 20239 21.525801 59.439800 0.0 160.0 585446400 15840 \n 20240 21.525801 59.439800 150.0 160.0 585446400 15847 \n 20241 23.555000 65.239998 0.0 73.0 587001600 20130 \n \n nuclide value _unc _dl ... Latitude degrees \\\n 0 h3 850.0000 59.669998 1 ... 54 \n 1 h3 970.0000 29.100000 1 ... 54 \n 2 h3 910.0000 24.570000 1 ... 54 \n 3 h3 1070.0000 21.400000 1 ... 54 \n 4 h3 1020.0000 20.400000 1 ... 54 \n ... ... ... ... ... ... ... \n 20237 cm243_244_tot 0.0064 0.001280 1 ... 57 \n 20238 cm243_244_tot 0.0045 0.000900 1 ... 59 \n 20239 cm243_244_tot 0.0022 0.000660 1 ... 59 \n 20240 cm243_244_tot 0.0064 0.001920 1 ... 59 \n 20241 cm243_244_tot 0.0039 0.001170 1 ... 65 \n \n Latitude minutes Latitude seconds Latitude direction \\\n 0 0 21.601868 N \n 1 0 22.315979 N \n 2 0 22.686768 N \n 3 0 23.400879 N \n 4 0 24.005127 N \n ... ... ... ... \n 20237 20 35.879517 N \n 20238 25 59.880066 N \n 20239 26 23.280945 N \n 20240 26 23.280945 N \n 20241 14 23.992310 N \n \n Longitude degrees Longitude minutes Longitude seconds \\\n 0 14 11 59.278336 \n 1 14 12 8.280258 \n 2 14 11 58.200302 \n 3 14 12 3.600769 \n 4 14 12 1.798325 \n ... ... ... ... \n 20237 20 1 48.002472 \n 20238 21 30 0.000000 \n 20239 21 31 32.882538 \n 20240 21 31 32.882538 \n 20241 23 33 18.001099 \n \n Longitude direction Unit Value type \n 0 E Bq/m3 = \n 1 E Bq/m3 = \n 2 E Bq/m3 = \n 3 E Bq/m3 = \n 4 E Bq/m3 = \n ... ... ... ... \n 20237 E Bq/m3 = \n 20238 E Bq/m3 = \n 20239 E Bq/m3 = \n 20240 E Bq/m3 = \n 20241 E Bq/m3 = \n \n [20242 rows x 27 columns],\n 'sediment': lon lat tot_depth time sed_type sample nuclide \\\n 0 10.850000 54.049999 22.0 866592000 58 842 be7 \n 1 10.203300 54.415001 13.0 811641600 58 4064 be7 \n 2 10.203300 54.415001 13.0 811641600 58 4069 be7 \n 3 10.203300 54.415001 13.0 811641600 58 4074 be7 \n 4 11.750000 54.416698 24.0 838512000 58 4535 be7 \n ... ... ... ... ... ... ... ... \n 37084 23.391199 65.277496 90.0 1283299200 2 37039 bi212 \n 37085 23.391199 65.277496 90.0 1283299200 2 37048 bi212 \n 37086 23.391199 65.277496 90.0 1283299200 2 37065 bi212 \n 37087 23.391199 65.277496 90.0 1283299200 2 37074 bi212 \n 37088 23.391199 65.277496 90.0 1283299200 2 37083 bi212 \n \n value _unc _dl ... Latitude degrees Latitude minutes \\\n 0 24.299999 7.7760 1 ... 54 2 \n 1 45.500000 4.5500 1 ... 54 24 \n 2 7.000000 NaN 2 ... 54 24 \n 3 4.800000 NaN 2 ... 54 24 \n 4 6.900000 1.9320 1 ... 54 25 \n ... ... ... ... ... ... ... \n 37084 42.900002 6.1347 1 ... 65 16 \n 37085 58.400002 6.1904 1 ... 65 16 \n 37086 51.400002 5.9624 1 ... 65 16 \n 37087 41.799999 5.4758 1 ... 65 16 \n 37088 43.700001 3.4523 1 ... 65 16 \n \n Latitude seconds Latitude direction Longitude degrees \\\n 0 59.997253 N 10 \n 1 54.003296 N 10 \n 2 54.003296 N 10 \n 3 54.003296 N 10 \n 4 0.114441 N 11 \n ... ... ... ... \n 37084 38.986816 N 23 \n 37085 38.986816 N 23 \n 37086 38.986816 N 23 \n 37087 38.986816 N 23 \n 37088 38.986816 N 23 \n \n Longitude minutes Longitude seconds Longitude direction Unit \\\n 0 51 0.001373 E Bq/kgd \n 1 12 11.881714 E Bq/kgd \n 2 12 11.881714 E Bq/kgd \n 3 12 11.881714 E Bq/kgd \n 4 45 0.000000 E Bq/kgd \n ... ... ... ... ... \n 37084 23 28.316803 E Bq/kgd \n 37085 23 28.316803 E Bq/kgd \n 37086 23 28.316803 E Bq/kgd \n 37087 23 28.316803 E Bq/kgd \n 37088 23 28.316803 E Bq/kgd \n \n Value type \n 0 = \n 1 = \n 2 < \n 3 < \n 4 = \n ... ... \n 37084 = \n 37085 = \n 37086 = \n 37087 = \n 37088 = \n \n [37089 rows x 25 columns],\n 'biota': lon lat smp_depth time bio_group species \\\n 0 11.5000 54.080002 0.0 908755200 11 96 \n 1 11.5000 54.080002 0.0 900547200 11 96 \n 2 11.5000 54.080002 0.0 874540800 14 129 \n 3 11.5000 54.080002 0.0 865900800 14 129 \n 4 11.5000 54.080002 0.0 874886400 11 96 \n ... ... ... ... ... ... ... \n 14868 12.0742 57.335201 0.0 1253145600 11 96 \n 14869 12.0742 57.335201 0.0 1225670400 11 96 \n 14870 12.0742 57.335201 0.0 1160352000 11 96 \n 14871 12.0742 57.335201 0.0 1380240000 11 96 \n 14872 12.0742 57.335201 0.0 1409788800 11 96 \n \n body_part sample nuclide value ... Latitude minutes \\\n 0 54 150 be7 46.500 ... 4 \n 1 54 159 be7 66.500 ... 4 \n 2 1 168 be7 5.430 ... 4 \n 3 1 177 be7 13.700 ... 4 \n 4 54 183 be7 11.300 ... 4 \n ... ... ... ... ... ... ... \n 14868 54 11586 tl208 0.880 ... 20 \n 14869 54 11598 tl208 0.770 ... 20 \n 14870 54 11620 tl208 1.310 ... 20 \n 14871 54 11766 tl208 0.668 ... 20 \n 14872 54 11775 tl208 0.684 ... 20 \n \n Latitude seconds Latitude direction Longitude degrees \\\n 0 48.006592 N 11 \n 1 48.006592 N 11 \n 2 48.006592 N 11 \n 3 48.006592 N 11 \n 4 48.006592 N 11 \n ... ... ... ... \n 14868 6.724548 N 12 \n 14869 6.724548 N 12 \n 14870 6.724548 N 12 \n 14871 6.724548 N 12 \n 14872 6.724548 N 12 \n \n Longitude minutes Longitude seconds Longitude direction Unit \\\n 0 30 0.000000 E Bq/kgd \n 1 30 0.000000 E Bq/kgd \n 2 30 0.000000 E Bq/kgd \n 3 30 0.000000 E Bq/kgd \n 4 30 0.000000 E Bq/kgd \n ... ... ... ... ... \n 14868 4 27.118835 E Bq/kgd \n 14869 4 27.118835 E Bq/kgd \n 14870 4 27.118835 E Bq/kgd \n 14871 4 27.118835 E Bq/kgd \n 14872 4 27.118835 E Bq/kgd \n \n Value type Species \n 0 = Fucus vesiculosus \n 1 = Fucus vesiculosus \n 2 = Mytilus edulis \n 3 = Mytilus edulis \n 4 < Fucus vesiculosus \n ... ... ... \n 14868 = Fucus vesiculosus \n 14869 = Fucus vesiculosus \n 14870 = Fucus vesiculosus \n 14871 = Fucus vesiculosus \n 14872 = Fucus vesiculosus \n \n [14873 rows x 28 columns]}\n\n\n\n\n\nLookup : Body part\n\nsource\n\n\nget_bodypart_lut\n\n get_bodypart_lut ()\n\n\nsource\n\n\nLookupBodypartByIdCB\n\n LookupBodypartByIdCB (fn_lut=<function get_bodypart_lut>)\n\nLookup MARIS bodypart by bodypar_id.\n\ndfs = netcdf4_to_df(fname_in)\ntfm = Transformer(dfs, cbs=[ReshapeWideToLong(),\n LookupTimeFromEncodedTime(cfg()),\n GetSampleTypeCB(),\n LookupNuclideByIdCB(),\n ConvertLonLatCB(), \n LookupUnitByIdCB(),\n LookupValueTypeByIdCB(),\n LookupSpeciesByIdCB(),\n LookupBodypartByIdCB()\n ])\ntfm()\n\n{'seawater': lon lat smp_depth tot_depth time sample \\\n 0 14.199800 54.006001 0.0 11.0 1497744000 78 \n 1 14.202300 54.006199 0.0 12.0 1339632000 83 \n 2 14.199500 54.006302 0.0 12.0 1402876800 86 \n 3 14.201000 54.006500 0.0 12.0 1278460800 91 \n 4 14.200500 54.006668 0.0 12.0 1309910400 101 \n ... ... ... ... ... ... ... \n 20237 20.030001 57.343300 0.0 236.0 524620800 14175 \n 20238 21.500000 59.433300 0.0 156.0 555033600 15712 \n 20239 21.525801 59.439800 0.0 160.0 585446400 15840 \n 20240 21.525801 59.439800 150.0 160.0 585446400 15847 \n 20241 23.555000 65.239998 0.0 73.0 587001600 20130 \n \n nuclide value _unc _dl ... Latitude degrees \\\n 0 h3 850.0000 59.669998 1 ... 54 \n 1 h3 970.0000 29.100000 1 ... 54 \n 2 h3 910.0000 24.570000 1 ... 54 \n 3 h3 1070.0000 21.400000 1 ... 54 \n 4 h3 1020.0000 20.400000 1 ... 54 \n ... ... ... ... ... ... ... \n 20237 cm243_244_tot 0.0064 0.001280 1 ... 57 \n 20238 cm243_244_tot 0.0045 0.000900 1 ... 59 \n 20239 cm243_244_tot 0.0022 0.000660 1 ... 59 \n 20240 cm243_244_tot 0.0064 0.001920 1 ... 59 \n 20241 cm243_244_tot 0.0039 0.001170 1 ... 65 \n \n Latitude minutes Latitude seconds Latitude direction \\\n 0 0 21.601868 N \n 1 0 22.315979 N \n 2 0 22.686768 N \n 3 0 23.400879 N \n 4 0 24.005127 N \n ... ... ... ... \n 20237 20 35.879517 N \n 20238 25 59.880066 N \n 20239 26 23.280945 N \n 20240 26 23.280945 N \n 20241 14 23.992310 N \n \n Longitude degrees Longitude minutes Longitude seconds \\\n 0 14 11 59.278336 \n 1 14 12 8.280258 \n 2 14 11 58.200302 \n 3 14 12 3.600769 \n 4 14 12 1.798325 \n ... ... ... ... \n 20237 20 1 48.002472 \n 20238 21 30 0.000000 \n 20239 21 31 32.882538 \n 20240 21 31 32.882538 \n 20241 23 33 18.001099 \n \n Longitude direction Unit Value type \n 0 E Bq/m3 = \n 1 E Bq/m3 = \n 2 E Bq/m3 = \n 3 E Bq/m3 = \n 4 E Bq/m3 = \n ... ... ... ... \n 20237 E Bq/m3 = \n 20238 E Bq/m3 = \n 20239 E Bq/m3 = \n 20240 E Bq/m3 = \n 20241 E Bq/m3 = \n \n [20242 rows x 27 columns],\n 'sediment': lon lat tot_depth time sed_type sample nuclide \\\n 0 10.850000 54.049999 22.0 866592000 58 842 be7 \n 1 10.203300 54.415001 13.0 811641600 58 4064 be7 \n 2 10.203300 54.415001 13.0 811641600 58 4069 be7 \n 3 10.203300 54.415001 13.0 811641600 58 4074 be7 \n 4 11.750000 54.416698 24.0 838512000 58 4535 be7 \n ... ... ... ... ... ... ... ... \n 37084 23.391199 65.277496 90.0 1283299200 2 37039 bi212 \n 37085 23.391199 65.277496 90.0 1283299200 2 37048 bi212 \n 37086 23.391199 65.277496 90.0 1283299200 2 37065 bi212 \n 37087 23.391199 65.277496 90.0 1283299200 2 37074 bi212 \n 37088 23.391199 65.277496 90.0 1283299200 2 37083 bi212 \n \n value _unc _dl ... Latitude degrees Latitude minutes \\\n 0 24.299999 7.7760 1 ... 54 2 \n 1 45.500000 4.5500 1 ... 54 24 \n 2 7.000000 NaN 2 ... 54 24 \n 3 4.800000 NaN 2 ... 54 24 \n 4 6.900000 1.9320 1 ... 54 25 \n ... ... ... ... ... ... ... \n 37084 42.900002 6.1347 1 ... 65 16 \n 37085 58.400002 6.1904 1 ... 65 16 \n 37086 51.400002 5.9624 1 ... 65 16 \n 37087 41.799999 5.4758 1 ... 65 16 \n 37088 43.700001 3.4523 1 ... 65 16 \n \n Latitude seconds Latitude direction Longitude degrees \\\n 0 59.997253 N 10 \n 1 54.003296 N 10 \n 2 54.003296 N 10 \n 3 54.003296 N 10 \n 4 0.114441 N 11 \n ... ... ... ... \n 37084 38.986816 N 23 \n 37085 38.986816 N 23 \n 37086 38.986816 N 23 \n 37087 38.986816 N 23 \n 37088 38.986816 N 23 \n \n Longitude minutes Longitude seconds Longitude direction Unit \\\n 0 51 0.001373 E Bq/kgd \n 1 12 11.881714 E Bq/kgd \n 2 12 11.881714 E Bq/kgd \n 3 12 11.881714 E Bq/kgd \n 4 45 0.000000 E Bq/kgd \n ... ... ... ... ... \n 37084 23 28.316803 E Bq/kgd \n 37085 23 28.316803 E Bq/kgd \n 37086 23 28.316803 E Bq/kgd \n 37087 23 28.316803 E Bq/kgd \n 37088 23 28.316803 E Bq/kgd \n \n Value type \n 0 = \n 1 = \n 2 < \n 3 < \n 4 = \n ... ... \n 37084 = \n 37085 = \n 37086 = \n 37087 = \n 37088 = \n \n [37089 rows x 25 columns],\n 'biota': lon lat smp_depth time bio_group species \\\n 0 11.5000 54.080002 0.0 908755200 11 96 \n 1 11.5000 54.080002 0.0 900547200 11 96 \n 2 11.5000 54.080002 0.0 874540800 14 129 \n 3 11.5000 54.080002 0.0 865900800 14 129 \n 4 11.5000 54.080002 0.0 874886400 11 96 \n ... ... ... ... ... ... ... \n 14868 12.0742 57.335201 0.0 1253145600 11 96 \n 14869 12.0742 57.335201 0.0 1225670400 11 96 \n 14870 12.0742 57.335201 0.0 1160352000 11 96 \n 14871 12.0742 57.335201 0.0 1380240000 11 96 \n 14872 12.0742 57.335201 0.0 1409788800 11 96 \n \n body_part sample nuclide value ... Latitude seconds \\\n 0 54 150 be7 46.500 ... 48.006592 \n 1 54 159 be7 66.500 ... 48.006592 \n 2 1 168 be7 5.430 ... 48.006592 \n 3 1 177 be7 13.700 ... 48.006592 \n 4 54 183 be7 11.300 ... 48.006592 \n ... ... ... ... ... ... ... \n 14868 54 11586 tl208 0.880 ... 6.724548 \n 14869 54 11598 tl208 0.770 ... 6.724548 \n 14870 54 11620 tl208 1.310 ... 6.724548 \n 14871 54 11766 tl208 0.668 ... 6.724548 \n 14872 54 11775 tl208 0.684 ... 6.724548 \n \n Latitude direction Longitude degrees Longitude minutes \\\n 0 N 11 30 \n 1 N 11 30 \n 2 N 11 30 \n 3 N 11 30 \n 4 N 11 30 \n ... ... ... ... \n 14868 N 12 4 \n 14869 N 12 4 \n 14870 N 12 4 \n 14871 N 12 4 \n 14872 N 12 4 \n \n Longitude seconds Longitude direction Unit Value type \\\n 0 0.000000 E Bq/kgd = \n 1 0.000000 E Bq/kgd = \n 2 0.000000 E Bq/kgd = \n 3 0.000000 E Bq/kgd = \n 4 0.000000 E Bq/kgd < \n ... ... ... ... ... \n 14868 27.118835 E Bq/kgd = \n 14869 27.118835 E Bq/kgd = \n 14870 27.118835 E Bq/kgd = \n 14871 27.118835 E Bq/kgd = \n 14872 27.118835 E Bq/kgd = \n \n Species Body part \n 0 Fucus vesiculosus Whole haptophytic plants \n 1 Fucus vesiculosus Whole haptophytic plants \n 2 Mytilus edulis Whole animal \n 3 Mytilus edulis Whole animal \n 4 Fucus vesiculosus Whole haptophytic plants \n ... ... ... \n 14868 Fucus vesiculosus Whole haptophytic plants \n 14869 Fucus vesiculosus Whole haptophytic plants \n 14870 Fucus vesiculosus Whole haptophytic plants \n 14871 Fucus vesiculosus Whole haptophytic plants \n 14872 Fucus vesiculosus Whole haptophytic plants \n \n [14873 rows x 29 columns]}\n\n\n\n\n\nLookup : Sediment type\n\nsource\n\n\nget_sediments_lut\n\n get_sediments_lut ()\n\n\nsource\n\n\nLookupSedimentTypeByIdCB\n\n LookupSedimentTypeByIdCB (fn_lut=<function get_sediments_lut>)\n\nLookup MARIS sedtype by sedtype_id.\n\ndfs = netcdf4_to_df(fname_in)\ntfm = Transformer(dfs, cbs=[ReshapeWideToLong(),\n LookupTimeFromEncodedTime(cfg()),\n GetSampleTypeCB(),\n LookupNuclideByIdCB(),\n ConvertLonLatCB(), \n LookupUnitByIdCB(),\n LookupValueTypeByIdCB(),\n LookupSpeciesByIdCB(),\n LookupBodypartByIdCB(),\n LookupSedimentTypeByIdCB()\n ])\ntfm()\n\n{'seawater': lon lat smp_depth tot_depth time sample \\\n 0 14.199800 54.006001 0.0 11.0 1497744000 78 \n 1 14.202300 54.006199 0.0 12.0 1339632000 83 \n 2 14.199500 54.006302 0.0 12.0 1402876800 86 \n 3 14.201000 54.006500 0.0 12.0 1278460800 91 \n 4 14.200500 54.006668 0.0 12.0 1309910400 101 \n ... ... ... ... ... ... ... \n 20237 20.030001 57.343300 0.0 236.0 524620800 14175 \n 20238 21.500000 59.433300 0.0 156.0 555033600 15712 \n 20239 21.525801 59.439800 0.0 160.0 585446400 15840 \n 20240 21.525801 59.439800 150.0 160.0 585446400 15847 \n 20241 23.555000 65.239998 0.0 73.0 587001600 20130 \n \n nuclide value _unc _dl ... Latitude degrees \\\n 0 h3 850.0000 59.669998 1 ... 54 \n 1 h3 970.0000 29.100000 1 ... 54 \n 2 h3 910.0000 24.570000 1 ... 54 \n 3 h3 1070.0000 21.400000 1 ... 54 \n 4 h3 1020.0000 20.400000 1 ... 54 \n ... ... ... ... ... ... ... \n 20237 cm243_244_tot 0.0064 0.001280 1 ... 57 \n 20238 cm243_244_tot 0.0045 0.000900 1 ... 59 \n 20239 cm243_244_tot 0.0022 0.000660 1 ... 59 \n 20240 cm243_244_tot 0.0064 0.001920 1 ... 59 \n 20241 cm243_244_tot 0.0039 0.001170 1 ... 65 \n \n Latitude minutes Latitude seconds Latitude direction \\\n 0 0 21.601868 N \n 1 0 22.315979 N \n 2 0 22.686768 N \n 3 0 23.400879 N \n 4 0 24.005127 N \n ... ... ... ... \n 20237 20 35.879517 N \n 20238 25 59.880066 N \n 20239 26 23.280945 N \n 20240 26 23.280945 N \n 20241 14 23.992310 N \n \n Longitude degrees Longitude minutes Longitude seconds \\\n 0 14 11 59.278336 \n 1 14 12 8.280258 \n 2 14 11 58.200302 \n 3 14 12 3.600769 \n 4 14 12 1.798325 \n ... ... ... ... \n 20237 20 1 48.002472 \n 20238 21 30 0.000000 \n 20239 21 31 32.882538 \n 20240 21 31 32.882538 \n 20241 23 33 18.001099 \n \n Longitude direction Unit Value type \n 0 E Bq/m3 = \n 1 E Bq/m3 = \n 2 E Bq/m3 = \n 3 E Bq/m3 = \n 4 E Bq/m3 = \n ... ... ... ... \n 20237 E Bq/m3 = \n 20238 E Bq/m3 = \n 20239 E Bq/m3 = \n 20240 E Bq/m3 = \n 20241 E Bq/m3 = \n \n [20242 rows x 27 columns],\n 'sediment': lon lat tot_depth time sed_type sample nuclide \\\n 0 10.850000 54.049999 22.0 866592000 58 842 be7 \n 1 10.203300 54.415001 13.0 811641600 58 4064 be7 \n 2 10.203300 54.415001 13.0 811641600 58 4069 be7 \n 3 10.203300 54.415001 13.0 811641600 58 4074 be7 \n 4 11.750000 54.416698 24.0 838512000 58 4535 be7 \n ... ... ... ... ... ... ... ... \n 37084 23.391199 65.277496 90.0 1283299200 2 37039 bi212 \n 37085 23.391199 65.277496 90.0 1283299200 2 37048 bi212 \n 37086 23.391199 65.277496 90.0 1283299200 2 37065 bi212 \n 37087 23.391199 65.277496 90.0 1283299200 2 37074 bi212 \n 37088 23.391199 65.277496 90.0 1283299200 2 37083 bi212 \n \n value _unc _dl ... Latitude minutes Latitude seconds \\\n 0 24.299999 7.7760 1 ... 2 59.997253 \n 1 45.500000 4.5500 1 ... 24 54.003296 \n 2 7.000000 NaN 2 ... 24 54.003296 \n 3 4.800000 NaN 2 ... 24 54.003296 \n 4 6.900000 1.9320 1 ... 25 0.114441 \n ... ... ... ... ... ... ... \n 37084 42.900002 6.1347 1 ... 16 38.986816 \n 37085 58.400002 6.1904 1 ... 16 38.986816 \n 37086 51.400002 5.9624 1 ... 16 38.986816 \n 37087 41.799999 5.4758 1 ... 16 38.986816 \n 37088 43.700001 3.4523 1 ... 16 38.986816 \n \n Latitude direction Longitude degrees Longitude minutes \\\n 0 N 10 51 \n 1 N 10 12 \n 2 N 10 12 \n 3 N 10 12 \n 4 N 11 45 \n ... ... ... ... \n 37084 N 23 23 \n 37085 N 23 23 \n 37086 N 23 23 \n 37087 N 23 23 \n 37088 N 23 23 \n \n Longitude seconds Longitude direction Unit Value type \\\n 0 0.001373 E Bq/kgd = \n 1 11.881714 E Bq/kgd = \n 2 11.881714 E Bq/kgd < \n 3 11.881714 E Bq/kgd < \n 4 0.000000 E Bq/kgd = \n ... ... ... ... ... \n 37084 28.316803 E Bq/kgd = \n 37085 28.316803 E Bq/kgd = \n 37086 28.316803 E Bq/kgd = \n 37087 28.316803 E Bq/kgd = \n 37088 28.316803 E Bq/kgd = \n \n Sediment type \n 0 Pure mud \n 1 Pure mud \n 2 Pure mud \n 3 Pure mud \n 4 Pure mud \n ... ... \n 37084 Gravel \n 37085 Gravel \n 37086 Gravel \n 37087 Gravel \n 37088 Gravel \n \n [37089 rows x 26 columns],\n 'biota': lon lat smp_depth time bio_group species \\\n 0 11.5000 54.080002 0.0 908755200 11 96 \n 1 11.5000 54.080002 0.0 900547200 11 96 \n 2 11.5000 54.080002 0.0 874540800 14 129 \n 3 11.5000 54.080002 0.0 865900800 14 129 \n 4 11.5000 54.080002 0.0 874886400 11 96 \n ... ... ... ... ... ... ... \n 14868 12.0742 57.335201 0.0 1253145600 11 96 \n 14869 12.0742 57.335201 0.0 1225670400 11 96 \n 14870 12.0742 57.335201 0.0 1160352000 11 96 \n 14871 12.0742 57.335201 0.0 1380240000 11 96 \n 14872 12.0742 57.335201 0.0 1409788800 11 96 \n \n body_part sample nuclide value ... Latitude seconds \\\n 0 54 150 be7 46.500 ... 48.006592 \n 1 54 159 be7 66.500 ... 48.006592 \n 2 1 168 be7 5.430 ... 48.006592 \n 3 1 177 be7 13.700 ... 48.006592 \n 4 54 183 be7 11.300 ... 48.006592 \n ... ... ... ... ... ... ... \n 14868 54 11586 tl208 0.880 ... 6.724548 \n 14869 54 11598 tl208 0.770 ... 6.724548 \n 14870 54 11620 tl208 1.310 ... 6.724548 \n 14871 54 11766 tl208 0.668 ... 6.724548 \n 14872 54 11775 tl208 0.684 ... 6.724548 \n \n Latitude direction Longitude degrees Longitude minutes \\\n 0 N 11 30 \n 1 N 11 30 \n 2 N 11 30 \n 3 N 11 30 \n 4 N 11 30 \n ... ... ... ... \n 14868 N 12 4 \n 14869 N 12 4 \n 14870 N 12 4 \n 14871 N 12 4 \n 14872 N 12 4 \n \n Longitude seconds Longitude direction Unit Value type \\\n 0 0.000000 E Bq/kgd = \n 1 0.000000 E Bq/kgd = \n 2 0.000000 E Bq/kgd = \n 3 0.000000 E Bq/kgd = \n 4 0.000000 E Bq/kgd < \n ... ... ... ... ... \n 14868 27.118835 E Bq/kgd = \n 14869 27.118835 E Bq/kgd = \n 14870 27.118835 E Bq/kgd = \n 14871 27.118835 E Bq/kgd = \n 14872 27.118835 E Bq/kgd = \n \n Species Body part \n 0 Fucus vesiculosus Whole haptophytic plants \n 1 Fucus vesiculosus Whole haptophytic plants \n 2 Mytilus edulis Whole animal \n 3 Mytilus edulis Whole animal \n 4 Fucus vesiculosus Whole haptophytic plants \n ... ... ... \n 14868 Fucus vesiculosus Whole haptophytic plants \n 14869 Fucus vesiculosus Whole haptophytic plants \n 14870 Fucus vesiculosus Whole haptophytic plants \n 14871 Fucus vesiculosus Whole haptophytic plants \n 14872 Fucus vesiculosus Whole haptophytic plants \n \n [14873 rows x 29 columns]}\n\n\n\n\n\nRename columns\n\nsource\n\n\nget_renaming_rules_netcdf2OpenRefine\n\n get_renaming_rules_netcdf2OpenRefine ()\n\n\nclass SelectAndRenameColumnCB(Callback):\n def __init__(self,\n fn_renaming_rules,\n ):\n fc.store_attr()\n def __call__(self, tfm):\n renaming = self.fn_renaming_rules()\n for grp in tfm.dfs.keys(): \n # get columns related to the grp (e.g. 'biota').\n coi = [v for k, v in renaming.items() if grp in k]\n # Join cols of interest\n coi_rename = {}\n for d in coi:\n for k, v in d.items(): \n coi_rename[k]=v\n # list cols\n cols = list(coi_rename.keys()) \n # select cols in df \n tfm.dfs[grp] = tfm.dfs[grp].loc[:, cols]\n # Rename cols\n tfm.dfs[grp].rename(columns=coi_rename, inplace=True)\n\n\ndfs = netcdf4_to_df(fname_in)\ntfm = Transformer(dfs, cbs=[ReshapeWideToLong(),\n LookupTimeFromEncodedTime(cfg()),\n GetSampleTypeCB(),\n LookupNuclideByIdCB(),\n ConvertLonLatCB(), \n LookupUnitByIdCB(),\n LookupValueTypeByIdCB(),\n LookupSpeciesByIdCB(),\n LookupBodypartByIdCB(),\n LookupSedimentTypeByIdCB(),\n SelectAndRenameColumnCB(get_renaming_rules_netcdf2OpenRefine)\n ])\ntfm()\n\n{'seawater': Sample type Latitude degrees Latitude minutes Latitude seconds \\\n 0 SEAWATER 54 0 21.601868 \n 1 SEAWATER 54 0 22.315979 \n 2 SEAWATER 54 0 22.686768 \n 3 SEAWATER 54 0 23.400879 \n 4 SEAWATER 54 0 24.005127 \n ... ... ... ... ... \n 20237 SEAWATER 57 20 35.879517 \n 20238 SEAWATER 59 25 59.880066 \n 20239 SEAWATER 59 26 23.280945 \n 20240 SEAWATER 59 26 23.280945 \n 20241 SEAWATER 65 14 23.992310 \n \n Latitude direction Longitude degrees Longitude minutes \\\n 0 N 14 11 \n 1 N 14 12 \n 2 N 14 11 \n 3 N 14 12 \n 4 N 14 12 \n ... ... ... ... \n 20237 N 20 1 \n 20238 N 21 30 \n 20239 N 21 31 \n 20240 N 21 31 \n 20241 N 23 33 \n \n Longitude seconds Longitude direction Latitude decimal ... \\\n 0 59.278336 E 54.006001 ... \n 1 8.280258 E 54.006199 ... \n 2 58.200302 E 54.006302 ... \n 3 3.600769 E 54.006500 ... \n 4 1.798325 E 54.006668 ... \n ... ... ... ... ... \n 20237 48.002472 E 57.343300 ... \n 20238 0.000000 E 59.433300 ... \n 20239 32.882538 E 59.439800 ... \n 20240 32.882538 E 59.439800 ... \n 20241 18.001099 E 65.239998 ... \n \n Sampling start time Nuclide Value type Unit Activity or MDA \\\n 0 00:00:00 3H = Bq/m3 850.0000 \n 1 00:00:00 3H = Bq/m3 970.0000 \n 2 00:00:00 3H = Bq/m3 910.0000 \n 3 00:00:00 3H = Bq/m3 1070.0000 \n 4 00:00:00 3H = Bq/m3 1020.0000 \n ... ... ... ... ... ... \n 20237 00:00:00 243_244Cm = Bq/m3 0.0064 \n 20238 00:00:00 243_244Cm = Bq/m3 0.0045 \n 20239 00:00:00 243_244Cm = Bq/m3 0.0022 \n 20240 00:00:00 243_244Cm = Bq/m3 0.0064 \n 20241 00:00:00 243_244Cm = Bq/m3 0.0039 \n \n Uncertainty Total depth Sampling depth Salinity Temperature \n 0 59.669998 11.0 0.0 7.50 NaN \n 1 29.100000 12.0 0.0 6.77 NaN \n 2 24.570000 12.0 0.0 6.80 NaN \n 3 21.400000 12.0 0.0 5.82 NaN \n 4 20.400000 12.0 0.0 5.40 NaN \n ... ... ... ... ... ... \n 20237 0.001280 236.0 0.0 6.90 NaN \n 20238 0.000900 156.0 0.0 6.75 NaN \n 20239 0.000660 160.0 0.0 5.83 20.4 \n 20240 0.001920 160.0 150.0 9.77 3.9 \n 20241 0.001170 73.0 0.0 3.10 15.6 \n \n [20242 rows x 22 columns],\n 'sediment': Sample type Latitude degrees Latitude minutes Latitude seconds \\\n 0 SEDIMENT 54 2 59.997253 \n 1 SEDIMENT 54 24 54.003296 \n 2 SEDIMENT 54 24 54.003296 \n 3 SEDIMENT 54 24 54.003296 \n 4 SEDIMENT 54 25 0.114441 \n ... ... ... ... ... \n 37084 SEDIMENT 65 16 38.986816 \n 37085 SEDIMENT 65 16 38.986816 \n 37086 SEDIMENT 65 16 38.986816 \n 37087 SEDIMENT 65 16 38.986816 \n 37088 SEDIMENT 65 16 38.986816 \n \n Latitude direction Longitude degrees Longitude minutes \\\n 0 N 10 51 \n 1 N 10 12 \n 2 N 10 12 \n 3 N 10 12 \n 4 N 11 45 \n ... ... ... ... \n 37084 N 23 23 \n 37085 N 23 23 \n 37086 N 23 23 \n 37087 N 23 23 \n 37088 N 23 23 \n \n Longitude seconds Longitude direction Latitude decimal \\\n 0 0.001373 E 54.049999 \n 1 11.881714 E 54.415001 \n 2 11.881714 E 54.415001 \n 3 11.881714 E 54.415001 \n 4 0.000000 E 54.416698 \n ... ... ... ... \n 37084 28.316803 E 65.277496 \n 37085 28.316803 E 65.277496 \n 37086 28.316803 E 65.277496 \n 37087 28.316803 E 65.277496 \n 37088 28.316803 E 65.277496 \n \n Longitude decimal Sampling start date Sampling start time Nuclide \\\n 0 10.850000 18-Jun-1997 00:00:00 7Be \n 1 10.203300 21-Sep-1995 00:00:00 7Be \n 2 10.203300 21-Sep-1995 00:00:00 7Be \n 3 10.203300 21-Sep-1995 00:00:00 7Be \n 4 11.750000 28-Jul-1996 00:00:00 7Be \n ... ... ... ... ... \n 37084 23.391199 01-Sep-2010 00:00:00 212Bi \n 37085 23.391199 01-Sep-2010 00:00:00 212Bi \n 37086 23.391199 01-Sep-2010 00:00:00 212Bi \n 37087 23.391199 01-Sep-2010 00:00:00 212Bi \n 37088 23.391199 01-Sep-2010 00:00:00 212Bi \n \n Value type Unit Activity or MDA Uncertainty Total depth \\\n 0 = Bq/kgd 24.299999 7.7760 22.0 \n 1 = Bq/kgd 45.500000 4.5500 13.0 \n 2 < Bq/kgd 7.000000 NaN 13.0 \n 3 < Bq/kgd 4.800000 NaN 13.0 \n 4 = Bq/kgd 6.900000 1.9320 24.0 \n ... ... ... ... ... ... \n 37084 = Bq/kgd 42.900002 6.1347 90.0 \n 37085 = Bq/kgd 58.400002 6.1904 90.0 \n 37086 = Bq/kgd 51.400002 5.9624 90.0 \n 37087 = Bq/kgd 41.799999 5.4758 90.0 \n 37088 = Bq/kgd 43.700001 3.4523 90.0 \n \n Sediment type \n 0 Pure mud \n 1 Pure mud \n 2 Pure mud \n 3 Pure mud \n 4 Pure mud \n ... ... \n 37084 Gravel \n 37085 Gravel \n 37086 Gravel \n 37087 Gravel \n 37088 Gravel \n \n [37089 rows x 20 columns],\n 'biota': Sample type Latitude degrees Latitude minutes Latitude seconds \\\n 0 BIOTA 54 4 48.006592 \n 1 BIOTA 54 4 48.006592 \n 2 BIOTA 54 4 48.006592 \n 3 BIOTA 54 4 48.006592 \n 4 BIOTA 54 4 48.006592 \n ... ... ... ... ... \n 14868 BIOTA 57 20 6.724548 \n 14869 BIOTA 57 20 6.724548 \n 14870 BIOTA 57 20 6.724548 \n 14871 BIOTA 57 20 6.724548 \n 14872 BIOTA 57 20 6.724548 \n \n Latitude direction Longitude degrees Longitude minutes \\\n 0 N 11 30 \n 1 N 11 30 \n 2 N 11 30 \n 3 N 11 30 \n 4 N 11 30 \n ... ... ... ... \n 14868 N 12 4 \n 14869 N 12 4 \n 14870 N 12 4 \n 14871 N 12 4 \n 14872 N 12 4 \n \n Longitude seconds Longitude direction Latitude decimal ... \\\n 0 0.000000 E 54.080002 ... \n 1 0.000000 E 54.080002 ... \n 2 0.000000 E 54.080002 ... \n 3 0.000000 E 54.080002 ... \n 4 0.000000 E 54.080002 ... \n ... ... ... ... ... \n 14868 27.118835 E 57.335201 ... \n 14869 27.118835 E 57.335201 ... \n 14870 27.118835 E 57.335201 ... \n 14871 27.118835 E 57.335201 ... \n 14872 27.118835 E 57.335201 ... \n \n Sampling start date Sampling start time Nuclide Value type Unit \\\n 0 19-Oct-1998 00:00:00 7Be = Bq/kgd \n 1 16-Jul-1998 00:00:00 7Be = Bq/kgd \n 2 18-Sep-1997 00:00:00 7Be = Bq/kgd \n 3 10-Jun-1997 00:00:00 7Be = Bq/kgd \n 4 22-Sep-1997 00:00:00 7Be < Bq/kgd \n ... ... ... ... ... ... \n 14868 17-Sep-2009 00:00:00 208Tl = Bq/kgd \n 14869 03-Nov-2008 00:00:00 208Tl = Bq/kgd \n 14870 09-Oct-2006 00:00:00 208Tl = Bq/kgd \n 14871 27-Sep-2013 00:00:00 208Tl = Bq/kgd \n 14872 04-Sep-2014 00:00:00 208Tl = Bq/kgd \n \n Activity or MDA Uncertainty Species \\\n 0 46.500 1.813500 Fucus vesiculosus \n 1 66.500 6.317500 Fucus vesiculosus \n 2 5.430 1.574700 Mytilus edulis \n 3 13.700 4.384000 Mytilus edulis \n 4 11.300 0.000000 Fucus vesiculosus \n ... ... ... ... \n 14868 0.880 0.079200 Fucus vesiculosus \n 14869 0.770 0.069300 Fucus vesiculosus \n 14870 1.310 0.142790 Fucus vesiculosus \n 14871 0.668 0.057448 Fucus vesiculosus \n 14872 0.684 0.072504 Fucus vesiculosus \n \n Body part bio_group \n 0 Whole haptophytic plants 11 \n 1 Whole haptophytic plants 11 \n 2 Whole animal 14 \n 3 Whole animal 14 \n 4 Whole haptophytic plants 11 \n ... ... ... \n 14868 Whole haptophytic plants 11 \n 14869 Whole haptophytic plants 11 \n 14870 Whole haptophytic plants 11 \n 14871 Whole haptophytic plants 11 \n 14872 Whole haptophytic plants 11 \n \n [14873 rows x 21 columns]}\n\n\n\n\n\nEncoding\n\nsource\n\n\nencode\n\n encode (fname_in, fname_out, ref_id=-1, **kwargs)\n\n\nencode(fname_in, fname_out, ref_id, verbose=False)\n\n<marisco.serializers.OpenRefineCsvEncoder>" + }, + { + "objectID": "handlers/netcdf_to_csv.html#todo", + "href": "handlers/netcdf_to_csv.html#todo", + "title": "NetCDF to Open Refine CSV (WIP)", + "section": "TODO", + "text": "TODO\nTODO Review Maris Nuclides lut. Cs127?\nTODO: Should the var be called ‘detection limit’? Is ‘value type’ more appropriate?\nTODO Biogroup not used in OPEN REfINE csv format. Confirm this\nTODO Ask about Species dbo. Paul said there is a larger one.\nTODO: Maintain sample (i.e. index) in the output." + }, + { + "objectID": "api/nc_template.html", + "href": "api/nc_template.html", + "title": "NetCDF Template", + "section": "", + "text": "Generate a NetCDF4 template from the configurable CDL.toml file, itself generated in /api/configs.ipynb.\n\nsource\n\n\n\n NCTemplater (cdl:Dict, nuclide_vars_fname:str, tpl_fname:str,\n enum_dicts:Dict, verbose=False)\n\nMARIS NetCDF template generator.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncdl\nDict\n\n“Pseudo CDL” (.toml)\n\n\nnuclide_vars_fname\nstr\n\nFile name and path of MARIS nuclide lookup table containing variable names\n\n\ntpl_fname\nstr\n\nFile name and path of NetCDF4 file to be generated\n\n\nenum_dicts\nDict\n\nMARIS NetCDF enumeration types\n\n\nverbose\nbool\nFalse\n\n\n\n\nFor example, provided the configuration cdl.toml below, the templater gets access, among others, to its dim definiton section:\n\ncdl_test = read_toml('./files/cdl.toml')\nlut_src_dir_test = './files/lut'\ncdl_enums_test = read_toml('./files/cdl.toml')['enums']\nenums = get_enum_dicts(lut_src_dir=lut_src_dir_test, \n cdl_enums=cdl_enums_test)\n\n\ntemplater = NCTemplater(cdl=cdl_test,\n nuclide_vars_fname='./files/lut/dbo_nuclide.xlsx', \n tpl_fname='./files/nc/test.nc',\n enum_dicts=enums)\n\nexpected = {'name': 'sample', \n 'dtype': 'u8', \n 'attrs': {'long_name': 'Sample ID of measurement'}\n }\n\nfc.test_eq(templater.dim, expected)\n\n\nfor k, v in enums['species_t'].items():\n if v == 5: break\n print(k, v)\n\nNot applicable -1\nNOT AVAILABLE 0\nAristeus antennatus 1\nApostichopus 2\nSaccharina japonica var religiosa 3\nSiganus fuscescens 4\n\n\n\nsource\n\n\n\n\n NCTemplater.nuclide_vars (col_varnames:str='nc_name',\n col_stdnames:str='nusymbol', dtype:str='f4')\n\nReturn the name of the radionuclide variables analysed.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncol_varnames\nstr\nnc_name\nColumn name in the Excel lookup file containing the NetCDF variable names\n\n\ncol_stdnames\nstr\nnusymbol\nColumn name Excel lookup file containing the NetCDF standard names\n\n\ndtype\nstr\nf4\nDefault data type\n\n\nReturns\nlist\n\nList of nuclide variables (including their names and attributes)\n\n\n\nFor example, to retrieve the NetCDF nuclide names and associated attributes:\n\ntemplater = NCTemplater(cdl=cdl_test,\n nuclide_vars_fname='./files/lut/dbo_nuclide.xlsx', \n tpl_fname='./files/nc/test.nc',\n enum_dicts=enums)\nexpected = [\n {'name': 'h3', 'attrs': {'long_name': 'Tritium 3', 'standard_name': '3H'}, 'dtype': 'f4'},\n {'name': 'be7', 'attrs': {'long_name': 'Beryllium 7', 'standard_name': '7Be'}, 'dtype': 'f4'}\n ]\n\nfc.test_eq(templater.nuclide_vars()[:2], expected)\n\n\nsource\n\n\n\n\n NCTemplater.derive (nuclide:dict, suffix:dict)\n\nDerive NetCDF nuclide-dependent variable names & attributes as defined in CDL.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nnuclide\ndict\nNuclide variable name and associated netcdf attributes\n\n\nsuffix\ndict\nNaming rules as described in CDL (e.g _unc)\n\n\nReturns\ndict\nDerived variable name and associated attributes\n\n\n\nFor example, among others, the cdl.toml file defines the naming convention on variable names deriving from nuclides (e.g h3_unc for measurement uncertainty on the h3 nuclide variable).\n\ntemplater = NCTemplater(cdl=cdl_test,\n nuclide_vars_fname='./files/lut/dbo_nuclide.xlsx', \n tpl_fname='./files/nc/test.nc',\n enum_dicts=enums)\n\nHere is below the defined Tritium NetCDF variable as specified in the .cdl file:\n\ntemplater.nuclide_vars()[0]\n\n{'name': 'h3',\n 'dtype': 'f4',\n 'attrs': {'long_name': 'Tritium 3', 'standard_name': '3H'}}\n\n\n\n# Example of suffix defined in the .cdl file\nsuffix = {\n 'name': '_unc',\n 'attrs': {\n 'long_name': ' uncertainty',\n 'standard_name': '_uncertainty'\n },\n 'dtype': 'f4'\n }\n\n# And what we expect\nexpected = {\n 'name': 'h3_unc',\n 'attrs': {\n 'long_name': 'Tritium 3 uncertainty',\n 'standard_name': '3H_uncertainty'\n },\n 'dtype': 'f4'\n }\n\nfc.test_eq(templater.derive(templater.nuclide_vars()[0], suffix=suffix), expected)\n\n\nsource\n\n\n\n\n NCTemplater.create_enum_types ()\n\nCreate enumeration types\n\nsource\n\n\n\n\n NCTemplater.create_groups ()\n\nCreate NetCDF groups\n\nsource\n\n\n\n\n NCTemplater.create_variables (grp:netCDF4._netCDF4.Group)\n\nCreate variables\n\n\n\n\nType\nDetails\n\n\n\n\ngrp\nGroup\nNetCDF group\n\n\n\n\nsource\n\n\n\n\n NCTemplater.create_default_variables (grp:netCDF4._netCDF4.Group)\n\nCreate Default variables\n\n\n\n\nType\nDetails\n\n\n\n\ngrp\nGroup\nNetCDF group\n\n\n\n\nsource\n\n\n\n\n NCTemplater.create_group_specific_variables (grp:netCDF4._netCDF4.Group)\n\nCreate group specific variables\n\n\n\n\nType\nDetails\n\n\n\n\ngrp\nGroup\nNetCDF group\n\n\n\n\nsource\n\n\n\n\n NCTemplater.create_analyte_variables (grp:netCDF4._netCDF4.Group)\n\nCreate analyte variables and dependent one as uncertainty, detection limit, …\n\n\n\n\nType\nDetails\n\n\n\n\ngrp\nGroup\nNetCDF group\n\n\n\n\nsource\n\n\n\n\n NCTemplater.create_variable (grp:netCDF4._netCDF4.Group, var:Dict)\n\nCreate NetCDF variable with proper types (standard and enums)\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\ngrp\nGroup\nNetCDF group\n\n\nvar\nDict\nVariable specificiation dict with name, dtype and attrs keys\n\n\n\n\n# Troubleshooting na values\n# from netCDF4 import Dataset\n# import numpy as np\n\n# with Dataset(''./files/nc/test-na-values.nc', 'w', format='NETCDF4') as nc:\n# sample = nc.createDimension(\"sample\", 4)\n\n# enum_dict = {'Not applicable': -1, 'Not available': 0, 'Bq per m3': 1, 'Bq per kg': 2}\n# # unit_type = nc.createEnumType(np.uint8,'unit_t',enum_dict)\n# unit_type = nc.createEnumType(np.int_,'unit_t',enum_dict)\n\n# meas_var = nc.createVariable('measurement', 'f4', 'sample')\n# unit_var = nc.createVariable('unit', unit_type, 'sample',\n# fill_value=-1\n# # fill_value=enum_dict['Not available']\n# )\n\n# meas_var[:] = [1.1, 2.1, 3.1, np.nan]\n# unit_var[:] = [enum_dict[k] for k in ['Bq per m3', 'Bq per kg', 'Bq per kg']] + [-1]\n# print(unit_var)\n\n\nsource\n\n\n\n\n NCTemplater.generate ()\n\nGenerate CDL\nSo in summary, to produce a template MARIS NetCDF:\n\ntemplater = NCTemplater(cdl=cdl_test,\n nuclide_vars_fname='./files/lut/dbo_nuclide.xlsx', \n tpl_fname='./files/nc/template-test.nc',\n enum_dicts=enums, \n verbose=True)\n\ntemplater.generate()\n\nCreating area_t enumeration type\nCreating bio_group_t enumeration type\nCreating body_part_t enumeration type\nCreating species_t enumeration type\nCreating sed_type_t enumeration type\nCreating unit_t enumeration type\nCreating dl_t enumeration type\nCreating filt_t enumeration type\nCreating counmet_t enumeration type\nCreating sampmet_t enumeration type\nCreating prepmet_t enumeration type", + "crumbs": [ + "API", + "NetCDF Template" + ] + }, + { + "objectID": "api/nc_template.html#netcdf-template-generator", + "href": "api/nc_template.html#netcdf-template-generator", + "title": "NetCDF Template", + "section": "", + "text": "Generate a NetCDF4 template from the configurable CDL.toml file, itself generated in /api/configs.ipynb.\n\nsource\n\n\n\n NCTemplater (cdl:Dict, nuclide_vars_fname:str, tpl_fname:str,\n enum_dicts:Dict, verbose=False)\n\nMARIS NetCDF template generator.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncdl\nDict\n\n“Pseudo CDL” (.toml)\n\n\nnuclide_vars_fname\nstr\n\nFile name and path of MARIS nuclide lookup table containing variable names\n\n\ntpl_fname\nstr\n\nFile name and path of NetCDF4 file to be generated\n\n\nenum_dicts\nDict\n\nMARIS NetCDF enumeration types\n\n\nverbose\nbool\nFalse\n\n\n\n\nFor example, provided the configuration cdl.toml below, the templater gets access, among others, to its dim definiton section:\n\ncdl_test = read_toml('./files/cdl.toml')\nlut_src_dir_test = './files/lut'\ncdl_enums_test = read_toml('./files/cdl.toml')['enums']\nenums = get_enum_dicts(lut_src_dir=lut_src_dir_test, \n cdl_enums=cdl_enums_test)\n\n\ntemplater = NCTemplater(cdl=cdl_test,\n nuclide_vars_fname='./files/lut/dbo_nuclide.xlsx', \n tpl_fname='./files/nc/test.nc',\n enum_dicts=enums)\n\nexpected = {'name': 'sample', \n 'dtype': 'u8', \n 'attrs': {'long_name': 'Sample ID of measurement'}\n }\n\nfc.test_eq(templater.dim, expected)\n\n\nfor k, v in enums['species_t'].items():\n if v == 5: break\n print(k, v)\n\nNot applicable -1\nNOT AVAILABLE 0\nAristeus antennatus 1\nApostichopus 2\nSaccharina japonica var religiosa 3\nSiganus fuscescens 4\n\n\n\nsource\n\n\n\n\n NCTemplater.nuclide_vars (col_varnames:str='nc_name',\n col_stdnames:str='nusymbol', dtype:str='f4')\n\nReturn the name of the radionuclide variables analysed.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncol_varnames\nstr\nnc_name\nColumn name in the Excel lookup file containing the NetCDF variable names\n\n\ncol_stdnames\nstr\nnusymbol\nColumn name Excel lookup file containing the NetCDF standard names\n\n\ndtype\nstr\nf4\nDefault data type\n\n\nReturns\nlist\n\nList of nuclide variables (including their names and attributes)\n\n\n\nFor example, to retrieve the NetCDF nuclide names and associated attributes:\n\ntemplater = NCTemplater(cdl=cdl_test,\n nuclide_vars_fname='./files/lut/dbo_nuclide.xlsx', \n tpl_fname='./files/nc/test.nc',\n enum_dicts=enums)\nexpected = [\n {'name': 'h3', 'attrs': {'long_name': 'Tritium 3', 'standard_name': '3H'}, 'dtype': 'f4'},\n {'name': 'be7', 'attrs': {'long_name': 'Beryllium 7', 'standard_name': '7Be'}, 'dtype': 'f4'}\n ]\n\nfc.test_eq(templater.nuclide_vars()[:2], expected)\n\n\nsource\n\n\n\n\n NCTemplater.derive (nuclide:dict, suffix:dict)\n\nDerive NetCDF nuclide-dependent variable names & attributes as defined in CDL.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nnuclide\ndict\nNuclide variable name and associated netcdf attributes\n\n\nsuffix\ndict\nNaming rules as described in CDL (e.g _unc)\n\n\nReturns\ndict\nDerived variable name and associated attributes\n\n\n\nFor example, among others, the cdl.toml file defines the naming convention on variable names deriving from nuclides (e.g h3_unc for measurement uncertainty on the h3 nuclide variable).\n\ntemplater = NCTemplater(cdl=cdl_test,\n nuclide_vars_fname='./files/lut/dbo_nuclide.xlsx', \n tpl_fname='./files/nc/test.nc',\n enum_dicts=enums)\n\nHere is below the defined Tritium NetCDF variable as specified in the .cdl file:\n\ntemplater.nuclide_vars()[0]\n\n{'name': 'h3',\n 'dtype': 'f4',\n 'attrs': {'long_name': 'Tritium 3', 'standard_name': '3H'}}\n\n\n\n# Example of suffix defined in the .cdl file\nsuffix = {\n 'name': '_unc',\n 'attrs': {\n 'long_name': ' uncertainty',\n 'standard_name': '_uncertainty'\n },\n 'dtype': 'f4'\n }\n\n# And what we expect\nexpected = {\n 'name': 'h3_unc',\n 'attrs': {\n 'long_name': 'Tritium 3 uncertainty',\n 'standard_name': '3H_uncertainty'\n },\n 'dtype': 'f4'\n }\n\nfc.test_eq(templater.derive(templater.nuclide_vars()[0], suffix=suffix), expected)\n\n\nsource\n\n\n\n\n NCTemplater.create_enum_types ()\n\nCreate enumeration types\n\nsource\n\n\n\n\n NCTemplater.create_groups ()\n\nCreate NetCDF groups\n\nsource\n\n\n\n\n NCTemplater.create_variables (grp:netCDF4._netCDF4.Group)\n\nCreate variables\n\n\n\n\nType\nDetails\n\n\n\n\ngrp\nGroup\nNetCDF group\n\n\n\n\nsource\n\n\n\n\n NCTemplater.create_default_variables (grp:netCDF4._netCDF4.Group)\n\nCreate Default variables\n\n\n\n\nType\nDetails\n\n\n\n\ngrp\nGroup\nNetCDF group\n\n\n\n\nsource\n\n\n\n\n NCTemplater.create_group_specific_variables (grp:netCDF4._netCDF4.Group)\n\nCreate group specific variables\n\n\n\n\nType\nDetails\n\n\n\n\ngrp\nGroup\nNetCDF group\n\n\n\n\nsource\n\n\n\n\n NCTemplater.create_analyte_variables (grp:netCDF4._netCDF4.Group)\n\nCreate analyte variables and dependent one as uncertainty, detection limit, …\n\n\n\n\nType\nDetails\n\n\n\n\ngrp\nGroup\nNetCDF group\n\n\n\n\nsource\n\n\n\n\n NCTemplater.create_variable (grp:netCDF4._netCDF4.Group, var:Dict)\n\nCreate NetCDF variable with proper types (standard and enums)\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\ngrp\nGroup\nNetCDF group\n\n\nvar\nDict\nVariable specificiation dict with name, dtype and attrs keys\n\n\n\n\n# Troubleshooting na values\n# from netCDF4 import Dataset\n# import numpy as np\n\n# with Dataset(''./files/nc/test-na-values.nc', 'w', format='NETCDF4') as nc:\n# sample = nc.createDimension(\"sample\", 4)\n\n# enum_dict = {'Not applicable': -1, 'Not available': 0, 'Bq per m3': 1, 'Bq per kg': 2}\n# # unit_type = nc.createEnumType(np.uint8,'unit_t',enum_dict)\n# unit_type = nc.createEnumType(np.int_,'unit_t',enum_dict)\n\n# meas_var = nc.createVariable('measurement', 'f4', 'sample')\n# unit_var = nc.createVariable('unit', unit_type, 'sample',\n# fill_value=-1\n# # fill_value=enum_dict['Not available']\n# )\n\n# meas_var[:] = [1.1, 2.1, 3.1, np.nan]\n# unit_var[:] = [enum_dict[k] for k in ['Bq per m3', 'Bq per kg', 'Bq per kg']] + [-1]\n# print(unit_var)\n\n\nsource\n\n\n\n\n NCTemplater.generate ()\n\nGenerate CDL\nSo in summary, to produce a template MARIS NetCDF:\n\ntemplater = NCTemplater(cdl=cdl_test,\n nuclide_vars_fname='./files/lut/dbo_nuclide.xlsx', \n tpl_fname='./files/nc/template-test.nc',\n enum_dicts=enums, \n verbose=True)\n\ntemplater.generate()\n\nCreating area_t enumeration type\nCreating bio_group_t enumeration type\nCreating body_part_t enumeration type\nCreating species_t enumeration type\nCreating sed_type_t enumeration type\nCreating unit_t enumeration type\nCreating dl_t enumeration type\nCreating filt_t enumeration type\nCreating counmet_t enumeration type\nCreating sampmet_t enumeration type\nCreating prepmet_t enumeration type", + "crumbs": [ + "API", + "NetCDF Template" + ] + }, + { + "objectID": "api/configs.html", + "href": "api/configs.html", + "title": "Configs", + "section": "", + "text": "Exported source\nfrom pathlib import Path\nimport os\nimport re\nfrom functools import partial\nfrom typing import Union\n\nfrom marisco.inout import read_toml, write_toml\nimport pandas as pd\nimport fastcore.all as fc", + "crumbs": [ + "API", + "Configs" + ] + }, + { + "objectID": "api/configs.html#configuration-files", + "href": "api/configs.html#configuration-files", + "title": "Configs", + "section": "Configuration files", + "text": "Configuration files\n\nsource\n\nbase_path\n\n base_path ()\n\n\n\nExported source\nCFG_FNAME = 'configs.toml'\nCDL_FNAME = 'cdl.toml'\nNUCLIDE_LOOKUP_FNAME = 'dbo_nuclide.xlsx'\nMARISCO_CFG_DIRNAME = '.marisco'\n\n\n\n\nExported source\ndef base_path(): return Path.home() / MARISCO_CFG_DIRNAME\n\n\nBy default, we create a folder named .marisco under your home directory that will receive all configuration files as defined in BASE_PATH:\n\nbase_path()\n\nPath('/Users/franckalbinet/.marisco')\n\n\n\n\nExported source\nCONFIGS = {\n 'gh': {\n 'owner': 'franckalbinet',\n 'repo': 'marisco'\n },\n 'names': {\n 'nc_template': 'maris-template.nc'\n },\n 'dirs': {\n 'lut': str(base_path() / 'lut'), # Look-up tables\n 'cache': str(base_path() / 'cache'), # Cache (e.f WoRMS species)\n 'tmp': str(base_path() / 'tmp')\n },\n 'paths': {\n 'luts': 'nbs/files/lut'\n },\n 'units': {\n 'time': 'seconds since 1970-01-01 00:00:00.0'\n },\n 'zotero': {\n 'api_key': os.getenv('ZOTERO_API_KEY'),\n 'lib_id': '2432820'\n }\n}\n\n\nThe CONFIGS dictionary defines general settings:\n\n\n\nkey\nValue\nDescription\n\n\n\n\ndirs/lut\n/Users/franckalbinet/.marisco/lut\nLocation & name of the directory receiving lookup tables.\n\n\ndirs/cache\n/Users/franckalbinet/.marisco/cache\nLocation & name of the directory receiving cache files such as WoRMS species retrieved.\n\n\ndirs/tmp\n/Users/franckalbinet/.marisco/tmp\nLocation & name of temporary files.\n\n\ngh/owner\nfranckalbinet\nGitHub account owner.\n\n\ngh/repo\nmarisco\nGitHub user used to download specific files (e.g lookup tables) during installation.\n\n\nnames/nc_template\nmaris-template.nc\nName of the MARIS NetCDF4 template.\n\n\npaths_luts\nnbs/files/lut\nGitHub repository directory name containing lookup tables.\n\n\nunits_time\nseconds since 1970-01-01 00:00:00.0\nReference date and time used for NetCDF time encoding.\n\n\nzotero/api_key\nyour-zotero-api-key\nZotero API key (“ZOTERO_API_KEY” environment variable).\n\n\nzotero/lib_id\n2432820\nZotero library ID.\n\n\n\nThe main CONFIGS_CDL dictionary, used to generate a NetCDF CDL (Common Data Language) .toml file. This file is then used to generate a template MARIS netcdf file. For further details refers to the configs.ipynb file.\nBelow, the vars/defaults section printed:\n\nsource\n\n\ncfg\n\n cfg ()\n\n\n\nExported source\ndef cfg(): return read_toml(base_path() / CFG_FNAME)\n\n\n\nsource\n\n\nnuc_lut_path\n\n nuc_lut_path ()\n\n\n\nExported source\ndef nuc_lut_path(): return Path(cfg()['dirs']['lut']) / NUCLIDE_LOOKUP_FNAME\n\n\n\nsource\n\n\nlut_path\n\n lut_path ()\n\n\n\nExported source\ndef lut_path(): return Path(cfg()['dirs']['lut'])\n\n\n\nsource\n\n\ncache_path\n\n cache_path ()\n\n\n\nExported source\ndef cache_path(): return Path(cfg()['dirs']['cache'])\n\n\n\n\nExported source\nCONFIGS_CDL = { \n 'placeholder': '_to_be_filled_in_',\n 'grps': {\n 'sea': {\n 'name': 'seawater',\n 'id': 1\n },\n 'bio': {\n 'name': 'biota',\n 'id': 2\n },\n 'sed': {\n 'name': 'sediment',\n 'id': 3\n },\n 'sus': {\n 'name': 'suspended-matter',\n 'id': 4\n }\n },\n 'global_attrs': {\n # Do not update keys. Only values if required\n 'id': '', # zotero?\n 'title': '',\n 'summary': '',\n 'keywords': '',\n 'keywords_vocabulary': 'GCMD Science Keywords',\n 'keywords_vocabulary_url': 'https://gcmd.earthdata.nasa.gov/static/kms/',\n 'record': '',\n 'featureType': '',\n 'cdm_data_type': '',\n\n # Conventions\n 'Conventions': 'CF-1.10 ACDD-1.3',\n\n # Publisher [ACDD1.3]\n 'publisher_name': 'Paul MCGINNITY, Iolanda OSVATH, Florence DESCROIX-COMANDUCCI',\n 'publisher_email': 'p.mc-ginnity@iaea.org, i.osvath@iaea.org, F.Descroix-Comanducci@iaea.org', \n 'publisher_url': 'https://maris.iaea.org',\n 'publisher_institution': 'International Atomic Energy Agency - IAEA', \n\n # Creator info [ACDD1.3]\n 'creator_name': '',\n 'institution': '',\n 'metadata_link': '',\n 'creator_email': '',\n 'creator_url': '',\n 'references': '',\n 'license': ' '.join(['Without prejudice to the applicable Terms and Conditions', \n '(https://nucleus.iaea.org/Pages/Others/Disclaimer.aspx),',\n 'I hereby agree that any use of the data will contain appropriate',\n 'acknowledgement of the data source(s) and the IAEA Marine',\n 'Radioactivity Information System (MARIS).']),\n 'comment': '',\n # Dataset info & coordinates [ACDD1.3]\n #'project': '', # Network long name\n #'platform': '', # Should be a long / full name\n 'geospatial_lat_min': '', \n 'geospatial_lon_min': '',\n 'geospatial_lat_max': '',\n 'geospatial_lon_max': '',\n 'geospatial_vertical_min': '',\n 'geospatial_vertical_max': '',\n 'geospatial_bounds': '', # wkt representation\n 'geospatial_bounds_crs': 'EPSG:4326',\n\n # Time information\n 'time_coverage_start': '',\n 'time_coverage_end': '',\n #'time_coverage_resolution': '',\n 'local_time_zone': '',\n 'date_created': '',\n 'date_modified': '',\n #\n # -- Additional metadata (custom to MARIS)\n #\n 'publisher_postprocess_logs': ''\n },\n 'dim': {\n 'name': 'sample',\n 'attrs': {\n 'long_name': 'Sample ID of measurement'\n },\n 'dtype': 'u8'\n },\n 'vars': { \n 'defaults': {\n 'lon': {\n 'name': 'lon',\n 'attrs': {\n 'long_name': 'Measurement longitude',\n 'standard_name': 'longitude',\n 'units': 'degrees_north',\n 'axis': 'Y',\n '_CoordinateAxisType': 'Lon'\n },\n 'dtype': 'f4'\n },\n 'lat': {\n 'name': 'lat',\n 'attrs': {\n 'long_name': 'Measurement latitude',\n 'standard_name': 'latitude',\n 'units': 'degrees_east',\n 'axis': 'X',\n '_CoordinateAxisType': 'Lat'\n },\n 'dtype': 'f4'\n },\n 'smp_depth': {\n 'name': 'smp_depth',\n 'attrs': {\n 'long_name': 'Sample depth below seal level',\n 'standard_name': 'sample_depth_below_sea_floor',\n 'units': 'm',\n 'axis': 'Z'\n },\n 'dtype': 'f4'\n },\n 'tot_depth': {\n 'name': 'tot_depth',\n 'attrs': {\n 'long_name': 'Total depth below seal level',\n 'standard_name': 'total_depth_below_sea_floor',\n 'units': 'm',\n 'axis': 'Z'\n },\n 'dtype': 'f4'\n },\n 'time': {\n 'name': 'time',\n 'attrs': {\n 'long_name': 'Time of measurement',\n 'standard_name': 'time',\n 'units': 'seconds since 1970-01-01 00:00:00.0',\n 'time_origin': '1970-01-01 00:00:00',\n 'time_zone': 'UTC',\n 'abbreviation': 'Date/Time',\n 'axis': 'T',\n 'calendar': 'gregorian'\n },\n 'dtype': 'u8',\n },\n 'area': {\n 'name': 'area',\n 'attrs': {\n 'long_name': 'Marine area/region id',\n 'standard_name': 'area_id'\n },\n 'dtype': 'area_t'\n },\n },\n 'bio': {\n 'bio_group': {\n 'name': 'bio_group',\n 'attrs': {\n 'long_name': 'Biota group',\n 'standard_name': 'biota_group_tbd'\n },\n 'dtype': 'bio_group_t'\n },\n 'species': {\n 'name': 'species',\n 'attrs': { \n 'long_name': 'Species',\n 'standard_name': 'species'\n },\n 'dtype': 'species_t'\n },\n 'body_part': {\n 'name': 'body_part',\n 'attrs': {\n 'long_name': 'Body part',\n 'standard_name': 'body_part_tbd'\n },\n 'dtype': 'body_part_t' \n }\n },\n 'sed': {\n 'sed_type': {\n 'name': 'sed_type',\n 'attrs': {\n 'long_name': 'Sediment type',\n 'standard_name': 'sediment_type_tbd'\n },\n 'dtype': 'sed_type_t'\n }\n },\n 'suffixes': {\n 'uncertainty': {\n 'name': '_unc',\n 'attrs': {\n 'long_name': ' uncertainty',\n 'standard_name': '_uncertainty'\n },\n 'dtype': 'f4'\n },\n 'detection_limit': {\n 'name': '_dl',\n 'attrs': {\n 'long_name': ' detection limit',\n 'standard_name': '_detection_limit'\n },\n 'dtype': 'dl_t'\n },\n 'volume': {\n 'name': '_vol',\n 'attrs': {\n 'long_name': ' volume',\n 'standard_name': '_volume'\n },\n 'dtype': 'f4'\n },\n 'salinity': {\n 'name': '_sal',\n 'attrs': {\n 'long_name': ' salinity',\n 'standard_name': '_sal'\n },\n 'dtype': 'f4'\n },\n 'temperature': {\n 'name': '_temp',\n 'attrs': {\n 'long_name': ' temperature',\n 'standard_name': '_temp'\n },\n 'dtype': 'f4'\n },\n 'filtered': {\n 'name': '_filt',\n 'attrs': {\n 'long_name': ' filtered',\n 'standard_name': '_filtered'\n },\n 'dtype': 'filt_t'\n },\n 'counting_method': {\n 'name': '_counmet',\n 'attrs': {\n 'long_name': ' counting method',\n 'standard_name': '_counting_method'\n },\n 'dtype': 'counmet_t'\n },\n 'sampling_method': {\n 'name': '_sampmet',\n 'attrs': {\n 'long_name': ' sampling method',\n 'standard_name': '_sampling_method'\n },\n 'dtype': 'sampmet_t'\n },\n 'preparation_method': {\n 'name': '_prepmet',\n 'attrs': {\n 'long_name': ' preparation method',\n 'standard_name': '_preparation_method'\n },\n 'dtype': 'prepmet_t'\n },\n 'unit': {\n 'name': '_unit',\n 'attrs': {\n 'long_name': ' unit',\n 'standard_name': '_unit'\n },\n 'dtype': 'unit_t'\n }\n }\n },\n 'enums': [\n {\n 'name': 'area_t', \n 'fname': 'dbo_area.xlsx', \n 'key': 'displayName', \n 'value':'areaId'\n },\n {\n 'name': 'bio_group_t', \n 'fname': 'dbo_biogroup.xlsx', \n 'key': 'biogroup', \n 'value':'biogroup_id'\n },\n {\n 'name': 'body_part_t', \n 'fname': 'dbo_bodypar.xlsx', \n 'key': 'bodypar', \n 'value':'bodypar_id'\n },\n {\n 'name': 'species_t', \n 'fname': 'dbo_species_cleaned.xlsx', \n 'key': 'species', \n 'value':'species_id'\n },\n {\n 'name': 'sed_type_t', \n 'fname': 'dbo_sedtype.xlsx', \n 'key': 'sedtype', \n 'value':'sedtype_id'\n },\n {\n 'name': 'unit_t', \n 'fname': 'dbo_unit.xlsx', \n 'key': 'unit_sanitized', \n 'value':'unit_id'\n },\n {\n 'name': 'dl_t', \n 'fname': 'dbo_detectlimit.xlsx', \n 'key': 'name_sanitized', \n 'value':'id'\n },\n {\n 'name': 'filt_t', \n 'fname': 'dbo_filtered.xlsx', \n 'key': 'name',\n 'value':'id'\n },\n {\n 'name': 'counmet_t', \n 'fname': 'dbo_counmet.xlsx', \n 'key': 'counmet',\n 'value':'counmet_id'\n },\n {\n 'name': 'sampmet_t', \n 'fname': 'dbo_sampmet.xlsx', \n 'key': 'sampmet',\n 'value':'sampmet_id'\n },\n {\n 'name': 'prepmet_t', \n 'fname': 'dbo_prepmet.xlsx', \n 'key': 'prepmet',\n 'value':'prepmet_id'\n }\n ]\n}\n\n\n\nfc.AttrDict(CONFIGS_CDL['vars']['defaults'])\n\n{ 'area': { 'attrs': { 'long_name': 'Marine area/region id',\n 'standard_name': 'area_id'},\n 'dtype': 'area_t',\n 'name': 'area'},\n 'lat': { 'attrs': { '_CoordinateAxisType': 'Lat',\n 'axis': 'X',\n 'long_name': 'Measurement latitude',\n 'standard_name': 'latitude',\n 'units': 'degrees_east'},\n 'dtype': 'f4',\n 'name': 'lat'},\n 'lon': { 'attrs': { '_CoordinateAxisType': 'Lon',\n 'axis': 'Y',\n 'long_name': 'Measurement longitude',\n 'standard_name': 'longitude',\n 'units': 'degrees_north'},\n 'dtype': 'f4',\n 'name': 'lon'},\n 'smp_depth': { 'attrs': { 'axis': 'Z',\n 'long_name': 'Sample depth below seal level',\n 'standard_name': 'sample_depth_below_sea_floor',\n 'units': 'm'},\n 'dtype': 'f4',\n 'name': 'smp_depth'},\n 'time': { 'attrs': { 'abbreviation': 'Date/Time',\n 'axis': 'T',\n 'calendar': 'gregorian',\n 'long_name': 'Time of measurement',\n 'standard_name': 'time',\n 'time_origin': '1970-01-01 00:00:00',\n 'time_zone': 'UTC',\n 'units': 'seconds since 1970-01-01 00:00:00.0'},\n 'dtype': 'u8',\n 'name': 'time'},\n 'tot_depth': { 'attrs': { 'axis': 'Z',\n 'long_name': 'Total depth below seal level',\n 'standard_name': 'total_depth_below_sea_floor',\n 'units': 'm'},\n 'dtype': 'f4',\n 'name': 'tot_depth'}}\n\n\n\nwrite_toml(Path('./files') / CDL_FNAME, CONFIGS_CDL)\n\nCreating files/cdl.toml\n\n\n\nsource\n\n\ncdl_cfg\n\n cdl_cfg ()\n\n\n\nExported source\ndef cdl_cfg(): return read_toml(base_path() / CDL_FNAME)\n\n\n\nsource\n\n\nspecies_lut_path\n\n species_lut_path ()\n\n\n\nExported source\ndef species_lut_path():\n src_dir = lut_path()\n fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'species_t'][0]['fname']\n return src_dir / fname\n\n\n\nsource\n\n\nbodyparts_lut_path\n\n bodyparts_lut_path ()\n\n\n\nExported source\ndef bodyparts_lut_path():\n src_dir = lut_path()\n fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'body_part_t'][0]['fname']\n return src_dir / fname\n\n\n\nsource\n\n\nbiogroup_lut_path\n\n biogroup_lut_path ()\n\n\n\nExported source\ndef biogroup_lut_path():\n src_dir = lut_path()\n fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'bio_group_t'][0]['fname']\n return src_dir / fname\n\n\n\nsource\n\n\nsediments_lut_path\n\n sediments_lut_path ()\n\n\n\nExported source\ndef sediments_lut_path():\n src_dir = lut_path()\n fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'sed_type_t'][0]['fname']\n return src_dir / fname\n\n\n\nsource\n\n\nunit_lut_path\n\n unit_lut_path ()\n\n\n\nExported source\ndef unit_lut_path():\n src_dir = lut_path()\n fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'unit_t'][0]['fname']\n return src_dir / fname\n\n\n\nsource\n\n\ndetection_limit_lut_path\n\n detection_limit_lut_path ()\n\n\n\nExported source\ndef detection_limit_lut_path():\n src_dir = lut_path()\n fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'dl_t'][0]['fname']\n return src_dir / fname\n\n\n\nsource\n\n\nfiltered_lut_path\n\n filtered_lut_path ()\n\n\n\nExported source\ndef filtered_lut_path():\n src_dir = lut_path()\n fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'filt_t'][0]['fname']\n return src_dir / fname\n\n\n\nsource\n\n\narea_lut_path\n\n area_lut_path ()\n\n\n\nExported source\ndef area_lut_path():\n src_dir = lut_path()\n fname = [enum for enum in cdl_cfg()['enums'] if enum['name'] == 'area_t'][0]['fname']\n return src_dir / fname", + "crumbs": [ + "API", + "Configs" + ] + }, + { + "objectID": "api/configs.html#utilities-function", + "href": "api/configs.html#utilities-function", + "title": "Configs", + "section": "Utilities function", + "text": "Utilities function\n\nsource\n\nname2grp\n\n name2grp (name:str, cdl:dict)\n\n\n\n\n\nType\nDetails\n\n\n\n\nname\nstr\nName of the group\n\n\ncdl\ndict\nCDL configuration\n\n\n\n\n\nExported source\nNETCDF_TO_PYTHON_TYPE = {\n 'u8': int,\n 'f4': float\n }\n\n\n\n\nExported source\ndef name2grp(\n name:str, # Name of the group\n cdl:dict, # CDL configuration\n ):\n # Reverse `cdl.toml` config group dict so that group config key can be retrieve based on its name\n return {v['name']:k for k, v in cdl['grps'].items()}[name]\n\n\nExample:\n\nname2grp('seawater', cdl=CONFIGS_CDL)\n\n'sea'\n\n\n\nsource\n\n\nnc_tpl_name\n\n nc_tpl_name ()\n\n\n\nExported source\ndef nc_tpl_name():\n p = base_path()\n return read_toml(p / 'configs.toml')['names']['nc_template']\n\n\n\nsource\n\n\nnc_tpl_path\n\n nc_tpl_path ()\n\nReturn the name of the MARIS NetCDF template as defined in configs.toml\n\n\nExported source\ndef nc_tpl_path():\n \"Return the name of the MARIS NetCDF template as defined in `configs.toml`\"\n p = base_path()\n return p / read_toml(p / 'configs.toml')['names']['nc_template']", + "crumbs": [ + "API", + "Configs" + ] + }, + { + "objectID": "api/configs.html#enumeration-types", + "href": "api/configs.html#enumeration-types", + "title": "Configs", + "section": "Enumeration types", + "text": "Enumeration types\nEnumeration types are used to avoid using strings as NetCDF4 variable values. Instead, enumeration types (lookup tables) such as {'Crustaceans': 2, 'Echinoderms': 3, ...} are prepended to the NetCDF file template and associated ids (integers) are used as values.\n\nsource\n\nsanitize\n\n sanitize (s:Union[str,float])\n\n*Sanitize dictionary key to comply with NetCDF enumeration type:\n\nremove (, ), ., /, -\n\nstrip the string*\n\n\n\n\n\nType\nDetails\n\n\n\n\ns\nUnion\nString to sanitize\n\n\nReturns\nstr\nSanitized string\n\n\n\n\n\nExported source\ndef sanitize(s:Union[str, float] # String to sanitize\n ) -> str: # Sanitized string\n \"\"\"\n Sanitize dictionary key to comply with NetCDF enumeration type: \n \n - remove `(`, `)`, `.`, `/`, `-` \n - strip the string\n \"\"\"\n if isinstance(s, str):\n s = re.sub(r'[().]', '', s)\n return re.sub(r'[/-]', ' ', s).strip()\n elif pd.isna(s): # This covers np.nan, None, and pandas NaT\n return s\n else:\n return str(s).strip()\n\n\nFor example:\n\nfc.test_eq(sanitize('key (sanitized)'), 'key sanitized')\nfc.test_eq(sanitize('key san.itized'), 'key sanitized')\nfc.test_eq(sanitize('key-sanitized'), 'key sanitized')\nfc.test_eq(sanitize('key/sanitized'), 'key sanitized')\n\nNetCDF4 enumeration type seems to not accept keys containing non alphanumeric characters like parentheses, dots, slash, … As a result, MARIS lookup table needs to be sanitized.\n\nsource\n\n\nget_lut\n\n get_lut (src_dir:str, fname:str, key:str, value:str,\n do_sanitize:bool=True, reverse:bool=False)\n\nConvert MARIS db lookup table excel file to dictionary {'name': id, ...} or {id: name, ...} if reverse is True.\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nsrc_dir\nstr\n\nDirectory containing lookup tables\n\n\nfname\nstr\n\nExcel file lookup table name\n\n\nkey\nstr\n\nExcel file column name to be used as dict keys\n\n\nvalue\nstr\n\nExcel file column name to be used as dict values\n\n\ndo_sanitize\nbool\nTrue\nSanitization required?\n\n\nreverse\nbool\nFalse\nReverse lookup table (value, key)\n\n\nReturns\ndict\n\nMARIS lookup table (key, value)\n\n\n\n\n\nExported source\ndef get_lut(src_dir:str, # Directory containing lookup tables\n fname:str, # Excel file lookup table name\n key:str, # Excel file column name to be used as dict keys \n value:str, # Excel file column name to be used as dict values \n do_sanitize:bool=True, # Sanitization required?\n reverse:bool=False # Reverse lookup table (value, key)\n ) -> dict: # MARIS lookup table (key, value)\n \"Convert MARIS db lookup table excel file to dictionary `{'name': id, ...}` or `{id: name, ...}` if `reverse` is True.\"\n fname = Path(src_dir) / fname\n df = pd.read_excel(fname, usecols=[key, value]).dropna(subset=value)\n df[value] = df[value].astype('int')\n df = df.set_index(key)\n lut = df[value].to_dict()\n if do_sanitize: lut = {sanitize(k): v for k, v in lut.items()}\n return {v: k for k,v in lut.items()} if reverse else lut\n\n\nFor example:\n\nlut_src_dir = './files/lut'\nget_lut(lut_src_dir, 'dbo_biogroup.xlsx', key='biogroup', value='biogroup_id', reverse=False)\n\n{'Not applicable': -1,\n 'Not available': 0,\n 'Birds': 1,\n 'Crustaceans': 2,\n 'Echinoderms': 3,\n 'Fish': 4,\n 'Mammals': 5,\n 'Molluscs': 6,\n 'Others': 7,\n 'Plankton': 8,\n 'Polychaete worms': 9,\n 'Reptile': 10,\n 'Seaweeds and plants': 11,\n 'Cephalopods': 12,\n 'Gastropods': 13,\n 'Bivalves': 14}\n\n\n\nsource\n\n\nEnums\n\n Enums (lut_src_dir:str, cdl_enums:dict)\n\nReturn dictionaries of MARIS NetCDF’s enumeration types\n\n\nExported source\nclass Enums():\n \"Return dictionaries of MARIS NetCDF's enumeration types\"\n def __init__(self, \n lut_src_dir:str,\n cdl_enums:dict\n ):\n fc.store_attr()\n self.types = self.lookup()\n \n def filter(self, name, values):\n return {name: id for name, id in self.types[name].items() if id in values}\n \n def lookup(self):\n types = {}\n for enum in self.cdl_enums:\n name, fname, key, value = enum.values()\n lut = get_lut(self.lut_src_dir, fname, key=key, value=value)\n types[name] = lut\n return types\n\n\n\nlut_src_dir_test = './files/lut'\ncdl_enums_test = read_toml('./files/cdl.toml')['enums']\n\nenums = Enums(lut_src_dir=lut_src_dir_test, \n cdl_enums=cdl_enums_test)\n\n\nenums.types['dl_t']\n\n{'Not applicable': -1,\n 'Not available': 0,\n 'Detected value': 1,\n 'Detection limit': 2,\n 'Not detected': 3,\n 'Derived': 4}\n\n\n\nenums.types['unit_t']\n\n{'Not applicable': -1,\n 'NOT AVAILABLE': 0,\n 'Bq per m3': 1,\n 'Bq per m2': 2,\n 'Bq per kg': 3,\n 'Bq per kgd': 4,\n 'Bq per kgw': 5,\n 'kg per kg': 6,\n 'TU': 7,\n 'DELTA per mill': 8,\n 'atom per kg': 9,\n 'atom per kgd': 10,\n 'atom per kgw': 11,\n 'atom per l': 12,\n 'Bq per kgC': 13}\n\n\n\n# {f'{var}_t': enums.subset('species_t', tfm.unique(var) for var in ['species']}\n\n\n# subset = {}\n# for var, values in [('species', [21, 50, 59, 84]),\n# ('area', [2, 3])]:\n# # values = tfm.unique(var)\n# type_name = f'{var}_t'\n# subset[type_name] = enums.filter(type_name, [21, 50, 59, 84])\n\n\nsource\n\n\nget_enum_dicts\n\n get_enum_dicts (lut_src_dir:str, cdl_enums:dict, **kwargs)\n\nReturn a dict of NetCDF enumeration types\n\n\nExported source\ndef get_enum_dicts(\n lut_src_dir:str,\n cdl_enums:dict,\n **kwargs\n ):\n \"Return a dict of NetCDF enumeration types\"\n enum_types = {}\n for enum in cdl_enums:\n name, fname, key, value = enum.values()\n lut = get_lut(lut_src_dir, fname, key=key, value=value, **kwargs)\n enum_types[name] = lut\n \n return enum_types\n\n\nFor example:\n\nlut_src_dir_test = './files/lut'\ncdl_enums_test = read_toml('./files/cdl.toml')['enums']\n\nenums = get_enum_dicts(lut_src_dir=lut_src_dir_test, \n cdl_enums=cdl_enums_test)\nenums.keys()\n\ndict_keys(['area_t', 'bio_group_t', 'body_part_t', 'species_t', 'sed_type_t', 'unit_t', 'dl_t', 'filt_t', 'counmet_t', 'sampmet_t', 'prepmet_t'])", + "crumbs": [ + "API", + "Configs" + ] + }, + { + "objectID": "api/callbacks.html", + "href": "api/callbacks.html", + "title": "Callbacks", + "section": "", + "text": "Exported source\nimport copy\nimport fastcore.all as fc\nfrom operator import attrgetter\nfrom cftime import date2num\nimport numpy as np\nimport pandas as pd\nfrom marisco.configs import cfg, cdl_cfg\nfrom functools import partial \nfrom typing import List, Dict, Callable, Tuple\nfrom pathlib import Path \n\nfrom marisco.configs import get_lut, nuc_lut_path", + "crumbs": [ + "API", + "Callbacks" + ] + }, + { + "objectID": "api/callbacks.html#core", + "href": "api/callbacks.html#core", + "title": "Callbacks", + "section": "Core", + "text": "Core\nThe Transformer class is designed to facilitate the application of a series of callbacks to a set of dataframes. It provides a structured way to apply transformations (i.e Callback) to the data, with a focus on flexibility and ease of use.\n\nsource\n\nCallback\n\n Callback ()\n\nBase class for callbacks.\n\n\nExported source\nclass Callback(): \n \"Base class for callbacks.\"\n order = 0\n\n\n\nsource\n\n\nrun_cbs\n\n run_cbs (cbs, obj=None)\n\nRun the callbacks in the order they are specified.\n\n\nExported source\ndef run_cbs(cbs, obj=None):\n \"Run the callbacks in the order they are specified.\"\n for cb in sorted(cbs, key=attrgetter('order')):\n if cb.__doc__: obj.logs.append(cb.__doc__)\n cb(obj)\n\n\n\nsource\n\n\nTransformer\n\n Transformer (dfs:pandas.core.frame.DataFrame, cbs:list=None,\n inplace:bool=False)\n\nTransform the dataframes according to the specified callbacks.\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ndfs\nDataFrame\n\nDictionary of DataFrames to transform\n\n\ncbs\nlist\nNone\nList of callbacks to run\n\n\ninplace\nbool\nFalse\nWhether to modify the dataframes in place\n\n\n\n\n\nExported source\nclass Transformer():\n def __init__(self, \n dfs:pd.DataFrame, # Dictionary of DataFrames to transform\n cbs:list=None, # List of callbacks to run\n inplace:bool=False # Whether to modify the dataframes in place\n ): \n \"Transform the dataframes according to the specified callbacks.\"\n fc.store_attr()\n self.dfs = dfs if inplace else {k: v.copy() for k, v in dfs.items()}\n self.logs = []\n \n def unique(self, col_name):\n \"Distinct values of a specific column present in all groups.\"\n columns = [df.get(col_name) for df in self.dfs.values() if df.get(col_name) is not None]\n values = np.concatenate(columns) if columns else []\n return np.unique(values)\n \n def __call__(self):\n \"Transform the dataframes according to the specified callbacks.\"\n if self.cbs: run_cbs(self.cbs, self)\n return self.dfs\n\n\nBelow, a few examples of how to use the Transformer class. Let’s define first a test callback that adds 1 to the depth:\n\nclass TestCB(Callback):\n \"A test callback to add 1 to the depth.\"\n def __call__(self, tfm):\n for grp, df in tfm.dfs.items(): \n df['depth'] = df['depth'].apply(lambda x: x+1)\n\nAnd apply it to the following dataframes:\n\ndfs = {'biota': pd.DataFrame({'id': [0, 1, 2], 'species': [0, 2, 0], 'depth': [2, 3, 4]}),\n 'seawater': pd.DataFrame({'id': [0, 1, 2], 'depth': [3, 4, 5]})}\n\ntfm = Transformer(dfs, cbs=[TestCB()])\ndf_test = tfm()\n\nfc.test_eq(df_test['biota']['depth'].to_list(), [3, 4, 5])\nfc.test_eq(df_test['seawater']['depth'].to_list(), [4, 5, 6])", + "crumbs": [ + "API", + "Callbacks" + ] + }, + { + "objectID": "api/callbacks.html#geographical", + "href": "api/callbacks.html#geographical", + "title": "Callbacks", + "section": "Geographical", + "text": "Geographical\nThis section gathers callbacks that are used to transform the geographical coordinates.\n\nsource\n\nSanitizeLonLatCB\n\n SanitizeLonLatCB (verbose=False)\n\nDrop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude , separator to . separator.\n\n\nExported source\nclass SanitizeLonLatCB(Callback):\n \"Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator.\"\n def __init__(self, verbose=False): fc.store_attr()\n def __call__(self, tfm):\n for grp, df in tfm.dfs.items():\n \" Convert `,` separator to `.` separator\"\n df['lon'] = [float(str(x).replace(',', '.')) for x in df['lon']]\n df['lat'] = [float(str(x).replace(',', '.')) for x in df['lat']]\n \n # mask zero values\n mask_zeroes = (df.lon == 0) & (df.lat == 0) \n nZeroes = mask_zeroes.sum()\n if nZeroes and self.verbose: \n print(f'The \"{grp}\" group contains {nZeroes} data points whose (lon, lat) = (0, 0)')\n \n # mask gps out of bounds, goob. \n mask_goob = (df.lon < -180) | (df.lon > 180) | (df.lat < -90) | (df.lat > 90)\n nGoob = mask_goob.sum()\n if nGoob and self.verbose: \n print(f'The \"{grp}\" group contains {nGoob} data points whose lon or lat are unrealistic. Outside -90 to 90 for latitude and -180 to 180 for longitude.')\n \n tfm.dfs[grp] = df.loc[~(mask_zeroes | mask_goob)]\n\n\n\n# Check that measurements located at (0,0) get removed\ndfs = {'biota': pd.DataFrame({'lon': [0, 1, 0], 'lat': [0, 2, 0]})}\ntfm = Transformer(dfs, cbs=[SanitizeLonLatCB()])\ntfm()['biota']\n\nexpected = [1., 2.]\nfc.test_eq(tfm()['biota'].iloc[0].to_list(), expected)\n\n\n# Check that comma decimal separator get replaced by point instead\ndfs = {'biota': pd.DataFrame({'lon': ['45,2'], 'lat': ['43,1']})}\ntfm = Transformer(dfs, cbs=[SanitizeLonLatCB()])\ntfm()['biota']\n\nexpected = [45.2, 43.1]\nfc.test_eq(tfm()['biota'].iloc[0].to_list(), expected)\n\n\n# Check that out of bounds lon or lat get removed\ndfs = {'biota': pd.DataFrame({'lon': [-190, 190, 1, 2, 1.1], 'lat': [1, 2, 91, -91, 2.2]})}\ntfm = Transformer(dfs, cbs=[SanitizeLonLatCB()])\ntfm()['biota']\n\nexpected = [1.1, 2.2]\nfc.test_eq(tfm()['biota'].iloc[0].to_list(), expected)", + "crumbs": [ + "API", + "Callbacks" + ] + }, + { + "objectID": "api/callbacks.html#add-columns", + "href": "api/callbacks.html#add-columns", + "title": "Callbacks", + "section": "Add columns", + "text": "Add columns\nThis section gathers callbacks that are used to add required columns to the dataframes.\n\nsource\n\nAddSampleTypeIdColumnCB\n\n AddSampleTypeIdColumnCB (cdl_cfg:Callable=<function cdl_cfg>,\n col_name:str='samptype_id')\n\nBase class for callbacks.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncdl_cfg\nCallable\ncdl_cfg\nCallable to get the CDL config dictionary\n\n\ncol_name\nstr\nsamptype_id\n\n\n\n\n\n\nExported source\nclass AddSampleTypeIdColumnCB(Callback):\n def __init__(self, \n cdl_cfg:Callable=cdl_cfg, # Callable to get the CDL config dictionary\n col_name:str='samptype_id'\n ): \n \"Add a column with the sample type id as defined in the CDL.\"\n fc.store_attr()\n self.lut = {v['name']: v['id'] for v in cdl_cfg()['grps'].values()}\n \n def __call__(self, tfm):\n for grp, df in tfm.dfs.items(): df[self.col_name] = self.lut[grp]\n\n\nLet’s test the callback:\n\ndfs = {v['name']: pd.DataFrame({'col_test': [0, 1, 2]}) for v in CONFIGS_CDL['grps'].values()}\n\ntfm = Transformer(dfs, cbs=[AddSampleTypeIdColumnCB(cdl_cfg=lambda: CONFIGS_CDL)])\ndfs_test = tfm()\n\nfor v in CONFIGS_CDL['grps'].values():\n fc.test_eq(dfs_test[v['name']]['samptype_id'].unique().item(), v['id'])\n\n\nsource\n\n\nAddNuclideIdColumnCB\n\n AddNuclideIdColumnCB (col_value:str, lut_fname_fn:<built-\n infunctioncallable>=<function nuc_lut_path>,\n col_name:str='nuclide_id')\n\nBase class for callbacks.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncol_value\nstr\n\nColumn name containing the nuclide name\n\n\nlut_fname_fn\ncallable\nnuc_lut_path\nFunction returning the lut path\n\n\ncol_name\nstr\nnuclide_id\nColumn name to store the nuclide id\n\n\n\n\n\nExported source\nclass AddNuclideIdColumnCB(Callback):\n def __init__(self, \n col_value:str, # Column name containing the nuclide name\n lut_fname_fn:callable=nuc_lut_path, # Function returning the lut path\n col_name:str='nuclide_id' # Column name to store the nuclide id\n ): \n \"Add a column with the nuclide id.\"\n fc.store_attr()\n self.lut = get_lut(lut_fname_fn().parent, lut_fname_fn().name, \n key='nc_name', value='nuclide_id', reverse=False)\n \n def __call__(self, tfm):\n for grp, df in tfm.dfs.items(): \n df[self.col_name] = df[self.col_value].map(self.lut)\n\n\n\ndfs = {v['name']: pd.DataFrame({'Nuclide': ['cs137', 'pu239_240_tot']}) for v in CONFIGS_CDL['grps'].values()}\n\nlut_fname_fn = lambda: Path('./files/lut/dbo_nuclide.xlsx')\n\ntfm = Transformer(dfs, cbs=[AddNuclideIdColumnCB(col_value='Nuclide', lut_fname_fn=lut_fname_fn)])\ntfm()['seawater']\n\nexpected = [33, 77]\nfor grp in tfm.dfs.keys():\n fc.test_eq(tfm.dfs[grp]['nuclide_id'].to_list(), expected)", + "crumbs": [ + "API", + "Callbacks" + ] + }, + { + "objectID": "api/callbacks.html#map-standardize", + "href": "api/callbacks.html#map-standardize", + "title": "Callbacks", + "section": "Map & Standardize", + "text": "Map & Standardize\n\nsource\n\nLowerStripNameCB\n\n LowerStripNameCB (col_src:str, col_dst:str=None,\n fn_transform:Callable=<function <lambda>>)\n\nBase class for callbacks.\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncol_src\nstr\n\nSource column name e.g. ‘Nuclide’\n\n\ncol_dst\nstr\nNone\nDestination column name\n\n\nfn_transform\nCallable\n\nTransformation function\n\n\n\n\n\nExported source\nclass LowerStripNameCB(Callback):\n def __init__(self, \n col_src:str, # Source column name e.g. 'Nuclide'\n col_dst:str=None, # Destination column name\n fn_transform:Callable=lambda x: x.lower().strip() # Transformation function\n ):\n \"Convert values to lowercase and strip any trailing spaces.\"\n fc.store_attr()\n self.__doc__ = f\"Convert values from '{col_src}' to lowercase, strip spaces, and store in '{col_dst}'.\"\n if not col_dst: self.col_dst = col_src\n \n def _safe_transform(self, value):\n \"Ensure value is not NA and apply transformation function.\"\n return value if pd.isna(value) else self.fn_transform(str(value))\n \n def __call__(self, tfm):\n for key in tfm.dfs.keys():\n tfm.dfs[key][self.col_dst] = tfm.dfs[key][self.col_src].apply(self._safe_transform)\n\n\nLet’s test the callback:\n\ndfs = {'seawater': pd.DataFrame({'Nuclide': ['CS137', '226RA']})}\n\ntfm = Transformer(dfs, cbs=[LowerStripNameCB(col_src='Nuclide', col_dst='NUCLIDE')])\nfc.test_eq(tfm()['seawater']['NUCLIDE'].to_list(), ['cs137', '226ra'])\n\n\ntfm = Transformer(dfs, cbs=[LowerStripNameCB(col_src='Nuclide')])\nfc.test_eq(tfm()['seawater']['Nuclide'].to_list(), ['cs137', '226ra'])\n\nThe point is when (semi-automatic) remapping names generally:\n\nwe need first to guess (fuzzy matching or other) the right nuclide name.\nThen manually check the result and eventually update the lookup table.\nFinally we can apply the lookup table to the dataframe.", + "crumbs": [ + "API", + "Callbacks" + ] + }, + { + "objectID": "api/callbacks.html#change-structure", + "href": "api/callbacks.html#change-structure", + "title": "Callbacks", + "section": "Change structure", + "text": "Change structure\nMany data providers use a long format (e.g lat, lon, radionuclide, value, unc, ...) to store their data. When encoding as netCDF, it is often required to use a wide format (e.g lat, lon, nuclide1_value, nuclide1_unc, nuclide2_value, nuclide2_unc, ...). The class ReshapeLongToWide is designed to perform this transformation.\n\nsource\n\nReshapeLongToWide\n\n ReshapeLongToWide (columns=['nuclide'], values=['value'],\n num_fill_value=-999, str_fill_value='STR FILL VALUE')\n\nBase class for callbacks.\n\n\nExported source\nclass ReshapeLongToWide(Callback):\n def __init__(self, columns=['nuclide'], values=['value'], \n num_fill_value=-999, str_fill_value='STR FILL VALUE'):\n \"Convert data from long to wide with renamed columns.\"\n fc.store_attr()\n self.derived_cols = self._get_derived_cols()\n \n def _get_derived_cols(self):\n \"Retrieve all possible derived vars (e.g 'unc', 'dl', ...) from configs.\"\n return [value['name'] for value in cdl_cfg()['vars']['suffixes'].values()]\n\n def renamed_cols(self, cols):\n \"Flatten columns name.\"\n return [inner if outer == \"value\" else f'{inner}{outer}' if inner else outer\n for outer, inner in cols]\n\n def _get_unique_fill_value(self, df, idx):\n \"Get a unique fill value for NaN replacement.\"\n fill_value = self.num_fill_value\n while (df[idx] == fill_value).any().any():\n fill_value -= 1\n return fill_value\n\n def _fill_nan_values(self, df, idx):\n \"Fill NaN values in index columns.\"\n num_fill_value = self._get_unique_fill_value(df, idx)\n for col in idx:\n fill_value = num_fill_value if pd.api.types.is_numeric_dtype(df[col]) else self.str_fill_value\n df[col] = df[col].fillna(fill_value)\n return df, num_fill_value\n\n def pivot(self, df):\n derived_coi = [col for col in self.derived_cols if col in df.columns]\n df.index.name = 'org_index'\n df = df.reset_index()\n idx = list(set(df.columns) - set(self.columns + derived_coi + self.values))\n \n df, num_fill_value = self._fill_nan_values(df, idx)\n\n pivot_df = df.pivot_table(index=idx,\n columns=self.columns,\n values=self.values + derived_coi,\n fill_value=np.nan,\n aggfunc=lambda x: x).reset_index()\n\n pivot_df[idx] = pivot_df[idx].replace({self.str_fill_value: np.nan, num_fill_value: np.nan})\n return pivot_df.set_index('org_index')\n\n def __call__(self, tfm):\n for grp in tfm.dfs.keys():\n tfm.dfs[grp] = self.pivot(tfm.dfs[grp])\n tfm.dfs[grp].columns = self.renamed_cols(tfm.dfs[grp].columns)\n\n\n\ndfs_test = fc.load_pickle('./files/pkl/dfs_reshape_test_in.pkl')\ndfs_expected = fc.load_pickle('./files/pkl/dfs_reshape_test_expected.pkl')\n\ntfm = Transformer(dfs_test, cbs=[ReshapeLongToWide()])\ndfs_output = tfm()\ntest_dfs(dfs_output, dfs_expected)\n\n\nsource\n\n\nCompareDfsAndTfmCB\n\n CompareDfsAndTfmCB (dfs:Dict[str,pandas.core.frame.DataFrame])\n\nBase class for callbacks.\n\n\nExported source\nclass CompareDfsAndTfmCB(Callback):\n def __init__(self, dfs: Dict[str, pd.DataFrame]): \n \"Create a dataframe of dropped data. Data included in the `dfs` not in the `tfm`.\"\n fc.store_attr()\n \n def __call__(self, tfm: Transformer) -> None:\n self._initialize_tfm_attributes(tfm)\n for grp in tfm.dfs.keys():\n dropped_df = self._get_dropped_data(grp, tfm)\n tfm.dfs_dropped[grp] = dropped_df\n tfm.compare_stats[grp] = self._compute_stats(grp, tfm)\n\n def _initialize_tfm_attributes(self, tfm: Transformer) -> None:\n tfm.dfs_dropped = {}\n tfm.compare_stats = {}\n\n def _get_dropped_data(self, \n grp: str, # The group key\n tfm: Transformer # The transformation object containing `dfs`\n ) -> pd.DataFrame: # Dataframe with dropped rows\n \"Get the data that is present in `dfs` but not in `tfm.dfs`.\"\n index_diff = self.dfs[grp].index.difference(tfm.dfs[grp].index)\n return self.dfs[grp].loc[index_diff]\n \n def _compute_stats(self, \n grp: str, # The group key\n tfm: Transformer # The transformation object containing `dfs`\n ) -> Dict[str, int]: # Dictionary with comparison statistics\n \"Compute comparison statistics between `dfs` and `tfm.dfs`.\"\n return {\n 'Number of rows in dfs': len(self.dfs[grp].index),\n 'Number of rows in tfm.dfs': len(tfm.dfs[grp].index),\n 'Number of dropped rows': len(tfm.dfs_dropped[grp].index),\n 'Number of rows in tfm.dfs + Number of dropped rows': len(tfm.dfs[grp].index) + len(tfm.dfs_dropped[grp].index)\n }\n\n\nCompareDfsAndTfmCB compares the original dataframes to the transformed dataframe. A dictionary of dataframes, tfm.dfs_dropped, is created to include the data present in the original dataset but absent from the transformed data. tfm.compare_stats provides a quick overview of the number of rows in both the original dataframes and the transformed dataframe.\nFor instance:\n\ndfs_test = {\n 'seawater': pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]}),\n 'sediment': pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]}),\n}\n\nclass TestTfmCB(Callback):\n def __call__(self, tfm):\n for key in tfm.dfs.keys():\n df = tfm.dfs[key]\n drop_idxs = [0, 1] if key == 'seawater' else [0]\n df.drop(drop_idxs, inplace=True)\n \ntfm = Transformer(dfs_test, cbs=[\n TestTfmCB(), \n CompareDfsAndTfmCB(dfs_test)], inplace=False)\n\nprint(tfm())\n\nfc.test_eq(tfm.compare_stats['seawater']['Number of dropped rows'], 2)\nfc.test_eq(tfm.compare_stats['sediment']['Number of dropped rows'], 1)\n\n{'seawater': a b\n2 3 6, 'sediment': a b\n1 2 5\n2 3 6}", + "crumbs": [ + "API", + "Callbacks" + ] + }, + { + "objectID": "api/callbacks.html#time", + "href": "api/callbacks.html#time", + "title": "Callbacks", + "section": "Time", + "text": "Time\nThese callbacks are used to transform the time variable according to netCDF CF standards. For instance, the EncodeTimeCB callback is used to encode the time variable as an integer representing seconds since a reference date as specified in configs.ipynb CONFIGS_CDL dictionary.\n\nsource\n\nEncodeTimeCB\n\n EncodeTimeCB (cfg, verbose=False)\n\nEncode time as int representing seconds since xxx\n\n\nExported source\nclass EncodeTimeCB(Callback):\n \"Encode time as `int` representing seconds since xxx\" \n def __init__(self, cfg , verbose=False): fc.store_attr()\n def __call__(self, tfm): \n def format_time(x): \n return date2num(x, units=self.cfg['units']['time'])\n \n for k in tfm.dfs.keys():\n # If invalid time entries.\n if tfm.dfs[k]['time'].isna().any():\n if self.verbose:\n invalid_time_df=tfm.dfs[k][tfm.dfs[k]['time'].isna()]\n print (f'{len(invalid_time_df.index)} of {len(tfm.dfs[k].index)} entries for `time` are invalid for {k}.')\n # Filter nan values\n tfm.dfs[k] = tfm.dfs[k][tfm.dfs[k]['time'].notna()]\n \n tfm.dfs[k]['time'] = tfm.dfs[k]['time'].apply(format_time)", + "crumbs": [ + "API", + "Callbacks" + ] + }, + { + "objectID": "api/inout.html", + "href": "api/inout.html", + "title": "Input/Output", + "section": "", + "text": "source\n\nwrite_toml\n\n write_toml (fname, cfg)\n\n\nsource\n\n\nread_toml\n\n read_toml (fname)" + }, + { + "objectID": "cli/netcdfy.html", + "href": "cli/netcdfy.html", + "title": "marisco", + "section": "", + "text": "The autoreload extension is already loaded. To reload it, use:\n %reload_ext autoreload\n\n\n\nsource\n\nimport_handler\n\n import_handler (handler_name, fn_name='encode')\n\n\nsource\n\n\nmain\n\n main (handler_name:str, src:str, dest:str)\n\nEncode MARIS dataset as NetCDF\n\n\n\n\nType\nDetails\n\n\n\n\nhandler_name\nstr\nHandler’s name (e.g helcom, …)\n\n\nsrc\nstr\nPath to dataset to encode\n\n\ndest\nstr\nPath to converted NetCDF4" + }, + { + "objectID": "index.html", + "href": "index.html", + "title": "MARISCO", + "section": "", + "text": "The IAEA Marine Radioactivity Information System (MARIS) allows free access to users to search and download the results of measurements of radioactivity in seawater, biota, sediment and suspended matter. MARIS is maintained and developed by the IAEA Environmental Laboratories in Monaco.\nThe current Python package offers command-line utilities for encoding MARIS harvested datasets into NetCDF or .csv formats. This allows to convert MARIS data into a format that is compatible with a wide range of scientific and data analysis tools.", + "crumbs": [ + "MARISCO" + ] + }, + { + "objectID": "index.html#install", + "href": "index.html#install", + "title": "MARISCO", + "section": "Install", + "text": "Install\nNow, to install marisco simply run\npip install marisco\nOnce successfully installed, run the following command:\nmaris_init\nThis command:\n\ncreates a .marisco/ directory containing various configuration/configurable files ((below)) in your /home directory\ncreates a configs.toml file containing default but configurable settings (default paths, …)\ncreates a configurable cdl.toml file used to generate a MARIS NetCDF4 CDL (Common Data Language) template;\ndownloads several MARIS DB nomenclature/lookup table into .marisco/lut/ directory\ngenerate maris-template.nc, the MARIS NetCDF4 template generated from cdl.toml and use to encode MARIS datasets\n\n\n\n\n\n\n\nTip\n\n\n\nFor inexperienced Python users, please refers to How to setup Marisco with Anaconda or How to setup Marisco with Windows Subsystem for Linux (WSL) and Visual Studio Code editor.\n\n\n\nZotero API key\nUpon conversion, marisco will automatically retrieve the bibliographic metadata of each MARIS dataset from Zotero. To do so, you need to define the following environment variable ZOTERO_API_KEY containing the MARIS Zotero API key. Please contact the MARIS team to get your API key.", + "crumbs": [ + "MARISCO" + ] + }, + { + "objectID": "index.html#getting-started", + "href": "index.html#getting-started", + "title": "MARISCO", + "section": "Getting started", + "text": "Getting started\n\nCommand line utilities\nAll commands accept a -h argument to get access to its documentation.\n\nmaris_init\nCreate configuration files, MARIS NetCDF CDL (Common Data Language) and donwload required lookup tables (nomenclatures).\n\n\nmaris_create_nc_template\nGenerate MARIS NetCDF template to be used when encoding datasets\n\n\nmaris_netcdfy\nEncode MARIS dataset as NetCDF\nPositional arguments:\n\nhandler_name: Handler’s name (e.g helcom, …)\nstr: Path to dataset to encode\ndest: Path to converted NetCDF4\n\nExample:\nmaris_netcdfy helcom _data/accdb/mors/csv _data/output/helcom.nc", + "crumbs": [ + "MARISCO" + ] + }, + { + "objectID": "index.html#development", + "href": "index.html#development", + "title": "MARISCO", + "section": "Development", + "text": "Development\n\nFAQ\n\nHow is cdl.toml created & what it is used for?\nA Python dictionary named CONFIGS_CDL specifying MARIS NetCDF attributes, variables, dimensions, … is defined in nbs/api/configs.ipynb in the first instance. Running the command maris_init will generate a toml version of it named .marisco/cdl.toml further used to create a MARIS NetCDF template named in .marisco/maris-template.nc.\nOnce marisco installed, further customization of the MARIS NetCDF template can be done directly through .marisco/cdl.toml file then running the command maris_create_nc_template.", + "crumbs": [ + "MARISCO" + ] + }, + { + "objectID": "cli/init.html", + "href": "cli/init.html", + "title": "marisco", + "section": "", + "text": "The autoreload extension is already loaded. To reload it, use:\n %reload_ext autoreload\n\n\n\nsource\n\nmain\n\n main ()\n\nCreate configuration files & download lookup tables" + }, + { + "objectID": "cli/create_nc_template.html", + "href": "cli/create_nc_template.html", + "title": "marisco", + "section": "", + "text": "source\n\nmain\n\n main (verbose:bool=False)\n\nCreate MARIS NetCDF template, optionally in verbose mode\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nverbose\nbool\nFalse\nVerbose" + }, + { + "objectID": "api/serializers.html", + "href": "api/serializers.html", + "title": "Serializers", + "section": "", + "text": "The autoreload extension is already loaded. To reload it, use:\n %reload_ext autoreload", + "crumbs": [ + "API", + "Serializers" + ] + }, + { + "objectID": "api/serializers.html#netcdf-encoder", + "href": "api/serializers.html#netcdf-encoder", + "title": "Serializers", + "section": "NetCDF encoder", + "text": "NetCDF encoder\n\nsource\n\nNetCDFEncoder\n\n NetCDFEncoder (dfs:dict[pandas.core.frame.DataFrame], src_fname:str,\n dest_fname:str, global_attrs:Dict, enums_xtra:Dict={},\n verbose:bool=False)\n\nMARIS NetCDF encoder.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ndfs\ndict\n\ndict of Dataframes to encode with group name as key {‘sediment’: df_sed, …}\n\n\nsrc_fname\nstr\n\nFile name and path to the MARIS CDL template\n\n\ndest_fname\nstr\n\nName of output file to produce\n\n\nglobal_attrs\nDict\n\nGlobal attributes\n\n\nenums_xtra\nDict\n{}\nEnumeration types to overwrite\n\n\nverbose\nbool\nFalse\nPrint currently written NetCDF group and variable names\n\n\n\n\n\nExported source\nclass NetCDFEncoder:\n \"MARIS NetCDF encoder.\"\n def __init__(self, \n dfs:dict[pd.DataFrame], # dict of Dataframes to encode with group name as key {'sediment': df_sed, ...}\n src_fname:str, # File name and path to the MARIS CDL template\n dest_fname:str, # Name of output file to produce\n global_attrs:Dict, # Global attributes\n enums_xtra:Dict={}, # Enumeration types to overwrite\n verbose:bool=False, # Print currently written NetCDF group and variable names\n ):\n store_attr()\n self.enum_types = {}\n\n\n\ndf_seawater = pd.DataFrame({\n 'sample': [0, 1, 5], \n 'lon': [141, 142, 143], \n 'lat': [37.3, 38.3, 39.3], \n 'time': [1234, 1235, 1236], \n 'i131': [1, 1.5, 2],\n 'i131_dl': [0, 1, 2], \n 'i131_unit': [1, 1, 2],\n 'species': [134, 136, 137]\n })\n\ndf_biota = pd.DataFrame({\n 'sample': [0, 1], \n 'lon': [141, 142], \n 'lat': [37.3, 38.3], \n 'time': [1234, 1235], \n 'i131': [1, 1.5],\n 'i131_dl': [0, 1], \n 'i131_unit': [1, 1],\n 'species': [134, 136]\n })\n\ndfs = {'seawater': df_seawater, 'biota': df_biota}\nattrs = {'id': '123', 'title': 'Test title', 'summary': 'Summary test'}\nsrc = './files/nc/template-test.nc'\ndest = './files/nc/encoding-test.nc'\nenums_xtra = {\n 'species_t': {'Aristeus antennatus': 134, 'Apostichopus': 136}\n }\n\n\nsource\n\n\nNetCDFEncoder.copy_global_attributes\n\n NetCDFEncoder.copy_global_attributes ()\n\nUpdate NetCDF template global attributes as specified by global_attrs argument.\n\n\nExported source\n@patch \ndef copy_global_attributes(self:NetCDFEncoder):\n \"Update NetCDF template global attributes as specified by `global_attrs` argument.\"\n self.dest.setncatts(self.src.__dict__)\n for k, v in self.global_attrs.items(): self.dest.setncattr(k, v)\n\n\n\nsource\n\n\nNetCDFEncoder.copy_dimensions\n\n NetCDFEncoder.copy_dimensions ()\n\n\n\nExported source\n@patch\ndef copy_dimensions(self:NetCDFEncoder):\n for name, dimension in self.src.dimensions.items():\n self.dest.createDimension(name, (len(dimension) if not dimension.isunlimited() else None))\n\n\n\nsource\n\n\nNetCDFEncoder.process_groups\n\n NetCDFEncoder.process_groups ()\n\n\n\nExported source\n@patch\ndef process_groups(self:NetCDFEncoder):\n for grp_name, df in self.dfs.items():\n self.process_group(grp_name, df)\n\n\n\nsource\n\n\nNetCDFEncoder.process_group\n\n NetCDFEncoder.process_group (group_name, df)\n\n\n\nExported source\n@patch\ndef process_group(self:NetCDFEncoder, group_name, df):\n group_dest = self.dest.createGroup(group_name)\n # Set the dimensions for each group\n group_dest.createDimension(group_name, len(df.index)) \n self.copy_variables(group_name, df, group_dest)\n\n\n\nsource\n\n\nNetCDFEncoder.copy_variables\n\n NetCDFEncoder.copy_variables (group_name, df, group_dest)\n\n\n\nExported source\n@patch\ndef copy_variables(self:NetCDFEncoder, group_name, df, group_dest):\n for var_name, var_src in self.src.groups[group_name].variables.items():\n if var_name in df.reset_index().columns: \n self.copy_variable(var_name, var_src, df, group_dest)\n\n\n\nsource\n\n\nNetCDFEncoder.copy_variable\n\n NetCDFEncoder.copy_variable (var_name, var_src, df, group_dest)\n\n\n\nExported source\n@patch\ndef copy_variable(self:NetCDFEncoder, var_name, var_src, df, group_dest):\n dtype_name = var_src.datatype.name\n enums_src = self.src.enumtypes\n if self.verbose: \n print(80*'-')\n print(f'Group: {group_dest.name}, Variable: {var_name}')\n # If the type of the var is an enum (meaning present in the template src) then create it\n if dtype_name in enums_src: self.copy_enum_type(dtype_name) \n self._create_and_copy_variable(var_name, var_src, df, group_dest, dtype_name)\n self.copy_variable_attributes(var_name, var_src, group_dest)\n\n\n\nsource\n\n\nNetCDFEncoder.sanitize_if_enum_and_nan\n\n NetCDFEncoder.sanitize_if_enum_and_nan (values, fill_value=-1)\n\n\n\nExported source\n@patch\ndef _create_and_copy_variable(self:NetCDFEncoder, var_name, var_src, df, group_dest, dtype_name):\n variable_type = self.enum_types.get(dtype_name, var_src.datatype)\n # Use the group_dest dimensions\n group_dest.createVariable(var_name, variable_type, group_dest.dimensions, compression='zlib', complevel=9) \n isNotEnum = type(variable_type) != netCDF4._netCDF4.EnumType\n values = df[var_name].values\n group_dest[var_name][:] = values if isNotEnum else self.sanitize_if_enum_and_nan(values)\n\n\n\n\nExported source\n@patch\ndef sanitize_if_enum_and_nan(self:NetCDFEncoder, values, fill_value=-1):\n values[np.isnan(values)] = int(fill_value)\n values = values.astype(int)\n return values\n\n\n\nsource\n\n\nNetCDFEncoder.copy_enum_type\n\n NetCDFEncoder.copy_enum_type (dtype_name)\n\n\n\nExported source\n@patch\ndef copy_enum_type(self:NetCDFEncoder, dtype_name):\n # if enum type not already created\n if dtype_name not in self.enum_types:\n enum_info = self.src.enumtypes[dtype_name]\n # If a subset of an enum is defined in enums_xtra (typically for the lengthy species_t)\n if enum_info.name in self.enums_xtra:\n # add \"not applicable\"\n enum_info.enum_dict = self.enums_xtra[enum_info.name]\n enum_info.enum_dict['Not applicable'] = -1 # TBD\n self.enum_types[dtype_name] = self.dest.createEnumType(enum_info.dtype, \n enum_info.name, \n enum_info.enum_dict)\n\n\n\nsource\n\n\nNetCDFEncoder.copy_variable_attributes\n\n NetCDFEncoder.copy_variable_attributes (var_name, var_src, group_dest)\n\n\n\nExported source\n@patch\ndef copy_variable_attributes(self:NetCDFEncoder, var_name, var_src, group_dest):\n group_dest[var_name].setncatts(var_src.__dict__)\n\n\n\n# DEPRECATED\n@patch\ndef cast_verbose_rf(self:NetCDFEncoder, \n df, \n col):\n \"\"\"\n Try to cast df column to numeric type:\n - Silently coerce to nan if not possible\n - But log when it failed\n \"\"\"\n n_before = sum(df.reset_index()[col].notna())\n df_after = pd.to_numeric(df.reset_index()[col], errors='coerce', downcast=None)\n n_after = sum(df_after.notna())\n if n_before != n_after: print(f'Failed to convert type of {col} in {n_before - n_after} occurences')\n return df_after\n\n\nsource\n\n\nNetCDFEncoder.encode\n\n NetCDFEncoder.encode ()\n\nEncode MARIS NetCDF based on template and dataframes.\n\n\nExported source\n@patch\ndef encode(self:NetCDFEncoder):\n \"Encode MARIS NetCDF based on template and dataframes.\"\n with Dataset(self.src_fname, format='NETCDF4') as self.src, Dataset(self.dest_fname, 'w', format='NETCDF4') as self.dest:\n self.copy_global_attributes()\n self.copy_dimensions()\n self.process_groups()\n\n\n\nencoder = NetCDFEncoder(dfs, src_fname=src, dest_fname=dest, \n global_attrs=attrs, enums_xtra=enums_xtra, verbose=False)\nencoder.encode()\n\n\n# Test that global attributes are copied\nwith Dataset(dest, 'r', format='NETCDF4') as nc:\n for k, v in {'id': '123', 'title': 'Test title', 'summary': 'Summary test'}.items():\n fc.test_eq(getattr(nc, k), v)\n\n\n# Test that dimension is `sample` and unlimited\nwith Dataset(dest, 'r', format='NETCDF4') as nc:\n fc.test_eq('sample' in nc.dimensions, True)\n fc.test_eq(nc.dimensions['sample'].isunlimited(), True)\n\n\n# Test that groups are created\nwith Dataset(dest, 'r', format='NETCDF4') as nc:\n fc.test_eq(nc.groups.keys(), ['seawater', 'biota'])\n\n\n# Test that groups are created\nwith Dataset(dest, 'r', format='NETCDF4') as nc:\n fc.test_eq(nc.groups.keys(), ['seawater', 'biota'])\n\n\n# Test that correct variables are created in groups\nwith Dataset(dest, 'r', format='NETCDF4') as nc:\n fc.test_eq(nc['biota'].variables.keys(), \n ['sample', 'lon', 'lat', 'time', 'species', 'i131', 'i131_dl', 'i131_unit'])\n \n fc.test_eq(nc['seawater'].variables.keys(), \n ['sample', 'lon', 'lat', 'time', 'i131', 'i131_dl', 'i131_unit'])\n\n\n# Test that correct variables are created in groups\nwith Dataset(dest, 'r', format='NETCDF4') as nc:\n print(nc.dimensions.items())\n print(nc['biota'].dimensions.items())\n print(nc['seawater'].dimensions.items())\n\ndict_items([('sample', <class 'netCDF4._netCDF4.Dimension'> (unlimited): name = 'sample', size = 0)])\ndict_items([('biota', <class 'netCDF4._netCDF4.Dimension'>: name = 'biota', size = 2)])\ndict_items([('seawater', <class 'netCDF4._netCDF4.Dimension'>: name = 'seawater', size = 3)])", + "crumbs": [ + "API", + "Serializers" + ] + }, + { + "objectID": "api/serializers.html#openrefine-csv-encoder", + "href": "api/serializers.html#openrefine-csv-encoder", + "title": "Serializers", + "section": "OpenRefine CSV encoder", + "text": "OpenRefine CSV encoder\n\nsource\n\nOpenRefineCsvEncoder\n\n OpenRefineCsvEncoder (dfs:dict[pandas.core.frame.DataFrame],\n dest_fname:str, ref_id=-1, verbose:bool=False)\n\nOpenRefine CSV from NetCDF.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ndfs\ndict\n\ndict of Dataframes to encode with group name as key {‘sediment’: df_sed, …}\n\n\ndest_fname\nstr\n\nName of output file to produce\n\n\nref_id\nint\n-1\nref_id to include\n\n\nverbose\nbool\nFalse\nPrint\n\n\n\n\n\nExported source\nclass OpenRefineCsvEncoder:\n \"OpenRefine CSV from NetCDF.\"\n def __init__(self, \n dfs:dict[pd.DataFrame], # dict of Dataframes to encode with group name as key {'sediment': df_sed, ...}\n dest_fname:str, # Name of output file to produce\n ref_id = -1, # ref_id to include \n verbose:bool=False, # Print \n ):\n store_attr()\n\n\n\nsource\n\n\nOpenRefineCsvEncoder.process_groups_to_csv\n\n OpenRefineCsvEncoder.process_groups_to_csv ()\n\n\n\nExported source\n@patch\ndef process_groups_to_csv(self:OpenRefineCsvEncoder):\n for grp_name, df in self.dfs.items():\n # include ref_id\n if self.ref_id != -1:\n df['ref_id'] = self.ref_id\n self.process_group_to_csv(grp_name, df)\n\n\n\nsource\n\n\nOpenRefineCsvEncoder.process_group_to_csv\n\n OpenRefineCsvEncoder.process_group_to_csv (group_name, df)\n\n\n\nExported source\n@patch\ndef process_group_to_csv(self:OpenRefineCsvEncoder, group_name, df):\n filename, file_extension=os.path.splitext(self.dest_fname)\n path = filename + '_' + group_name + file_extension\n df.to_csv( path_or_buf= path, sep=',', index=False)\n\n\n\nsource\n\n\nOpenRefineCsvEncoder.encode\n\n OpenRefineCsvEncoder.encode ()\n\nEncode OpenRefine CSV based on dataframes from NetCDF.\n\n\nExported source\n@patch\ndef encode(self:OpenRefineCsvEncoder):\n \"Encode OpenRefine CSV based on dataframes from NetCDF.\"\n # Include ref_id\n \n # Process to csv\n self.process_groups_to_csv()\n\n\n\ndest = '../files/csv/encoding-test.csv'\n\nencoder = OpenRefineCsvEncoder(dfs, dest_fname=dest)\nencoder.encode()", + "crumbs": [ + "API", + "Serializers" + ] + }, + { + "objectID": "api/metadata.html", + "href": "api/metadata.html", + "title": "Metadata", + "section": "", + "text": "source", + "crumbs": [ + "API", + "Metadata" + ] + }, + { + "objectID": "api/metadata.html#how-to-use", + "href": "api/metadata.html#how-to-use", + "title": "Metadata", + "section": "How to use", + "text": "How to use\n\ndfs = pd.read_pickle('../files/pkl/dfs_test.pkl')\n\n\nkw = ['oceanography', 'Earth Science > Oceans > Ocean Chemistry> Radionuclides',\n 'Earth Science > Human Dimensions > Environmental Impacts > Nuclear Radiation Exposure',\n 'Earth Science > Oceans > Ocean Chemistry > Ocean Tracers, Earth Science > Oceans > Marine Sediments',\n 'Earth Science > Oceans > Ocean Chemistry, Earth Science > Oceans > Sea Ice > Isotopes',\n 'Earth Science > Oceans > Water Quality > Ocean Contaminants',\n 'Earth Science > Biological Classification > Animals/Vertebrates > Fish',\n 'Earth Science > Biosphere > Ecosystems > Marine Ecosystems',\n 'Earth Science > Biological Classification > Animals/Invertebrates > Mollusks',\n 'Earth Science > Biological Classification > Animals/Invertebrates > Arthropods > Crustaceans',\n 'Earth Science > Biological Classification > Plants > Macroalgae (Seaweeds)']\n\n\nfeed = GlobAttrsFeeder(dfs, cbs=[\n BboxCB(),\n DepthRangeCB(),\n TimeRangeCB(cfg=CONFIGS),\n ZoteroCB('26VMZZ2Q', cfg=CONFIGS),\n KeyValuePairCB('keywords', ', '.join(kw))\n ])\n\nattrs = feed(); attrs\n\n{'geospatial_lat_min': '29.05',\n 'geospatial_lat_max': '65.35',\n 'geospatial_lon_min': '9.6333',\n 'geospatial_lon_max': '54.0',\n 'geospatial_bounds': 'POLYGON ((9.6333 54, 29.05 54, 29.05 65.35, 9.6333 65.35, 9.6333 54))',\n 'geospatial_vertical_max': '0',\n 'geospatial_vertical_min': '-248.0',\n 'time_coverage_start': '1984-01-10T00:00:00',\n 'time_coverage_end': '1987-06-28T00:00:00',\n 'title': 'Environmental database - Helsinki Commission Monitoring of Radioactive Substances',\n 'summary': 'MORS Environment database has been used to collate data resulting from monitoring of environmental radioactivity in the Baltic Sea based on HELCOM Recommendation 26/3.\\n\\nThe database is structured according to HELCOM Guidelines on Monitoring of Radioactive Substances (https://www.helcom.fi/wp-content/uploads/2019/08/Guidelines-for-Monitoring-of-Radioactive-Substances.pdf), which specifies reporting format, database structure, data types and obligatory parameters used for reporting data under Recommendation 26/3.\\n\\nThe database is updated and quality assured annually by HELCOM MORS EG.',\n 'creator_name': '[{\"creatorType\": \"author\", \"name\": \"HELCOM MORS\"}]',\n 'keywords': 'oceanography, Earth Science > Oceans > Ocean Chemistry> Radionuclides, Earth Science > Human Dimensions > Environmental Impacts > Nuclear Radiation Exposure, Earth Science > Oceans > Ocean Chemistry > Ocean Tracers, Earth Science > Oceans > Marine Sediments, Earth Science > Oceans > Ocean Chemistry, Earth Science > Oceans > Sea Ice > Isotopes, Earth Science > Oceans > Water Quality > Ocean Contaminants, Earth Science > Biological Classification > Animals/Vertebrates > Fish, Earth Science > Biosphere > Ecosystems > Marine Ecosystems, Earth Science > Biological Classification > Animals/Invertebrates > Mollusks, Earth Science > Biological Classification > Animals/Invertebrates > Arthropods > Crustaceans, Earth Science > Biological Classification > Plants > Macroalgae (Seaweeds)'}", + "crumbs": [ + "API", + "Metadata" + ] + }, + { + "objectID": "api/utils.html", + "href": "api/utils.html", + "title": "Utilities", + "section": "", + "text": "import pandas as pd", + "crumbs": [ + "API", + "Utilities" + ] + }, + { + "objectID": "api/utils.html#core", + "href": "api/utils.html#core", + "title": "Utilities", + "section": "Core", + "text": "Core\nAbstracting some common operations.\n\nsource\n\nget_unique_across_dfs\n\n get_unique_across_dfs (dfs:dict, col_name:str='NUCLIDE',\n as_df:bool=False, include_nchars:bool=False)\n\nGet a list of unique column values across dataframes.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ndfs\ndict\n\nDictionary of dataframes\n\n\ncol_name\nstr\nNUCLIDE\nColumn name to extract unique values from\n\n\nas_df\nbool\nFalse\nReturn a DataFrame of unique values\n\n\ninclude_nchars\nbool\nFalse\nAdd a column with the number of characters in the value\n\n\nReturns\nlist\n\nReturns a list of unique column values across dataframes\n\n\n\n\n\nExported source\ndef get_unique_across_dfs(dfs:dict, # Dictionary of dataframes\n col_name:str='NUCLIDE', # Column name to extract unique values from\n as_df:bool=False, # Return a DataFrame of unique values\n include_nchars:bool=False # Add a column with the number of characters in the value\n ) -> list: # Returns a list of unique column values across dataframes\n \"Get a list of unique column values across dataframes.\"\n unique_values = list(set().union(*(df[col_name].unique() for df in dfs.values() if col_name in df.columns)))\n if not as_df:\n return unique_values\n else:\n df_uniques = pd.DataFrame(unique_values, columns=['value']).reset_index()\n if include_nchars: df_uniques['n_chars'] = df_uniques['value'].str.len()\n return df_uniques\n\n\nExample of use:\n\ndfs_test = {'seawater': pd.DataFrame({'NUCLIDE': ['cs137', 'cs134_137_tot', 'cs134_137_tot']}),\n 'biota': pd.DataFrame({'NUCLIDE': ['cs137', 'cs134', 'cs134_137_tot']}),\n 'sediment': pd.DataFrame({'NUCLIDE': ['cs134_137_tot', 'cs134_137_tot', 'cs134_137_tot']})}\n\nfc.test_eq(set(get_unique_across_dfs(dfs_test, col_name='NUCLIDE')), \n set(['cs134', 'cs137', 'cs134_137_tot']))\n\nWhat if the column name is not in one of the dataframe?\n\ndfs_test = {'seawater': pd.DataFrame({'NUCLIDE': ['cs137', 'cs134_137_tot', 'cs134_137_tot']}),\n 'biota': pd.DataFrame({'NUCLIDE': ['cs137', 'cs134', 'cs134_137_tot']}),\n 'sediment': pd.DataFrame({'NONUCLIDE': ['cs134_137_tot', 'cs134_137_tot', 'cs134_137_tot']})}\n\nfc.test_eq(set(get_unique_across_dfs(dfs_test, col_name='NUCLIDE')), \n set(['cs134', 'cs137', 'cs134_137_tot']))\n\n\nget_unique_across_dfs(dfs_test, col_name='NUCLIDE', as_df=True, include_nchars=True)\n\n\n\n\n\n\n\n\nindex\nvalue\nn_chars\n\n\n\n\n0\n0\ncs137\n5\n\n\n1\n1\ncs134_137_tot\n13\n\n\n2\n2\ncs134\n5\n\n\n\n\n\n\n\n\nsource\n\n\nRemapper\n\n Remapper (provider_lut_df:pandas.core.frame.DataFrame,\n maris_lut_fn:<built-infunctioncallable>, maris_col_id:str,\n maris_col_name:str, provider_col_to_match:str,\n provider_col_key, fname_cache)\n\nRemap a data provider lookup table to a MARIS lookup table using fuzzy matching.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nprovider_lut_df\nDataFrame\nData provider lookup table to be remapped\n\n\nmaris_lut_fn\ncallable\nFunction that returns the MARIS lookup table path\n\n\nmaris_col_id\nstr\nMARIS lookup table column name for the id\n\n\nmaris_col_name\nstr\nMARIS lookup table column name for the name\n\n\nprovider_col_to_match\nstr\nData provider lookup table column name for the name to match\n\n\nprovider_col_key\n\nData provider lookup table column name for the key\n\n\nfname_cache\n\nCache file name\n\n\n\n\n\nExported source\nclass Remapper():\n def __init__(self,\n provider_lut_df:pd.DataFrame, # Data provider lookup table to be remapped\n maris_lut_fn:callable, # Function that returns the MARIS lookup table path\n maris_col_id:str, # MARIS lookup table column name for the id\n maris_col_name:str, # MARIS lookup table column name for the name\n provider_col_to_match:str, # Data provider lookup table column name for the name to match\n provider_col_key, # Data provider lookup table column name for the key\n fname_cache # Cache file name\n ):\n \"Remap a data provider lookup table to a MARIS lookup table using fuzzy matching.\"\n fc.store_attr()\n self.cache_file = cache_path() / fname_cache\n self.maris_lut = maris_lut_fn()\n self.lut = {}\n\n def generate_lookup_table(self, \n fixes={}, # Lookup table fixes\n as_df=True, # Whether to return a DataFrame\n overwrite=True):\n \"Generate a lookup table from a data provider lookup table to a MARIS lookup table using fuzzy matching.\"\n self.fixes = fixes\n self.as_df = as_df\n if overwrite or not self.cache_file.exists():\n self._create_lookup_table()\n fc.save_pickle(self.cache_file, self.lut)\n else:\n self.lut = fc.load_pickle(self.cache_file)\n\n return self._format_output()\n\n def _create_lookup_table(self):\n df = self.provider_lut_df\n for _, row in tqdm(df.iterrows(), total=len(df), desc=\"Processing\"): \n # print(row[self.provider_col_to_match])\n self._process_row(row)\n\n def _process_row(self, row):\n value_to_match = row[self.provider_col_to_match]\n if isinstance(value_to_match, str): # Only process if value is a string\n name_to_match = self.fixes.get(value_to_match, value_to_match)\n \n result = match_maris_lut(self.maris_lut, name_to_match, self.maris_col_id, self.maris_col_name).iloc[0]\n match = Match(result[self.maris_col_id], result[self.maris_col_name], \n value_to_match, result['score'])\n self.lut[row[self.provider_col_key]] = match\n else:\n # Handle non-string values (e.g., NaN)\n self.lut[row[self.provider_col_key]] = Match(-1, \"Unknown\", value_to_match, 0)\n \n def select_match(self, match_score_threshold:int=1):\n self.lut = {k: v for k, v in self.lut.items() if v.match_score >= match_score_threshold}\n return self._format_output()\n\n def _format_output(self):\n if not self.as_df: return self.lut\n df_lut = pd.DataFrame.from_dict(self.lut, orient='index', \n columns=['matched_maris_name', 'source_name', 'match_score'])\n df_lut.index.name = 'source_key'\n return df_lut.sort_values(by='match_score', ascending=False)", + "crumbs": [ + "API", + "Utilities" + ] + }, + { + "objectID": "api/utils.html#validation", + "href": "api/utils.html#validation", + "title": "Utilities", + "section": "Validation", + "text": "Validation\n\nsource\n\nhas_valid_varname\n\n has_valid_varname (var_names:list, cdl_path:str, group=None)\n\nCheck that proposed variable names are in MARIS CDL\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nvar_names\nlist\n\nvariable names\n\n\ncdl_path\nstr\n\nPath to MARIS CDL file (point of truth)\n\n\ngroup\nNoneType\nNone\nCheck if the variable names is contained in the group\n\n\n\n\n\nExported source\ndef has_valid_varname(\n var_names:list, # variable names\n cdl_path:str, # Path to MARIS CDL file (point of truth)\n group = None, # Check if the variable names is contained in the group\n):\n \"Check that proposed variable names are in MARIS CDL\"\n has_valid = True\n with Dataset(cdl_path) as nc:\n cdl_vars={}\n all_vars=[]\n # get variable names in CDL \n for grp in nc.groups.values():\n # Create a list of var for each group\n vars = list(grp.variables.keys())\n cdl_vars[grp.name] = vars\n all_vars.extend(vars)\n \n if group != None:\n allowed_vars= cdl_vars[group]\n else: \n # get unique \n allowed_vars = list(set(all_vars))\n \n for name in var_names:\n if name not in allowed_vars:\n has_valid = False\n if group != None:\n print(f'\"{name}\" variable name not found in group \"{group}\" of MARIS CDL')\n else:\n print(f'\"{name}\" variable name not found in MARIS CDL')\n return has_valid\n\n\n\nVARNAMES = ['lat', 'lon']\ntest_eq(has_valid_varname(VARNAMES, './files/nc/maris-cdl.nc'), True)\n\n\nVARNAMES = ['ba140_invalid', 'ba140_dl']\ntest_eq(has_valid_varname(VARNAMES, './files/nc/maris-cdl.nc'), False)\n\n\"ba140_invalid\" variable name not found in MARIS CDL", + "crumbs": [ + "API", + "Utilities" + ] + }, + { + "objectID": "api/utils.html#geoprocessing", + "href": "api/utils.html#geoprocessing", + "title": "Utilities", + "section": "Geoprocessing", + "text": "Geoprocessing\n\nsource\n\nget_bbox\n\n get_bbox (df, coord_cols=('lon', 'lat'))\n\n\n\nExported source\ndef get_bbox(df,\n coord_cols=('lon', 'lat')\n ):\n x, y = coord_cols \n arr = [(row[x], row[y]) for _, row in df.iterrows()]\n return MultiPoint(arr).envelope\n\n\n\ndf = pd.DataFrame({'lon': np.linspace(-10, 5, 20), 'lat': np.linspace(40, 50, 20)})\nbbox = get_bbox(df);\n\n\n# To get `lon_min`, `lon_max`, `lat_min`, `lat_max`\nbbox.bounds\n\n(-10.0, 40.0, 5.0, 50.0)\n\n\n\n# And its Well-Know Text representation\nbbox.wkt\n\n'POLYGON ((-10 40, 5 40, 5 50, -10 50, -10 40))'\n\n\n\n# If unique (lon, lat)\ndf = pd.DataFrame({'lon': [0, 0], 'lat': [1, 1]})\nbbox = get_bbox(df);\n\n\nbbox.bounds\n\n(0.0, 1.0, 0.0, 1.0)", + "crumbs": [ + "API", + "Utilities" + ] + }, + { + "objectID": "api/utils.html#downloaders", + "href": "api/utils.html#downloaders", + "title": "Utilities", + "section": "Downloaders", + "text": "Downloaders\n\nsource\n\ndownload_file\n\n download_file (owner, repo, src_dir, dest_dir, fname)\n\n\n\nExported source\ndef download_files_in_folder(owner:str, \n repo:str, \n src_dir:str, \n dest_dir:str\n ):\n \"Make a GET request to the GitHub API to get the contents of the folder\"\n url = f\"https://api.github.com/repos/{owner}/{repo}/contents/{src_dir}\"\n response = requests.get(url)\n\n if response.status_code == 200:\n contents = response.json()\n\n # Iterate over the files and download them\n for item in contents:\n if item[\"type\"] == \"file\":\n fname = item[\"name\"]\n download_file(owner, repo, src_dir, dest_dir, fname)\n else:\n print(f\"Error: {response.status_code}\")\n\ndef download_file(owner, repo, src_dir, dest_dir, fname):\n # Make a GET request to the GitHub API to get the raw file contents\n url = f\"https://raw.githubusercontent.com/{owner}/{repo}/master/{src_dir}/{fname}\"\n response = requests.get(url)\n\n if response.status_code == 200:\n # Save the file locally\n with open(Path(dest_dir) / fname, \"wb\") as file:\n file.write(response.content)\n print(f\"{fname} downloaded successfully.\")\n else:\n print(f\"Error: {response.status_code}\")\n\n\n\nsource\n\n\ndownload_files_in_folder\n\n download_files_in_folder (owner:str, repo:str, src_dir:str, dest_dir:str)\n\nMake a GET request to the GitHub API to get the contents of the folder", + "crumbs": [ + "API", + "Utilities" + ] + }, + { + "objectID": "api/utils.html#worrms", + "href": "api/utils.html#worrms", + "title": "Utilities", + "section": "WorRMS", + "text": "WorRMS\nThe World Register of Marine Species (WorMS) is an authoritative classification and catalogue of marine names. It provides a REST API (among others) allowing to “fuzzy” match any species name you might encounter in marine data sources names againt their own database. There are several types of matches as described here.\n\nsource\n\nmatch_worms\n\n match_worms (name:str)\n\nLookup name in WoRMS (fuzzy match)\n\n\n\n\nType\nDetails\n\n\n\n\nname\nstr\nName of species to look up in WoRMS\n\n\n\n\n\nExported source\ndef match_worms(\n name:str # Name of species to look up in WoRMS\n ):\n \"Lookup `name` in WoRMS (fuzzy match)\"\n url = 'https://www.marinespecies.org/rest/AphiaRecordsByMatchNames'\n params = {\n 'scientificnames[]': [name],\n 'marine_only': 'true'\n }\n headers = {\n 'accept': 'application/json'\n }\n \n response = requests.get(url, params=params, headers=headers)\n \n # Check if the request was successful (status code 200)\n if response.status_code == 200:\n data = response.json()\n return data\n else:\n return -1\n\n\nFor instance:\n\nmatch_worms('Aristeus antennatus')\n\n[[{'AphiaID': 107083,\n 'url': 'https://www.marinespecies.org/aphia.php?p=taxdetails&id=107083',\n 'scientificname': 'Aristeus antennatus',\n 'authority': '(Risso, 1816)',\n 'status': 'accepted',\n 'unacceptreason': None,\n 'taxonRankID': 220,\n 'rank': 'Species',\n 'valid_AphiaID': 107083,\n 'valid_name': 'Aristeus antennatus',\n 'valid_authority': '(Risso, 1816)',\n 'parentNameUsageID': 106807,\n 'kingdom': 'Animalia',\n 'phylum': 'Arthropoda',\n 'class': 'Malacostraca',\n 'order': 'Decapoda',\n 'family': 'Aristeidae',\n 'genus': 'Aristeus',\n 'citation': 'DecaNet eds. (2024). DecaNet. Aristeus antennatus (Risso, 1816). Accessed through: World Register of Marine Species at: https://www.marinespecies.org/aphia.php?p=taxdetails&id=107083 on 2024-06-10',\n 'lsid': 'urn:lsid:marinespecies.org:taxname:107083',\n 'isMarine': 1,\n 'isBrackish': 0,\n 'isFreshwater': 0,\n 'isTerrestrial': 0,\n 'isExtinct': 0,\n 'match_type': 'exact',\n 'modified': '2022-08-24T09:48:14.813Z'}]]\n\n\n\n# open dbo_species\n#from tqdm import tqdm\n#results = []\n#species = pd.read_excel(species_lut_path()).species\n#for i, name in tqdm(enumerate(species), total=len(species)):\n# if i > 1:\n# worms_match = match_worms(name)\n# if worms_match != -1:\n# results.append(worms_match[0][0])\n\n\n# np.unique(np.array([result['phylum'] for result in results]))\n\n\n#len(maris_worms_matches)\n\n\n#maris_worms_matches = fc.load_pickle('./files/pkl/maris-worms-matches.pkl')\n\n\n#np.unique(np.array([result['phylum'] for result in maris_worms_matches]))\n\n\n#len([result for result in maris_worms_matches if result['status'] == 'accepted'])", + "crumbs": [ + "API", + "Utilities" + ] + }, + { + "objectID": "api/utils.html#fuzzy-matching-for-maris-lookup-tables", + "href": "api/utils.html#fuzzy-matching-for-maris-lookup-tables", + "title": "Utilities", + "section": "Fuzzy matching for MARIS Lookup Tables", + "text": "Fuzzy matching for MARIS Lookup Tables\nUsing https://jamesturk.github.io/jellyfish fuzzy matching distance metrics.\n\nsource\n\nMatch\n\n Match (matched_id:int, matched_maris_name:str, source_name:str,\n match_score:int)\n\n\n\nExported source\n@dataclass\nclass Match:\n matched_id: int\n matched_maris_name: str\n source_name: str\n match_score: int\n\n\n\nsource\n\n\nmatch_maris_lut\n\n match_maris_lut (lut_path:str, data_provider_name:str, maris_id:str,\n maris_name:str, dist_fn:collections.abc.Callable=<built-\n in function levenshtein_distance>, nresults:int=10)\n\nFuzzy matching data provider and MARIS lookup tables (e.g biota species, sediments, …).\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nlut_path\nstr\n\nPath to MARIS species authoritative species look-up table\n\n\ndata_provider_name\nstr\n\nName of data provider nomenclature item to look up\n\n\nmaris_id\nstr\n\nId of MARIS lookup table nomenclature item to match\n\n\nmaris_name\nstr\n\nName of MARIS lookup table nomenclature item to match\n\n\ndist_fn\nCallable\nlevenshtein_distance\nDistance function\n\n\nnresults\nint\n10\nMaximum number of results to return\n\n\nReturns\nDataFrame\n\n\n\n\n\n\n\nExported source\ndef match_maris_lut(\n lut_path: str, # Path to MARIS species authoritative species look-up table\n data_provider_name: str, # Name of data provider nomenclature item to look up \n maris_id: str, # Id of MARIS lookup table nomenclature item to match\n maris_name: str, # Name of MARIS lookup table nomenclature item to match\n dist_fn: Callable = jf.levenshtein_distance, # Distance function\n nresults: int = 10 # Maximum number of results to return\n) -> pd.DataFrame:\n \"Fuzzy matching data provider and MARIS lookup tables (e.g biota species, sediments, ...).\"\n df = pd.read_excel(lut_path)\n df = df.dropna(subset=[maris_name])\n df = df.astype({maris_id: 'int'})\n df['score'] = df[maris_name].str.lower().apply(lambda x: dist_fn(data_provider_name.lower(), x))\n df = df.sort_values(by='score', ascending=True)[:nresults]\n return df[[maris_id, maris_name, 'score']]\n\n\nBelow an example trying to match the name “PLANKTON” with dbo_species_cleaned.xlsx MARIS biota species lookup table:\n\nlut_fname = '../files/lut/dbo_species_cleaned.xlsx'\nmatch_maris_lut(lut_fname, data_provider_name='PLANKTON', \n maris_id='species_id', maris_name='species')\n\n\n\n\n\n\n\n\nspecies_id\nspecies\nscore\n\n\n\n\n281\n280\nPlankton\n0\n\n\n696\n695\nZooplankton\n3\n\n\n633\n632\nPalaemon\n4\n\n\n697\n696\nPhytoplankton\n5\n\n\n812\n811\nChanos\n5\n\n\n160\n159\nNeuston\n5\n\n\n234\n233\nPenaeus\n6\n\n\n1458\n1457\nLamnidae\n6\n\n\n1438\n1437\nLabrus\n6\n\n\n1527\n1526\nFavites\n6\n\n\n\n\n\n\n\nBelow an example trying to match the name “GLACIAL” with dbo_sedtype.xlsx MARIS sediment lookup table:\n\n# sediments_lut_path()\nlut_fname = '../files/lut/dbo_sedtype.xlsx'\nmatch_maris_lut(lut_fname, data_provider_name='GLACIAL', \n maris_id='sedtype_id', maris_name='sedtype')\n\n\n\n\n\n\n\n\nsedtype_id\nsedtype\nscore\n\n\n\n\n26\n25\nGlacial\n0\n\n\n3\n2\nGravel\n4\n\n\n2\n1\nClay\n5\n\n\n51\n50\nGlacial clay\n5\n\n\n4\n3\nMarsh\n6\n\n\n7\n6\nSand\n6\n\n\n13\n12\nSilt\n6\n\n\n15\n14\nSludge\n6\n\n\n27\n26\nSoft\n7\n\n\n52\n51\nSoft clay\n7\n\n\n\n\n\n\n\n\nlut_fname = '../files/lut/dbo_nuclide.xlsx'\nmatch_maris_lut(lut_fname, data_provider_name='CS-137', \n maris_id='nuclide_id', maris_name='nc_name')\n\n\n\n\n\n\n\n\nnuclide_id\nnc_name\nscore\n\n\n\n\n31\n33\ncs137\n1\n\n\n30\n31\ncs134\n2\n\n\n99\n102\ncs136\n2\n\n\n29\n30\ncs127\n2\n\n\n111\n114\nce139\n3\n\n\n109\n112\nsb127\n3\n\n\n8\n7\nco57\n4\n\n\n28\n29\ni131\n4\n\n\n71\n74\ncm243\n4\n\n\n90\n93\nsn117m\n4", + "crumbs": [ + "API", + "Utilities" + ] + }, + { + "objectID": "api/utils.html#geoprocessing-1", + "href": "api/utils.html#geoprocessing-1", + "title": "Utilities", + "section": "Geoprocessing", + "text": "Geoprocessing\n\nsource\n\nget_bbox\n\n get_bbox (df, coord_cols=('lon', 'lat'))\n\n\ndf = pd.DataFrame({'lon': np.linspace(-10, 5, 20), 'lat': np.linspace(40, 50, 20)})\nbbox = get_bbox(df);\n\n\n# To get `lon_min`, `lon_max`, `lat_min`, `lat_max`\nbbox.bounds\n\n(-10.0, 40.0, 5.0, 50.0)\n\n\n\n# And its Well-Know Text representation\nbbox.wkt\n\n'POLYGON ((-10 40, 5 40, 5 50, -10 50, -10 40))'\n\n\n\n# If unique (lon, lat)\ndf = pd.DataFrame({'lon': [0, 0], 'lat': [1, 1]})\nbbox = get_bbox(df);\n\n\nbbox.bounds\n\n(0.0, 1.0, 0.0, 1.0)", + "crumbs": [ + "API", + "Utilities" + ] + }, + { + "objectID": "api/utils.html#downloaders-1", + "href": "api/utils.html#downloaders-1", + "title": "Utilities", + "section": "Downloaders", + "text": "Downloaders\n\nsource\n\ndownload_file\n\n download_file (owner, repo, src_dir, dest_dir, fname)\n\n\nsource\n\n\ndownload_files_in_folder\n\n download_files_in_folder (owner:str, repo:str, src_dir:str, dest_dir:str)\n\nMake a GET request to the GitHub API to get the contents of the folder", + "crumbs": [ + "API", + "Utilities" + ] + }, + { + "objectID": "api/utils.html#worrms-1", + "href": "api/utils.html#worrms-1", + "title": "Utilities", + "section": "WorRMS", + "text": "WorRMS\nThe World Register of Marine Species (WorMS) is an authoritative classification and catalogue of marine names. It provides a REST API (among others) allowing to “fuzzy” match any species name you might encounter in marine data sources names againt their own database. There are several types of matches as described here.\n\nsource\n\nmatch_worms\n\n match_worms (name:str)\n\nLookup name in WoRMS (fuzzy match)\n\n\n\n\nType\nDetails\n\n\n\n\nname\nstr\nName of species to look up in WoRMS\n\n\n\nFor instance:\n\nmatch_worms('Aristeus antennatus')\n\n[[{'AphiaID': 107083,\n 'url': 'https://www.marinespecies.org/aphia.php?p=taxdetails&id=107083',\n 'scientificname': 'Aristeus antennatus',\n 'authority': '(Risso, 1816)',\n 'status': 'accepted',\n 'unacceptreason': None,\n 'taxonRankID': 220,\n 'rank': 'Species',\n 'valid_AphiaID': 107083,\n 'valid_name': 'Aristeus antennatus',\n 'valid_authority': '(Risso, 1816)',\n 'parentNameUsageID': 106807,\n 'kingdom': 'Animalia',\n 'phylum': 'Arthropoda',\n 'class': 'Malacostraca',\n 'order': 'Decapoda',\n 'family': 'Aristeidae',\n 'genus': 'Aristeus',\n 'citation': 'DecaNet eds. (2024). DecaNet. Aristeus antennatus (Risso, 1816). Accessed through: World Register of Marine Species at: https://www.marinespecies.org/aphia.php?p=taxdetails&id=107083 on 2024-06-10',\n 'lsid': 'urn:lsid:marinespecies.org:taxname:107083',\n 'isMarine': 1,\n 'isBrackish': 0,\n 'isFreshwater': 0,\n 'isTerrestrial': 0,\n 'isExtinct': 0,\n 'match_type': 'exact',\n 'modified': '2022-08-24T09:48:14.813Z'}]]\n\n\n\n# open dbo_species\n#from tqdm import tqdm\n#results = []\n#species = pd.read_excel(species_lut_path()).species\n#for i, name in tqdm(enumerate(species), total=len(species)):\n# if i > 1:\n# worms_match = match_worms(name)\n# if worms_match != -1:\n# results.append(worms_match[0][0])\n\n\n# np.unique(np.array([result['phylum'] for result in results]))\n\narray(['Annelida', 'Arthropoda', 'Bryozoa', 'Chaetognatha', 'Charophyta',\n 'Chlorophyta', 'Chordata', 'Cnidaria', 'Ctenophora',\n 'Echinodermata', 'Mollusca', 'Myzozoa', 'Ochrophyta', 'Porifera',\n 'Rhodophyta', 'Tracheophyta'], dtype='<U13')\n\n\n\n#len(maris_worms_matches)\n\n\n#maris_worms_matches = fc.load_pickle('./files/pkl/maris-worms-matches.pkl')\n\n\n#np.unique(np.array([result['phylum'] for result in maris_worms_matches]))\n\n\n#len([result for result in maris_worms_matches if result['status'] == 'accepted'])\n\n\n#match_maris_sediment('GLACIAL')", + "crumbs": [ + "API", + "Utilities" + ] + }, + { + "objectID": "api/utils.html#test", + "href": "api/utils.html#test", + "title": "Utilities", + "section": "Test", + "text": "Test\n\nsource\n\ntest_dfs\n\n test_dfs (dfs1:dict, dfs2:dict)\n\nCompare two dictionaries of DataFrames for equality (also ensuring that columns are in the same order).\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\ndfs1\ndict\nFirst dictionary of DataFrames to compare\n\n\ndfs2\ndict\nSecond dictionary of DataFrames to compare\n\n\nReturns\nNone\nIt raises an AssertionError if the DataFrames are not equal\n\n\n\n\n\nExported source\ndef test_dfs(\n dfs1:dict, # First dictionary of DataFrames to compare \n dfs2:dict # Second dictionary of DataFrames to compare\n ) -> None: # It raises an `AssertionError` if the DataFrames are not equal\n \"Compare two dictionaries of DataFrames for equality (also ensuring that columns are in the same order).\"\n for grp in dfs1.keys():\n df1, df2 = (df.sort_index() for df in (dfs1[grp], dfs2[grp]))\n fc.test_eq(df1, df2.reindex(columns=df1.columns))", + "crumbs": [ + "API", + "Utilities" + ] + }, + { + "objectID": "handlers/helcom.html", + "href": "handlers/helcom.html", + "title": "HELCOM", + "section": "", + "text": "This data pipeline, known as a “handler” in Marisco terminology, is designed to clean, standardize, and encode HELCOM data into NetCDF format. The handler processes raw HELCOM data, applying various transformations and lookups to align it with MARIS data standards.\nKey functions of this handler:\nThis handler is a crucial component in the Marisco data processing workflow, ensuring HELCOM data is properly integrated into the MARIS database.\nNote: Additionally, an optional encoder (pipeline) is provided below to process data into a .csv format compatible with the MARIS master database. This feature is maintained for legacy purposes, as data ingestion was previously performed using OpenRefine.\nThe present notebook pretends to be an instance of Literate Programming in the sense that it is a narrative that includes code snippets that are interspersed with explanations. When a function or a class needs to be exported in a dedicated python module (in our case marisco/handlers/helcom.py) the code snippet is added to the module using #| exports as provided by the wonderful nbdev library.", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#configuration-file-paths", + "href": "handlers/helcom.html#configuration-file-paths", + "title": "HELCOM", + "section": "Configuration & file paths", + "text": "Configuration & file paths\n\nfname_in: path to the folder containing the HELCOM data in CSV format. The path can be defined as a relative path.\nfname_out_nc: path and filename for the NetCDF output.The path can be defined as a relative path.\nfname_out_csv: path and filename for the Open Refine csv output.The path can be defined as a relative path.\nZotero key: used to retrieve attributes related to the dataset from Zotero. The MARIS datasets include a library available on Zotero.\nref_id: refers to the location in Archive of the Zotero library.\n\n\n\nExported source\nfname_in = '../../_data/accdb/mors/csv'\nfname_out_nc = '../../_data/output/100-HELCOM-MORS-2024.nc'\nfname_out_csv = '../../_data/output/100-HELCOM-MORS-2024.csv'\nzotero_key ='26VMZZ2Q' # HELCOM MORS zotero key\nref_id = 100 # HELCOM MORS reference id as defined by MARIS", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#load-data", + "href": "handlers/helcom.html#load-data", + "title": "HELCOM", + "section": "Load data", + "text": "Load data\nHelcom MORS (Monitoring of Radioactive Substances in the Baltic Sea) data is provided as a Microsoft Access database. Mdbtools can be used to convert the tables of the Microsoft Access database to .csv files on Unix-like OS.\nExample steps:\n\nDownload data\nInstall mdbtools via VScode Terminal:\nsudo apt-get -y install mdbtools\nInstall unzip via VScode Terminal:\nsudo apt-get -y install unzip\nIn VS Code terminal (for instance), navigate to the marisco data folder:\ncd /home/marisco/downloads/marisco/_data/accdb/mors_19840101_20211231\nUnzip MORS_ENVIRONMENT.zip:\nunzip MORS_ENVIRONMENT.zip \nRun preprocess.sh to generate the required data files:\n./preprocess.sh MORS_ENVIRONMENT.zip\nContent of preprocess.sh script:\n#!/bin/bash\n\n# Example of use: ./preprocess.sh MORS_ENVIRONMENT.zip\nunzip $1\ndbname=$(ls *.accdb)\nmkdir csv\nfor table in $(mdb-tables -1 \"$dbname\"); do\n echo \"Export table $table\"\n mdb-export \"$dbname\" \"$table\" > \"csv/$table.csv\"\ndone\nOnce converted to .csv files, the data is ready to be loaded into a dictionary of dataframes.\n\n\nsource\n\nload_data\n\n load_data (src_dir:str|pathlib.Path, smp_types:list=[('SEA', 'seawater'),\n ('SED', 'sediment'), ('BIO', 'biota')])\n\nLoad HELCOM data and return the data in a dictionary of dataframes with the dictionary key as the sample type.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nsrc_dir\nstr | pathlib.Path\n\nThe directory where the source CSV files are located\n\n\nsmp_types\nlist\n[(‘SEA’, ‘seawater’), (‘SED’, ‘sediment’), (‘BIO’, ‘biota’)]\nA list of tuples, each containing the file prefix and the corresponding sample type name\n\n\nReturns\nDict\n\nA dictionary with sample types as keys and their corresponding dataframes as values\n\n\n\n\n\nExported source\ndefault_smp_types = [('SEA', 'seawater'), ('SED', 'sediment'), ('BIO', 'biota')]\n\n\n\n\nExported source\ndef load_data(src_dir:str|Path, # The directory where the source CSV files are located\n smp_types:list=default_smp_types # A list of tuples, each containing the file prefix and the corresponding sample type name\n ) -> Dict[str, pd.DataFrame]: # A dictionary with sample types as keys and their corresponding dataframes as values\n \"Load HELCOM data and return the data in a dictionary of dataframes with the dictionary key as the sample type.\"\n src_path = Path(src_dir)\n \n def load_and_merge(file_prefix: str) -> pd.DataFrame:\n try:\n df_meas = pd.read_csv(src_path / f'{file_prefix}02.csv')\n df_smp = pd.read_csv(src_path / f'{file_prefix}01.csv')\n return pd.merge(df_meas, df_smp, on='KEY', how='left')\n except FileNotFoundError as e:\n print(f\"Error loading files for {file_prefix}: {e}\")\n return pd.DataFrame() # Return an empty DataFrame if files are not found\n \n return {smp_type: load_and_merge(file_prefix) for file_prefix, smp_type in smp_types}\n\n\ndfs is a dictionary of dataframes created from the Helcom dataset located at the path fname_in. The data to be included in each dataframe is sorted by sample type. Each dictionary is defined with a key equal to the sample type.\n\ndfs = load_data(fname_in)\n\n#|eval: false\ndfs = load_data(fname_in)\nprint('keys/sample types: ', dfs.keys())\n\nfor key in dfs.keys():\n print(f'{key} columns: ', dfs[key].columns)\n\nkeys/sample types: dict_keys(['seawater', 'sediment', 'biota'])\nseawater columns: Index(['KEY', 'NUCLIDE', 'METHOD', '< VALUE_Bq/m³', 'VALUE_Bq/m³', 'ERROR%_m³',\n 'DATE_OF_ENTRY_x', 'COUNTRY', 'LABORATORY', 'SEQUENCE', 'DATE', 'YEAR',\n 'MONTH', 'DAY', 'STATION', 'LATITUDE (ddmmmm)', 'LATITUDE (dddddd)',\n 'LONGITUDE (ddmmmm)', 'LONGITUDE (dddddd)', 'TDEPTH', 'SDEPTH', 'SALIN',\n 'TTEMP', 'FILT', 'MORS_SUBBASIN', 'HELCOM_SUBBASIN', 'DATE_OF_ENTRY_y'],\n dtype='object')\nsediment columns: Index(['KEY', 'NUCLIDE', 'METHOD', '< VALUE_Bq/kg', 'VALUE_Bq/kg', 'ERROR%_kg',\n '< VALUE_Bq/m²', 'VALUE_Bq/m²', 'ERROR%_m²', 'DATE_OF_ENTRY_x',\n 'COUNTRY', 'LABORATORY', 'SEQUENCE', 'DATE', 'YEAR', 'MONTH', 'DAY',\n 'STATION', 'LATITUDE (ddmmmm)', 'LATITUDE (dddddd)',\n 'LONGITUDE (ddmmmm)', 'LONGITUDE (dddddd)', 'DEVICE', 'TDEPTH',\n 'UPPSLI', 'LOWSLI', 'AREA', 'SEDI', 'OXIC', 'DW%', 'LOI%',\n 'MORS_SUBBASIN', 'HELCOM_SUBBASIN', 'SUM_LINK', 'DATE_OF_ENTRY_y'],\n dtype='object')\nbiota columns: Index(['KEY', 'NUCLIDE', 'METHOD', '< VALUE_Bq/kg', 'VALUE_Bq/kg', 'BASIS',\n 'ERROR%', 'NUMBER', 'DATE_OF_ENTRY_x', 'COUNTRY', 'LABORATORY',\n 'SEQUENCE', 'DATE', 'YEAR', 'MONTH', 'DAY', 'STATION',\n 'LATITUDE ddmmmm', 'LATITUDE dddddd', 'LONGITUDE ddmmmm',\n 'LONGITUDE dddddd', 'SDEPTH', 'RUBIN', 'BIOTATYPE', 'TISSUE', 'NO',\n 'LENGTH', 'WEIGHT', 'DW%', 'LOI%', 'MORS_SUBBASIN', 'HELCOM_SUBBASIN',\n 'DATE_OF_ENTRY_y'],\n dtype='object')", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#add-sample-type-column", + "href": "handlers/helcom.html#add-sample-type-column", + "title": "HELCOM", + "section": "Add sample type column", + "text": "Add sample type column\nThe sample type (seawater, biota, sediment, …) as defined in the configs.ipynb are encoded group names in netCDF produced. Addition of sample type ids into individual dataframes is done using the AddSampleTypeIdColumnCB callback for legacy purposes (i.e. Open Refine output).\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[AddSampleTypeIdColumnCB(),\n CompareDfsAndTfmCB(dfs)\n ])\n\nprint(tfm()['seawater'][['KEY', 'samptype_id']].head())\nprint(pd.DataFrame.from_dict(tfm.compare_stats) , '\\n')\n\n KEY samptype_id\n0 WKRIL2012003 1\n1 WKRIL2012004 1\n2 WKRIL2012005 1\n3 WKRIL2012006 1\n4 WKRIL2012007 1\n seawater sediment biota\nNumber of rows in dfs 21216 39817 15827\nNumber of rows in tfm.dfs 21216 39817 15827\nNumber of dropped rows 0 0 0\nNumber of rows in tfm.dfs + Number of dropped rows 21216 39817 15827", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#normalize-nuclide-names", + "href": "handlers/helcom.html#normalize-nuclide-names", + "title": "HELCOM", + "section": "Normalize nuclide names", + "text": "Normalize nuclide names\n\nLower & strip nuclide names\n\n\n\n\n\n\nTip\n\n\n\nFEEDBACK TO DATA PROVIDER: Some nuclide names contain one or multiple trailing spaces.\n\n\nThis is demonstrated below for the NUCLIDE column:\n\ndf = get_unique_across_dfs(load_data(fname_in), 'NUCLIDE', as_df=True, include_nchars=True)\ndf['stripped_chars'] = df['value'].str.strip().str.replace(' ', '').str.len()\nprint(df[df['n_chars'] != df['stripped_chars']])\n\n index value n_chars stripped_chars\n1 1 PU238 8 5\n15 15 SR90 6 4\n21 21 CS137 9 5\n42 42 SR90 8 4\n56 56 CO60 8 4\n57 57 SR90 5 4\n58 58 CS134 8 5\n60 60 CS137 8 5\n68 68 K40 8 3\n71 71 CS137 6 5\n73 73 AM241 8 5\n92 92 SR90 7 4\n93 93 TC99 7 4\n\n\nTo fix this issue, we use the LowerStripNameCB callback. For each dataframe in the dictionary of dataframes, it corrects the nuclide name by converting it lowercase, striping any leading or trailing whitespace(s) and ensuring the number comes before letters (e.g. 137cs).\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[LowerStripNameCB(col_src='NUCLIDE')])\n\nfor key in tfm().keys():\n print(f'{key} nuclides: ')\n print(tfm()[key]['NUCLIDE'].unique())\n\nseawater nuclides: \n['cs137' 'sr90' 'h3' 'cs134' 'pu238' 'pu239240' 'am241' 'cm242' 'cm244'\n 'tc99' 'k40' 'ru103' 'sr89' 'sb125' 'nb95' 'ru106' 'zr95' 'ag110m'\n 'cm243244' 'ba140' 'ce144' 'u234' 'u238' 'co60' 'pu239' 'pb210' 'po210'\n 'np237' 'pu240' 'mn54']\nsediment nuclides: \n['ra226' 'cs137' 'ra228' 'k40' 'sr90' 'cs134137' 'cs134' 'pu239240'\n 'pu238' 'co60' 'ru103' 'ru106' 'sb125' 'ag110m' 'ce144' 'am241' 'be7'\n 'th228' 'pb210' 'co58' 'mn54' 'zr95' 'ba140' 'po210' 'ra224' 'nb95'\n 'pu238240' 'pu241' 'pu239' 'eu155' 'ir192' 'th232' 'cd109' 'sb124' 'zn65'\n 'th234' 'tl208' 'pb212' 'pb214' 'bi214' 'ac228' 'ra223' 'u235' 'bi212']\nbiota nuclides: \n['cs134' 'k40' 'co60' 'cs137' 'sr90' 'ag108m' 'mn54' 'co58' 'ag110m'\n 'zn65' 'sb125' 'pu239240' 'ru106' 'be7' 'ce144' 'pb210' 'po210' 'sb124'\n 'sr89' 'zr95' 'te129m' 'ru103' 'nb95' 'ce141' 'la140' 'i131' 'ba140'\n 'pu238' 'u235' 'bi214' 'pb214' 'pb212' 'tl208' 'ac228' 'ra223' 'eu155'\n 'ra226' 'gd153' 'sn113' 'fe59' 'tc99' 'co57' 'sn117m' 'eu152' 'sc46'\n 'rb86' 'ra224' 'th232' 'cs134137' 'am241' 'ra228' 'th228' 'k-40' 'cs138'\n 'cs139' 'cs140' 'cs141' 'cs142' 'cs143' 'cs144' 'cs145' 'cs146']\n\n\n\n\nRemap nuclide names to MARIS data formats\nWe below map nuclide names used by HELCOM to the MARIS standard nuclide names.\nRemapping data provider nomenclatures into MARIS standards is one recurrent operation and is done in a semi-automated manner according to the following pattern:\n\nInspect data provider nomenclature:\nMatch automatically against MARIS nomenclature (using a fuzzy matching algorithm);\nFix potential mismatches;\nApply the lookup table to the dataframe.\n\nAs now on, we will use this pattern to remap the HELCOM data provider nomenclatures into MARIS standards and name it for the sake of brevity IMFA (Inspect, Match, Fix, Apply).\nThe unique values of the data provider nuclide names. The get_unique_across_dfs is a utility function allowing to retrieve unique values of a specific column across all dataframes (please remind that we have one dataframe per sample type - biota, …).\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[LowerStripNameCB(col_src='NUCLIDE')])\ndfs_output = tfm()\n\nget_unique_across_dfs(dfs_output, col_name='NUCLIDE', as_df=True).head(5)\n\n\n\n\n\n\n\n\nindex\nvalue\n\n\n\n\n0\n0\nth228\n\n\n1\n1\nsc46\n\n\n2\n2\ncs142\n\n\n3\n3\ncs137\n\n\n4\n4\nzn65\n\n\n\n\n\n\n\nLet’s now create an instance of a fuzzy matching algorithm Remapper:\n\nremapper = Remapper(provider_lut_df=get_unique_across_dfs(dfs_output, col_name='NUCLIDE', as_df=True),\n maris_lut_fn=nuc_lut_path,\n maris_col_id='nuclide_id',\n maris_col_name='nc_name',\n provider_col_to_match='value',\n provider_col_key='value',\n fname_cache='nuclides_helcom.pkl')\n\nAnd try to match HELCOM to MARIS nuclide names as automatically as possible. The match_score column allows to assess the results:\n\nremapper.generate_lookup_table(as_df=True)\nremapper.select_match(match_score_threshold=1)\n\nProcessing: 100%|██████████| 77/77 [00:01<00:00, 46.82it/s]\n\n\n\n\n\n\n\n\n\nmatched_maris_name\nsource_name\nmatch_score\n\n\nsource_key\n\n\n\n\n\n\n\ncm243244\ncm244\ncm243244\n3\n\n\ncs134137\ncs137\ncs134137\n3\n\n\npu238240\npu240\npu238240\n3\n\n\npu239240\npu240\npu239240\n3\n\n\ncs142\nce144\ncs142\n2\n\n\ncs143\ncs127\ncs143\n2\n\n\ncs145\ncs136\ncs145\n2\n\n\ncs144\nce144\ncs144\n1\n\n\ncs146\ncs136\ncs146\n1\n\n\nk-40\nk40\nk-40\n1\n\n\ncs141\nce141\ncs141\n1\n\n\ncs139\nce139\ncs139\n1\n\n\ncs138\ncs137\ncs138\n1\n\n\ncs140\nce140\ncs140\n1\n\n\n\n\n\n\n\nWe then manually inspect the remaining unmatched names and create a fixes table to map them to the correct MARIS standards:\n\n\nExported source\nfixes_nuclide_names = {\n 'cs134137': 'cs134_137_tot',\n 'cm243244': 'cm243_244_tot',\n 'pu239240': 'pu239_240_tot',\n 'pu238240': 'pu238_240_tot',\n 'cs143': 'cs137',\n 'cs145': 'cs137',\n 'cs142': 'cs137',\n 'cs141': 'cs137',\n 'cs144': 'cs137',\n 'k-40': 'k40',\n 'cs140': 'cs137',\n 'cs146': 'cs137',\n 'cs139': 'cs137',\n 'cs138': 'cs137'\n }\n\n\nLet’s try to match again but this time we use the fixes_nuclide_names to map the nuclide names to the MARIS standards:\n\nremapper.generate_lookup_table(as_df=True, fixes=fixes_nuclide_names)\nfc.test_eq(len(remapper.select_match(match_score_threshold=1)), 0)\n\nProcessing: 100%|██████████| 77/77 [00:01<00:00, 51.25it/s]\n\n\nTest passes! We can now create a callback RemapNuclideNameCB to remap the nuclide names. Note that we pass overwrite=False to the Remapper constructor to now use the cached version.\n\nsource\n\n\nRemapNuclideNameCB\n\n RemapNuclideNameCB (fn_lut:Callable)\n\nBase class for callbacks.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nfn_lut\nCallable\nFunction that returns the lookup table dictionary\n\n\n\n\n\nExported source\n# Create a lookup table for nuclide names\nlut_nuclides = lambda df: Remapper(provider_lut_df=df,\n maris_lut_fn=nuc_lut_path,\n maris_col_id='nuclide_id',\n maris_col_name='nc_name',\n provider_col_to_match='value',\n provider_col_key='value',\n fname_cache='nuclides_helcom.pkl').generate_lookup_table(fixes=fixes_nuclide_names, \n as_df=False, overwrite=False)\n\n\n\n\nExported source\nclass RemapNuclideNameCB(Callback):\n def __init__(self, \n fn_lut:Callable # Function that returns the lookup table dictionary\n ):\n \"Remap data provider nuclide names to MARIS nuclide names.\"\n fc.store_attr()\n\n def __call__(self, tfm):\n df_uniques = get_unique_across_dfs(tfm.dfs, col_name='NUCLIDE', as_df=True)\n lut = {k: v.matched_maris_name for k, v in self.fn_lut(df_uniques).items()} \n for k in tfm.dfs.keys():\n tfm.dfs[k]['NUCLIDE'] = tfm.dfs[k]['NUCLIDE'].replace(lut)\n\n\nLet’s see it in action, along with the RemapRdnNameCB callback:\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[LowerStripNameCB(col_src='NUCLIDE'),\n RemapNuclideNameCB(lut_nuclides)\n ])\ndfs_out = tfm()\n\n# For instance\ndfs_out['biota'].NUCLIDE.unique()\n\narray(['cs134', 'k40', 'co60', 'cs137', 'sr90', 'ag108m', 'mn54', 'co58',\n 'ag110m', 'zn65', 'sb125', 'pu239_240_tot', 'ru106', 'be7',\n 'ce144', 'pb210', 'po210', 'sb124', 'sr89', 'zr95', 'te129m',\n 'ru103', 'nb95', 'ce141', 'la140', 'i131', 'ba140', 'pu238',\n 'u235', 'bi214', 'pb214', 'pb212', 'tl208', 'ac228', 'ra223',\n 'eu155', 'ra226', 'gd153', 'sn113', 'fe59', 'tc99', 'co57',\n 'sn117m', 'eu152', 'sc46', 'rb86', 'ra224', 'th232',\n 'cs134_137_tot', 'am241', 'ra228', 'th228'], dtype=object)\n\n\n\n\nAdd Nuclide Id column\nThe nuclide_id column is added to the dataframe for legacy reasons (again Open Refine output).\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[LowerStripNameCB(col_src='NUCLIDE'),\n RemapNuclideNameCB(lut_nuclides),\n AddNuclideIdColumnCB(col_value='NUCLIDE')\n ])\ndfs_out = tfm()\n\n# For instance\ndfs_out['biota'][['NUCLIDE', 'nuclide_id']]\n\n\n\n\n\n\n\n\nNUCLIDE\nnuclide_id\n\n\n\n\n0\ncs134\n31\n\n\n1\nk40\n4\n\n\n2\nco60\n9\n\n\n3\ncs137\n33\n\n\n4\ncs134\n31\n\n\n...\n...\n...\n\n\n15822\nk40\n4\n\n\n15823\ncs137\n33\n\n\n15824\nbe7\n2\n\n\n15825\nk40\n4\n\n\n15826\ncs137\n33\n\n\n\n\n15827 rows × 2 columns", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#standardize-time", + "href": "handlers/helcom.html#standardize-time", + "title": "HELCOM", + "section": "Standardize Time", + "text": "Standardize Time\n\nParse time\nCreate a callback that remaps the time format in the dictionary of dataframes (i.e. %m/%d/%y %H:%M:%S):\nComment (FA): TO BE REFACTORED\n\nsource\n\n\nParseTimeCB\n\n ParseTimeCB ()\n\nParse the time column in the dataframe.\n\n\nExported source\nclass ParseTimeCB(Callback):\n \"Parse the time column in the dataframe.\"\n def __init__(self): fc.store_attr()\n \n def __call__(self, \n tfm # The transformer object containing DataFrames\n ):\n for grp in tfm.dfs.keys():\n df = tfm.dfs[grp]\n self._process_dates(df)\n self._define_beg_period(df)\n\n def _process_dates(self, \n df:pd.DataFrame # DataFrame containing the `DATE`, `YEAR`, `MONTH`, and `DAY` columns\n ):\n \"Process and correct date and time information in the DataFrame.\"\n df['time'] = pd.to_datetime(df['DATE'], format='%m/%d/%y %H:%M:%S')\n # if 'DATE' column is nan, get 'time' from 'YEAR','MONTH' and 'DAY' column. \n # if 'DAY' or 'MONTH' is 0 then set it to 1. \n df.loc[df[\"DAY\"] == 0, \"DAY\"] = 1\n df.loc[df[\"MONTH\"] == 0, \"MONTH\"] = 1\n \n # if 'DAY' and 'MONTH' is nan but YEAR is not nan then set 'DAY' and 'MONTH' both to 1. \n condition = (df[\"DAY\"].isna()) & (df[\"MONTH\"].isna()) & (df[\"YEAR\"].notna())\n df.loc[condition, \"DAY\"] = 1\n df.loc[condition, \"MONTH\"] = 1\n \n condition = df['DATE'].isna() # if 'DATE' is nan. \n df['time'] = np.where(condition,\n # 'coerce', then invalid parsing will be set as NaT. NaT will result if the number of days are not valid for the month.\n pd.to_datetime(df[['YEAR', 'MONTH', 'DAY']], format='%y%m%d', errors='coerce'), \n pd.to_datetime(df['DATE'], format='%m/%d/%y %H:%M:%S'))\n \n def _define_beg_period(self, \n df: pd.DataFrame # DataFrame containing the `time` column\n ):\n \"Create a standardized date representation for Open Refine.\"\n df['begperiod'] = df['time']\n\n\nApply the transformer for callbacks ParseTimeCB. Then, print the begperiod and time data for seawater.\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[ParseTimeCB(),\n CompareDfsAndTfmCB(dfs)\n ])\ntfm()\nprint(pd.DataFrame.from_dict(tfm.compare_stats) , '\\n')\nprint(tfm.dfs['seawater'][['begperiod','time']])\n\n seawater sediment biota\nNumber of rows in dfs 21216 39817 15827\nNumber of rows in tfm.dfs 21216 39817 15827\nNumber of dropped rows 0 0 0\nNumber of rows in tfm.dfs + Number of dropped rows 21216 39817 15827 \n\n begperiod time\n0 2012-05-23 2012-05-23\n1 2012-05-23 2012-05-23\n2 2012-06-17 2012-06-17\n3 2012-05-24 2012-05-24\n4 2012-05-24 2012-05-24\n... ... ...\n21211 2021-10-15 2021-10-15\n21212 2021-11-04 2021-11-04\n21213 2021-10-15 2021-10-15\n21214 2021-05-17 2021-05-17\n21215 2021-05-13 2021-05-13\n\n[21216 rows x 2 columns]\n\n\n\n\nEncode time\nSeconds since …\nEncodeTimeCB converts the HELCOM time format to the MARIS NetCDF time format.\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[ParseTimeCB(),\n EncodeTimeCB(cfg(), verbose=True),\n CompareDfsAndTfmCB(dfs)\n ])\ntfm()\nprint(pd.DataFrame.from_dict(tfm.compare_stats) , '\\n')\n\n8 of 21216 entries for `time` are invalid for seawater.\n1 of 39817 entries for `time` are invalid for sediment.\n seawater sediment biota\nNumber of rows in dfs 21216 39817 15827\nNumber of rows in tfm.dfs 21208 39816 15827\nNumber of dropped rows 8 1 0\nNumber of rows in tfm.dfs + Number of dropped rows 21216 39817 15827", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#sanitize-value", + "href": "handlers/helcom.html#sanitize-value", + "title": "HELCOM", + "section": "Sanitize value", + "text": "Sanitize value\n\n\nExported source\n# Columns of interest\ncoi_val = {'seawater' : {'val': 'VALUE_Bq/m³'},\n 'biota': {'val': 'VALUE_Bq/kg'},\n 'sediment': {'val': 'VALUE_Bq/kg'}}\n\n\nComment (FA): Those lines can be simplified I think:\nvalue_col = self.coi.get(grp, {}).get('val')\nif value_col and value_col in df.columns:\n\nsource\n\nSanitizeValue\n\n SanitizeValue (coi:dict)\n\nSanitize value by removing blank entries and ensuring the ‘value’ column is retained.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\ncoi\ndict\nDictionary containing column names for values based on group\n\n\n\n\n\nExported source\nclass SanitizeValue(Callback):\n \"Sanitize value by removing blank entries and ensuring the 'value' column is retained.\"\n def __init__(self, \n coi:dict # Dictionary containing column names for values based on group\n ):\n fc.store_attr()\n\n def __call__(self, \n tfm # The transformer object containing DataFrames\n ):\n \"Sanitize the DataFrames in the transformer by removing rows with blank values in specified columns.\"\n for grp in tfm.dfs.keys():\n self._sanitize_dataframe(tfm.dfs[grp], grp)\n\n def _sanitize_dataframe(self, \n df:pd.DataFrame, # DataFrame to sanitize\n grp:str # Group name to determine column names\n ):\n \"Remove rows where specified value columns are blank and ensure the 'value' column is included.\"\n value_col = self.coi.get(grp, {}).get('val')\n if value_col and value_col in df.columns:\n df.dropna(subset=[value_col], inplace=True)\n # Ensure 'value' column is retained\n if 'value' not in df.columns:\n df['value'] = df[value_col]\n\n\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[SanitizeValue(coi_val),\n CompareDfsAndTfmCB(dfs)\n ])\n\ntfm()\nprint(pd.DataFrame.from_dict(tfm.compare_stats) , '\\n')\n\n seawater sediment biota\nNumber of rows in dfs 21216 39817 15827\nNumber of rows in tfm.dfs 21122 39532 15798\nNumber of dropped rows 94 285 29\nNumber of rows in tfm.dfs + Number of dropped rows 21216 39817 15827", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#normalize-uncertainty", + "href": "handlers/helcom.html#normalize-uncertainty", + "title": "HELCOM", + "section": "Normalize uncertainty", + "text": "Normalize uncertainty\nFunction unc_rel2stan converts uncertainty from relative uncertainty to standard uncertainty.\n\nsource\n\nunc_rel2stan\n\n unc_rel2stan (df:pandas.core.frame.DataFrame, meas_col:str, unc_col:str)\n\nConvert relative uncertainty to absolute uncertainty.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\ndf\nDataFrame\nDataFrame containing measurement and uncertainty columns\n\n\nmeas_col\nstr\nName of the column with measurement values\n\n\nunc_col\nstr\nName of the column with relative uncertainty values (percentages)\n\n\nReturns\nSeries\nSeries with calculated absolute uncertainties\n\n\n\n\n\nExported source\ndef unc_rel2stan(\n df:pd.DataFrame, # DataFrame containing measurement and uncertainty columns\n meas_col:str, # Name of the column with measurement values\n unc_col:str # Name of the column with relative uncertainty values (percentages)\n) -> pd.Series: # Series with calculated absolute uncertainties\n \"Convert relative uncertainty to absolute uncertainty.\"\n return df.apply(lambda row: row[unc_col] * row[meas_col] / 100, axis=1)\n\n\nFor each sample type in the Helcom dataset, the uncertainty is given as a relative uncertainty. The column names for both the value and the uncertainty vary by sample type. The coi_units_unc dictionary defines the column names for the Value and Uncertainty for each sample type.\n\n\nExported source\n# Columns of interest\ncoi_units_unc = [('seawater', 'VALUE_Bq/m³', 'ERROR%_m³'),\n ('biota', 'VALUE_Bq/kg', 'ERROR%'),\n ('sediment', 'VALUE_Bq/kg', 'ERROR%_kg')]\n\n\nNormalizeUncCB callback normalizes the uncertainty by converting from relative uncertainty to standard uncertainty.\n\nsource\n\n\nNormalizeUncCB\n\n NormalizeUncCB (fn_convert_unc:Callable=<function unc_rel2stan>,\n coi:List=[('seawater', 'VALUE_Bq/m³', 'ERROR%_m³'),\n ('biota', 'VALUE_Bq/kg', 'ERROR%'), ('sediment',\n 'VALUE_Bq/kg', 'ERROR%_kg')])\n\nConvert from relative error % to uncertainty of activity unit.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nfn_convert_unc\nCallable\nunc_rel2stan\nFunction converting relative uncertainty to absolute uncertainty\n\n\ncoi\nList\n[(‘seawater’, ‘VALUE_Bq/m³’, ’ERROR%_m³’), (‘biota’, ‘VALUE_Bq/kg’, ‘ERROR%’), (‘sediment’, ‘VALUE_Bq/kg’, ’ERROR%_kg’)]\nList of columns of interest\n\n\n\n\n\nExported source\nclass NormalizeUncCB(Callback):\n \"Convert from relative error % to uncertainty of activity unit.\"\n def __init__(self, \n fn_convert_unc:Callable=unc_rel2stan, # Function converting relative uncertainty to absolute uncertainty\n coi:List=coi_units_unc # List of columns of interest\n ):\n fc.store_attr()\n \n def __call__(self, tfm):\n for grp, val, unc in self.coi:\n if grp in tfm.dfs:\n df = tfm.dfs[grp]\n df['uncertainty'] = self.fn_convert_unc(df, val, unc)\n\n\nApply the transformer for callback NormalizeUncCB(). Then, print the value (i.e. activity per unit ) and standard uncertainty for each sample type.\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[NormalizeUncCB(),\n SanitizeValue(coi_val)])\n\nprint(tfm()['seawater'][['value', 'uncertainty']][:5])\nprint(tfm()['biota'][['value', 'uncertainty']][:5])\nprint(tfm()['sediment'][['value', 'uncertainty']][:5])\n\n value uncertainty\n0 5.3 1.696\n1 19.9 3.980\n2 25.5 5.100\n3 17.0 4.930\n4 22.2 3.996\n value uncertainty\n0 0.010140 NaN\n1 135.300000 4.830210\n2 0.013980 NaN\n3 4.338000 0.150962\n4 0.009614 NaN\n value uncertainty\n0 35.0 9.10\n1 36.0 7.92\n2 38.0 9.12\n3 36.0 9.00\n4 30.0 6.90", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#remap-biota-species", + "href": "handlers/helcom.html#remap-biota-species", + "title": "HELCOM", + "section": "Remap Biota species", + "text": "Remap Biota species\nWe follow in the next following processing steps the same approach as for remapping of nuclide names above.\nLet’s inspect the RUBIN_NAME.csv file provided by HELCOM describing the biota species nomenclature.\n\npd.read_csv(Path(fname_in) / 'RUBIN_NAME.csv').head()\n\n\n\n\n\n\n\n\nRUBIN_ID\nRUBIN\nSCIENTIFIC NAME\nENGLISH NAME\n\n\n\n\n0\n11\nABRA BRA\nABRAMIS BRAMA\nBREAM\n\n\n1\n12\nANGU ANG\nANGUILLA ANGUILLA\nEEL\n\n\n2\n13\nARCT ISL\nARCTICA ISLANDICA\nISLAND CYPRINE\n\n\n3\n14\nASTE RUB\nASTERIAS RUBENS\nCOMMON STARFISH\n\n\n4\n15\nCARD EDU\nCARDIUM EDULE\nCOCKLE\n\n\n\n\n\n\n\nWe try to remap the SCIENTIFIC NAME column to the species column of the MARIS nomenclature, again using a Remapper object:\n\nremapper = Remapper(provider_lut_df=pd.read_csv(Path(fname_in) / 'RUBIN_NAME.csv'),\n maris_lut_fn=species_lut_path,\n maris_col_id='species_id',\n maris_col_name='species',\n provider_col_to_match='SCIENTIFIC NAME',\n provider_col_key='RUBIN',\n fname_cache='species_helcom.pkl'\n )\n\nremapper.generate_lookup_table(as_df=True)\nremapper.select_match(match_score_threshold=1)\n\nProcessing: 100%|██████████| 46/46 [00:07<00:00, 5.95it/s]\n\n\n\n\n\n\n\n\n\nmatched_maris_name\nsource_name\nmatch_score\n\n\nsource_key\n\n\n\n\n\n\n\nSTIZ LUC\nSander lucioperca\nSTIZOSTEDION LUCIOPERCA\n10\n\n\nLAMI SAC\nLaminaria japonica\nLAMINARIA SACCHARINA\n7\n\n\nCARD EDU\nCardiidae\nCARDIUM EDULE\n6\n\n\nENCH CIM\nEchinodermata\nENCHINODERMATA CIM\n5\n\n\nPSET MAX\nPinctada maxima\nPSETTA MAXIMA\n5\n\n\nMACO BAL\nMacoma balthica\nMACOMA BALTICA\n1\n\n\nSTUC PEC\nStuckenia pectinata\nSTUCKENIA PECTINATE\n1\n\n\n\n\n\n\n\nWe fix below some of the entries that are not properly matched by the Remapper object:\n\n\nExported source\nfixes_biota_species = {\n 'CARDIUM EDULE': 'Cerastoderma edule',\n 'LAMINARIA SACCHARINA': 'Saccharina latissima',\n 'PSETTA MAXIMA': 'Scophthalmus maximus',\n 'STIZOSTEDION LUCIOPERCA': 'Sander luciopercas'}\n\n\nAnd give it an another try:\n\nremapper.generate_lookup_table(fixes=fixes_biota_species)\nremapper.select_match(match_score_threshold=1)\n\nProcessing: 100%|██████████| 46/46 [00:07<00:00, 6.23it/s]\n\n\n\n\n\n\n\n\n\nmatched_maris_name\nsource_name\nmatch_score\n\n\nsource_key\n\n\n\n\n\n\n\nENCH CIM\nEchinodermata\nENCHINODERMATA CIM\n5\n\n\nMACO BAL\nMacoma balthica\nMACOMA BALTICA\n1\n\n\nSTIZ LUC\nSander lucioperca\nSTIZOSTEDION LUCIOPERCA\n1\n\n\nSTUC PEC\nStuckenia pectinata\nSTUCKENIA PECTINATE\n1\n\n\n\n\n\n\n\nVisual inspection of the remaining unperfectly matched entries seem acceptable to proceed.\nWe now define a callback to apply the lookup table to the biota dataframe.\n\nsource\n\nRemapBiotaSpeciesCB\n\n RemapBiotaSpeciesCB (fn_lut:Callable)\n\nBiota species standardized to MARIS format.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nfn_lut\nCallable\nFunction that returns the lookup table dictionary\n\n\n\n\n\nExported source\nclass RemapBiotaSpeciesCB(Callback):\n \"Biota species standardized to MARIS format.\"\n def __init__(self, \n fn_lut:Callable # Function that returns the lookup table dictionary\n ):\n fc.store_attr()\n\n def __call__(self, tfm):\n \"Remap biota species names in the DataFrame using the lookup table and print unmatched RUBIN values.\"\n lut = self.fn_lut()\n tfm.dfs['biota']['species'] = tfm.dfs['biota']['RUBIN'].apply(lambda x: self._get_species(x, lut))\n\n def _get_species(self, \n rubin_value:str, # The RUBIN value from the DataFrame\n lut:dict # The lookup table dictionary\n ):\n \"Get the matched_id from the lookup table and print RUBIN if the matched_id is -1.\"\n match = lut.get(rubin_value.strip(), Match(-1, None, None, None))\n if match.matched_id == -1:\n self.print_unmatched_rubin(rubin_value)\n return match.matched_id\n\n def print_unmatched_rubin(self, \n rubin_value: str # The RUBIN value from the DataFrame\n ):\n \"Print the RUBIN value if the matched_id is -1.\"\n print(f\"Unmatched RUBIN: {rubin_value}\")\n\n\nLet’s see it in action, along with the RemapBiotaSpeciesCB callback:\n\n\nExported source\nlut_biota = lambda: Remapper(provider_lut_df=pd.read_csv(Path(fname_in) / 'RUBIN_NAME.csv'),\n maris_lut_fn=species_lut_path,\n maris_col_id='species_id',\n maris_col_name='species',\n provider_col_to_match='SCIENTIFIC NAME',\n provider_col_key='RUBIN',\n fname_cache='species_helcom.pkl'\n ).generate_lookup_table(fixes=fixes_biota_species, as_df=False, overwrite=False)\n\n\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[RemapBiotaSpeciesCB(lut_biota)])\n\n# For instance:\nprint(tfm()['biota']['species'].unique())\n\n[ 99 243 50 139 270 192 191 284 84 269 122 96 287 279\n 278 288 286 244 129 275 271 285 283 247 120 59 280 274\n 273 290 289 272 277 276 21 282 110 281 245 704 1524 703\n 1611 621 60]", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#remap-biota-tissues", + "href": "handlers/helcom.html#remap-biota-tissues", + "title": "HELCOM", + "section": "Remap Biota tissues", + "text": "Remap Biota tissues\nLet’s inspect the TISSUE.csv file provided by HELCOM describing the tissue nomenclature. Biota tissue is known as body part in the maris data set.\n\npd.read_csv('../../_data/accdb/mors/csv/TISSUE.csv').head()\n\n\n\n\n\n\n\n\nTISSUE\nTISSUE_DESCRIPTION\n\n\n\n\n0\n1\nWHOLE FISH\n\n\n1\n2\nWHOLE FISH WITHOUT ENTRAILS\n\n\n2\n3\nWHOLE FISH WITHOUT HEAD AND ENTRAILS\n\n\n3\n4\nFLESH WITH BONES\n\n\n4\n5\nFLESH WITHOUT BONES (FILETS)\n\n\n\n\n\n\n\n\nremapper = Remapper(provider_lut_df=pd.read_csv('../../_data/accdb/mors/csv/TISSUE.csv'),\n maris_lut_fn=bodyparts_lut_path,\n maris_col_id='bodypar_id',\n maris_col_name='bodypar',\n provider_col_to_match='TISSUE_DESCRIPTION',\n provider_col_key='TISSUE',\n fname_cache='tissues_helcom.pkl'\n )\n\nremapper.generate_lookup_table(as_df=True)\nremapper.select_match(match_score_threshold=1)\n\nProcessing: 100%|██████████| 29/29 [00:00<00:00, 123.14it/s]\n\n\n\n\n\n\n\n\n\nmatched_maris_name\nsource_name\nmatch_score\n\n\nsource_key\n\n\n\n\n\n\n\n3\nFlesh without bones\nWHOLE FISH WITHOUT HEAD AND ENTRAILS\n20\n\n\n2\nFlesh without bones\nWHOLE FISH WITHOUT ENTRAILS\n13\n\n\n8\nSoft parts\nSKIN/EPIDERMIS\n10\n\n\n5\nFlesh without bones\nFLESH WITHOUT BONES (FILETS)\n9\n\n\n1\nWhole animal\nWHOLE FISH\n5\n\n\n12\nBrain\nENTRAILS\n5\n\n\n15\nStomach and intestine\nSTOMACH + INTESTINE\n3\n\n\n41\nWhole animal\nWHOLE ANIMALS\n1\n\n\n\n\n\n\n\nWe fix below some of the entries that are not properly matched by the Remapper object:\n\n\nExported source\nfixes_biota_tissues = {\n 'WHOLE FISH WITHOUT HEAD AND ENTRAILS': 'Whole animal eviscerated without head',\n 'ENTRAILS': 'Viscera',\n 'SKIN/EPIDERMIS': 'Skin'}\n\n\n\nremapper.generate_lookup_table(as_df=True, fixes=fixes_biota_tissues)\nremapper.select_match(match_score_threshold=1)\n\nProcessing: 100%|██████████| 29/29 [00:00<00:00, 123.73it/s]\n\n\n\n\n\n\n\n\n\nmatched_maris_name\nsource_name\nmatch_score\n\n\nsource_key\n\n\n\n\n\n\n\n2\nFlesh without bones\nWHOLE FISH WITHOUT ENTRAILS\n13\n\n\n5\nFlesh without bones\nFLESH WITHOUT BONES (FILETS)\n9\n\n\n1\nWhole animal\nWHOLE FISH\n5\n\n\n15\nStomach and intestine\nSTOMACH + INTESTINE\n3\n\n\n41\nWhole animal\nWHOLE ANIMALS\n1\n\n\n\n\n\n\n\n\nsource\n\nRemapBiotaBodyPartCB\n\n RemapBiotaBodyPartCB (fn_lut:Callable)\n\nUpdate bodypart id based on MARIS body part LUT (dbo_bodypar.xlsx).\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nfn_lut\nCallable\nFunction that returns the lookup table dictionary\n\n\n\n\n\nExported source\nclass RemapBiotaBodyPartCB(Callback):\n \"Update bodypart id based on MARIS body part LUT (dbo_bodypar.xlsx).\"\n def __init__(self, \n fn_lut:Callable # Function that returns the lookup table dictionary\n ):\n fc.store_attr()\n\n def __call__(self, tfm):\n \"Remap biota body parts in the DataFrame using the lookup table and print unmatched TISSUE values.\"\n lut = self.fn_lut()\n tfm.dfs['biota']['body_part'] = tfm.dfs['biota']['TISSUE'].apply(lambda x: self._get_body_part(x, lut))\n\n def _get_body_part(self, \n tissue_value:str, # The TISSUE value from the DataFrame\n lut:dict # The lookup table dictionary\n ):\n \"Get the matched_id from the lookup table and print TISSUE if the matched_id is -1.\"\n match = lut.get(tissue_value, Match(-1, None, None, None))\n if match.matched_id == -1: \n self.print_unmatched_tissue(tissue_value)\n return match.matched_id\n\n def print_unmatched_tissue(self, \n tissue_value:str # The TISSUE value from the DataFrame\n ):\n \"Print the TISSUE value if the matched_id is -1.\"\n print(f\"Unmatched TISSUE: {tissue_value}\")\n\n\n\n\nExported source\nlut_tissues = lambda: Remapper(provider_lut_df=pd.read_csv('../../_data/accdb/mors/csv/TISSUE.csv'),\n maris_lut_fn=bodyparts_lut_path,\n maris_col_id='bodypar_id',\n maris_col_name='bodypar',\n provider_col_to_match='TISSUE_DESCRIPTION',\n provider_col_key='TISSUE',\n fname_cache='tissues_helcom.pkl'\n ).generate_lookup_table(fixes=fixes_biota_tissues, as_df=False, overwrite=False)\n\n\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[RemapBiotaSpeciesCB(lut_biota), \n RemapBiotaBodyPartCB(lut_tissues)\n ])\n\nprint(tfm()['biota'][['TISSUE', 'body_part']][:5])\n\n TISSUE body_part\n0 5 52\n1 5 52\n2 5 52\n3 5 52\n4 5 52", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#remap-biogroup", + "href": "handlers/helcom.html#remap-biogroup", + "title": "HELCOM", + "section": "Remap biogroup", + "text": "Remap biogroup\nget_biogroup_lut reads the file at species_lut_path() and from the contents of this file creates a dictionary linking species_id to biogroup_id.\n\n\nExported source\nlut_biogroup = lambda: get_lut(species_lut_path().parent, species_lut_path().name, \n key='species_id', value='biogroup_id')\n\n\nRemapBiogroupCB applies the corrected biota bio group data obtained from the lut_biogroup function to the biota dataframe in the dictionary of dataframes, dfs.\n\nsource\n\nRemapBiogroupCB\n\n RemapBiogroupCB (fn_lut:Callable)\n\nUpdate biogroup id based on MARIS species LUT (dbo_species.xlsx).\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nfn_lut\nCallable\nFunction that returns the lookup table dictionary\n\n\n\n\n\nExported source\nclass RemapBiogroupCB(Callback):\n \"Update biogroup id based on MARIS species LUT (dbo_species.xlsx).\"\n def __init__(self, \n fn_lut:Callable # Function that returns the lookup table dictionary\n ):\n fc.store_attr()\n self.lut = {int(k):v for k,v in fn_lut().items()}\n\n def __call__(self, tfm):\n tfm.dfs['biota']['bio_group'] = tfm.dfs['biota']['species'].apply(self._lookup_biogroup)\n\n def _lookup_biogroup(self, species_id):\n biogroup = self.lut.get(species_id, -1)\n if biogroup == -1: print(f\"Warning: Species ID {species_id} not found in biogroup lookup table\")\n return biogroup\n\n\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[RemapBiotaSpeciesCB(lut_biota), \n RemapBiotaBodyPartCB(lut_tissues),\n RemapBiogroupCB(lut_biogroup)])\n\nprint(tfm()['biota']['bio_group'].unique())\n\n[ 4 2 14 11 8 3]", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#remap-taxon-information", + "href": "handlers/helcom.html#remap-taxon-information", + "title": "HELCOM", + "section": "Remap Taxon Information", + "text": "Remap Taxon Information\nThese details (Taxonname , TaxonRepName, Taxonrank) are used for importing into the MARIS master database, but are not included in the NetCDF encoding. We need to get the taxon information from the dbo_species.xlsx file:\nWe need to get the taxon information from the dbo_species.xlsx file:\n\nsource\n\nget_taxon_info_lut\n\n get_taxon_info_lut (maris_lut:str)\n\nRetrieve a lookup table for Taxonname from a MARIS lookup table.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nmaris_lut\nstr\nPath to the MARIS lookup table (Excel file)\n\n\nReturns\ndict\nA dictionary mapping species_id to biogroup_id\n\n\n\n\n\nExported source\n# TODO: Include Commonname field after next MARIS data reconciling process.\ndef get_taxon_info_lut(\n maris_lut:str # Path to the MARIS lookup table (Excel file)\n) -> dict: # A dictionary mapping species_id to biogroup_id\n \"Retrieve a lookup table for Taxonname from a MARIS lookup table.\"\n species = pd.read_excel(maris_lut)\n return species[['species_id', 'Taxonname', 'Taxonrank','TaxonDB','TaxonDBID','TaxonDBURL']].set_index('species_id').to_dict()\n\nlut_taxon = lambda: get_taxon_info_lut(species_lut_path())\n\n\n\nsource\n\n\nRemapTaxonInformationCB\n\n RemapTaxonInformationCB (fn_lut:Callable)\n\nUpdate taxon names based on MARIS species LUT dbo_species.xlsx.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nfn_lut\nCallable\nFunction that returns the lookup table dictionary\n\n\n\n\n\nExported source\nclass RemapTaxonInformationCB(Callback):\n \"Update taxon names based on MARIS species LUT `dbo_species.xlsx`.\"\n def __init__(self, \n fn_lut:Callable # Function that returns the lookup table dictionary\n ):\n fc.store_attr()\n\n def __call__(self, tfm):\n \"Update taxon information columns in the DataFrame using the lookup table.\"\n lut = self.fn_lut()\n df = tfm.dfs['biota']\n \n self._set_taxon_rep_name(df)\n \n taxon_columns = ['Taxonname', 'Taxonrank', 'TaxonDB', 'TaxonDBID', 'TaxonDBURL']\n for col in taxon_columns:\n df[col] = df['species'].apply(lambda x: self._get_name_by_species_id(x, lut[col]))\n\n def _set_taxon_rep_name(self, df: pd.DataFrame):\n \"Set the `TaxonRepName` column to the `RUBIN` column values if it exists.\"\n if 'RUBIN' in df.columns:\n df['TaxonRepName'] = df['RUBIN']\n else:\n print(\"Warning: 'RUBIN' column not found in DataFrame.\")\n\n def _get_name_by_species_id(self, species_id: str, lut: dict) -> str:\n \"Get the name from the lookup table, defaulting to 'Unknown' if not found.\"\n name = lut.get(species_id, 'Unknown')\n if name == 'Unknown':\n print(f\"Unmatched species ID: {species_id}\")\n return name\n\n\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[ \n RemapBiotaSpeciesCB(lut_biota), \n RemapBiotaBodyPartCB(lut_tissues),\n RemapBiogroupCB(lut_biogroup),\n RemapTaxonInformationCB(lut_taxon)\n ])\ntfm()\nprint(tfm.dfs['biota'][['Taxonname', 'Taxonrank','TaxonDB','TaxonDBID','TaxonDBURL']].drop_duplicates().head())\n\n Taxonname Taxonrank TaxonDB TaxonDBID \\\n0 Gadus morhua species Wikidata Q199788 \n40 Sprattus sprattus species Wikidata Q506823 \n44 Clupea harengus species Wikidata Q2396858 \n77 Merlangius merlangus species Wikidata Q273083 \n78 Limanda limanda species Wikidata Q1135526 \n\n TaxonDBURL \n0 https://www.wikidata.org/wiki/Q199788 \n40 https://www.wikidata.org/wiki/Q506823 \n44 https://www.wikidata.org/wiki/Q2396858 \n77 https://www.wikidata.org/wiki/Q273083 \n78 https://www.wikidata.org/wiki/Q1135526", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#remap-sediment-types", + "href": "handlers/helcom.html#remap-sediment-types", + "title": "HELCOM", + "section": "Remap Sediment types", + "text": "Remap Sediment types\nWe use again the same IMFA (Inspect, Match, Fix, Apply) pattern to remap the HELCOM sediment types.\nLet’s inspect the SEDIMENT_TYPE.csv file provided by HELCOM describing the sediment type nomenclature:\n\npd.read_csv(Path(fname_in) / 'SEDIMENT_TYPE.csv').head()\n\n\n\n\n\n\n\n\nSEDI\nSEDIMENT TYPE\nRECOMMENDED TO BE USED\n\n\n\n\n0\n-99\nNO DATA\nNaN\n\n\n1\n0\nGRAVEL\nYES\n\n\n2\n1\nSAND\nYES\n\n\n3\n2\nFINE SAND\nNO\n\n\n4\n3\nSILT\nYES\n\n\n\n\n\n\n\n\n\n\n\n\n\nTip\n\n\n\nFEEDBACK TO DATA PROVIDER: The SEDI values 56 and 73 are not found in the SEDIMENT_TYPE.csv lookup table provided. Note also there are many nan values in the SEDIMENT_TYPE.csv file.\nWe reassign them to -99 for now but should be clarified/fixed. This is demonstrated below.\n\n\n\ndf_sed_lut = pd.read_csv(Path(fname_in) / 'SEDIMENT_TYPE.csv')\ndfs = load_data(fname_in)\n\nsediment_sedi = set(dfs['sediment'].SEDI.unique())\nlookup_sedi = set(df_sed_lut['SEDI'])\nmissing = sediment_sedi - lookup_sedi\nprint(f\"Missing SEDI values: {missing if missing else 'None'}\")\n\nMissing SEDI values: {56.0, 73.0, nan}\n\n\nLet’s try to match as many as possible:\n\nremapper = Remapper(provider_lut_df=pd.read_csv(Path(fname_in)/'SEDIMENT_TYPE.csv'),\n maris_lut_fn=sediments_lut_path,\n maris_col_id='sedtype_id',\n maris_col_name='sedtype',\n provider_col_to_match='SEDIMENT TYPE',\n provider_col_key='SEDI',\n fname_cache='sediments_helcom.pkl'\n )\n\nremapper.generate_lookup_table(as_df=True)\nremapper.select_match(match_score_threshold=1)\n\nProcessing: 100%|██████████| 47/47 [00:00<00:00, 137.20it/s]\n\n\n\n\n\n\n\n\n\nmatched_maris_name\nsource_name\nmatch_score\n\n\nsource_key\n\n\n\n\n\n\n\n-99\nSoft\nNO DATA\n5\n\n\n50\nMud and gravel\nMUD AND GARVEL\n2\n\n\n46\nGlacial clay\nCLACIAL CLAY\n1\n\n\n\n\n\n\n\n\n\nExported source\nfixes_sediments = {\n 'NO DATA': '(Not available)'\n}\n\n\n\nremapper.generate_lookup_table(as_df=True, fixes=fixes_sediments)\nremapper.select_match(match_score_threshold=1)\n\nProcessing: 100%|██████████| 47/47 [00:00<00:00, 83.93it/s] \n\n\n\n\n\n\n\n\n\nmatched_maris_name\nsource_name\nmatch_score\n\n\nsource_key\n\n\n\n\n\n\n\n50\nMud and gravel\nMUD AND GARVEL\n2\n\n\n46\nGlacial clay\nCLACIAL CLAY\n1\n\n\n\n\n\n\n\n\nsource\n\nRemapSedimentCB\n\n RemapSedimentCB (fn_lut:Callable)\n\nUpdate sediment id based on MARIS species LUT (dbo_sedtype.xlsx).\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nfn_lut\nCallable\nFunction that returns the lookup table dictionary\n\n\n\n\n\nExported source\nclass RemapSedimentCB(Callback):\n \"Update sediment id based on MARIS species LUT (dbo_sedtype.xlsx).\"\n def __init__(self, \n fn_lut:Callable, # Function that returns the lookup table dictionary\n ):\n fc.store_attr()\n\n def _fix_inconsistent_sedi(self, df:pd.DataFrame):\n \"Temporary fix for inconsistent SEDI values. Data provider to confirm and clarify.\"\n df['SEDI'] = df['SEDI'].replace({56: -99, 73: -99, np.nan: -99})\n return df\n \n def __call__(self, tfm):\n \"Remap sediment types in the DataFrame using the lookup table and handle specific replacements.\"\n lut = self.fn_lut()\n \n # Set SedRepName (TBC: what's used for?)\n tfm.dfs['sediment']['SedRepName'] = tfm.dfs['sediment']['SEDI'] \n \n tfm.dfs['sediment'] = self._fix_inconsistent_sedi(tfm.dfs['sediment'])\n tfm.dfs['sediment']['sed_type'] = tfm.dfs['sediment']['SEDI'].apply(lambda x: self._get_sediment_type(x, lut))\n\n def _get_sediment_type(self, \n sedi_value:int, # The `SEDI` value from the DataFrame\n lut:dict # The lookup table dictionary\n ): \n \"Get the matched_id from the lookup table and print SEDI if the matched_id is -1.\"\n match = lut.get(sedi_value, Match(-1, None, None, None))\n \n if match.matched_id == -1:\n self._print_unmatched_sedi(sedi_value)\n return match.matched_id\n\n def _print_unmatched_sedi(self, \n sedi_value:int # The `SEDI` value from the DataFram\n ):\n \"Print the SEDI value if the matched_id is -1.\"\n print(f\"Unmatched SEDI: {sedi_value}\")\n\n\n\n\nExported source\nlut_sediments = lambda: Remapper(provider_lut_df=pd.read_csv(Path(fname_in) / 'SEDIMENT_TYPE.csv'),\n maris_lut_fn=sediments_lut_path,\n maris_col_id='sedtype_id',\n maris_col_name='sedtype',\n provider_col_to_match='SEDIMENT TYPE',\n provider_col_key='SEDI',\n fname_cache='sediments_helcom.pkl'\n ).generate_lookup_table(fixes=fixes_sediments, as_df=False, overwrite=False)\n\n\nApply the transformer for callbacks RemapSedimentCB(get_maris_sediments). Then, print the SEDI and sed_type for the biota dataframe.\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[RemapSedimentCB(lut_sediments)])\n\ntfm()['sediment']['sed_type'].unique()\n\narray([ 0, 2, 58, 30, 59, 55, 56, 36, 29, 47, 4, 54, 33, 6, 44, 42, 48,\n 61, 57, 28, 49, 32, 45, 39, 46, 38, 31, 60, 62, 26, 53, 52, 1, 51,\n 37, 34, 50, 7, 10, 41, 43, 35])", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#remap-units", + "href": "handlers/helcom.html#remap-units", + "title": "HELCOM", + "section": "Remap units", + "text": "Remap units\n\n\n\n\n\n\nTip\n\n\n\nFEEDBACK TO DATA PROVIDER: The handling of unit types varies between biota and sediment sample types. For consistency and ease of use, it would be beneficial to have dedicated unit columns for all sample types.\n\n\nFor seawater and sediment sample types, the HELCOM dataset refers to units direcly in the name of certain columns, such as VALUE_Bq/m³ or VALUE_Bq/kg. As for biota, the units are included in the BASIS column. This is shown below:\n\ndfs = load_data(fname_in)\nfor grp in ['biota', 'sediment', 'seawater']:\n print(f\"{grp}: {dfs[grp].columns}\")\n \ndfs['biota']['BASIS'].unique()\n\nbiota: Index(['KEY', 'NUCLIDE', 'METHOD', '< VALUE_Bq/kg', 'VALUE_Bq/kg', 'BASIS',\n 'ERROR%', 'NUMBER', 'DATE_OF_ENTRY_x', 'COUNTRY', 'LABORATORY',\n 'SEQUENCE', 'DATE', 'YEAR', 'MONTH', 'DAY', 'STATION',\n 'LATITUDE ddmmmm', 'LATITUDE dddddd', 'LONGITUDE ddmmmm',\n 'LONGITUDE dddddd', 'SDEPTH', 'RUBIN', 'BIOTATYPE', 'TISSUE', 'NO',\n 'LENGTH', 'WEIGHT', 'DW%', 'LOI%', 'MORS_SUBBASIN', 'HELCOM_SUBBASIN',\n 'DATE_OF_ENTRY_y'],\n dtype='object')\nsediment: Index(['KEY', 'NUCLIDE', 'METHOD', '< VALUE_Bq/kg', 'VALUE_Bq/kg', 'ERROR%_kg',\n '< VALUE_Bq/m²', 'VALUE_Bq/m²', 'ERROR%_m²', 'DATE_OF_ENTRY_x',\n 'COUNTRY', 'LABORATORY', 'SEQUENCE', 'DATE', 'YEAR', 'MONTH', 'DAY',\n 'STATION', 'LATITUDE (ddmmmm)', 'LATITUDE (dddddd)',\n 'LONGITUDE (ddmmmm)', 'LONGITUDE (dddddd)', 'DEVICE', 'TDEPTH',\n 'UPPSLI', 'LOWSLI', 'AREA', 'SEDI', 'OXIC', 'DW%', 'LOI%',\n 'MORS_SUBBASIN', 'HELCOM_SUBBASIN', 'SUM_LINK', 'DATE_OF_ENTRY_y'],\n dtype='object')\nseawater: Index(['KEY', 'NUCLIDE', 'METHOD', '< VALUE_Bq/m³', 'VALUE_Bq/m³', 'ERROR%_m³',\n 'DATE_OF_ENTRY_x', 'COUNTRY', 'LABORATORY', 'SEQUENCE', 'DATE', 'YEAR',\n 'MONTH', 'DAY', 'STATION', 'LATITUDE (ddmmmm)', 'LATITUDE (dddddd)',\n 'LONGITUDE (ddmmmm)', 'LONGITUDE (dddddd)', 'TDEPTH', 'SDEPTH', 'SALIN',\n 'TTEMP', 'FILT', 'MORS_SUBBASIN', 'HELCOM_SUBBASIN', 'DATE_OF_ENTRY_y'],\n dtype='object')\n\n\narray(['W', nan, 'D', 'F'], dtype=object)\n\n\nGiven the inconsistent handling of units across sample types, we need to define custom mapping rules for standardizing the units. Below the MARIS unit types:\n\npd.read_excel(unit_lut_path())[['unit_id', 'unit', 'unit_sanitized']]\n\n\n\n\n\n\n\n\nunit_id\nunit\nunit_sanitized\n\n\n\n\n0\n-1\nNot applicable\nNot applicable\n\n\n1\n0\nNOT AVAILABLE\nNOT AVAILABLE\n\n\n2\n1\nBq/m3\nBq per m3\n\n\n3\n2\nBq/m2\nBq per m2\n\n\n4\n3\nBq/kg\nBq per kg\n\n\n5\n4\nBq/kgd\nBq per kgd\n\n\n6\n5\nBq/kgw\nBq per kgw\n\n\n7\n6\nkg/kg\nkg per kg\n\n\n8\n7\nTU\nTU\n\n\n9\n8\nDELTA/mill\nDELTA per mill\n\n\n10\n9\natom/kg\natom per kg\n\n\n11\n10\natom/kgd\natom per kgd\n\n\n12\n11\natom/kgw\natom per kgw\n\n\n13\n12\natom/l\natom per l\n\n\n14\n13\nBq/kgC\nBq per kgC\n\n\n\n\n\n\n\nWe define unit names renaming rules from HELCOM in an ad hoc way for now:\n\nsource\n\nRemapUnitCB\n\n RemapUnitCB (lut_units:dict={'seawater': 1, 'sediment': 4, 'biota': {'D':\n 4, 'W': 5, 'F': 5}})\n\nSet the unit id column in the DataFrames based on a lookup table.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nlut_units\ndict\n{‘seawater’: 1, ‘sediment’: 4, ‘biota’: {‘D’: 4, ‘W’: 5, ‘F’: 5}}\nDictionary containing renaming rules for different unit categories\n\n\n\n\n\nExported source\nlut_units = {\n 'seawater': 1, # 'Bq/m3'\n 'sediment': 4, # 'Bq/kgd' for sediment\n 'biota': {\n 'D': 4, # 'Bq/kgd'\n 'W': 5, # 'Bq/kgw'\n 'F': 5 # 'Bq/kgw' (assumed to be 'Fresh', so set to wet)\n }\n}\n\n\nApply the transformer for callback RemapUnitCB(). Then, print the unique unit for the seawater dataframe.\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[RemapUnitCB()])\n\nfor grp in ['biota', 'sediment', 'seawater']:\n print(f\"{grp}: {tfm()[grp]['unit'].unique()}\")\n\nbiota: [5 0 4]\nsediment: [4]\nseawater: [1]", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#remap-detection-limit", + "href": "handlers/helcom.html#remap-detection-limit", + "title": "HELCOM", + "section": "Remap detection limit", + "text": "Remap detection limit\nDetection limits are encoded as follows in MARIS:\n\npd.read_excel(detection_limit_lut_path())\n\n\n\n\n\n\n\n\nid\nname\nname_sanitized\n\n\n\n\n0\n-1\nNot applicable\nNot applicable\n\n\n1\n0\nNot Available\nNot available\n\n\n2\n1\n=\nDetected value\n\n\n3\n2\n<\nDetection limit\n\n\n4\n3\nND\nNot detected\n\n\n5\n4\nDE\nDerived\n\n\n\n\n\n\n\n\n\nExported source\nlut_dl = lambda: pd.read_excel(detection_limit_lut_path(), usecols=['name','id']).set_index('name').to_dict()['id']\n\n\nBased on columns of interest for each sample type:\n\n\nExported source\ncoi_dl = {'seawater' : {'val' : 'VALUE_Bq/m³',\n 'unc' : 'ERROR%_m³',\n 'dl' : '< VALUE_Bq/m³'},\n 'biota': {'val' : 'VALUE_Bq/kg',\n 'unc' : 'ERROR%',\n 'dl' : '< VALUE_Bq/kg'},\n 'sediment': {\n 'val' : 'VALUE_Bq/kg',\n 'unc' : 'ERROR%_kg',\n 'dl' : '< VALUE_Bq/kg'}}\n\n\nWe follow the following business logic to encode the detection limit:\nRemapDetectionLimitCB creates a detection_limit column with values determined as follows: 1. Perform a lookup with the appropriate columns value type (or detection limit) columns (< VALUE_Bq/m³ or < VALUE_Bq/kg) against the table returned from the function get_detectionlimit_lut. 2. If < VALUE_Bq/m³ or < VALUE_Bq/kg is NaN but both activity values (VALUE_Bq/m³ or VALUE_Bq/kg) and standard uncertainty (ERROR%_m³, ERROR%, or ERROR%_kg) are provided, then assign the ID of 1 (i.e. “Detected value”). 3. For other NaN values in the detection_limit column, set them to 0 (i.e. Not Available).\n\nsource\n\nRemapDetectionLimitCB\n\n RemapDetectionLimitCB (coi:dict, fn_lut:<built-infunctioncallable>)\n\nRemap value type to MARIS format.\n\n\n\n\nType\nDetails\n\n\n\n\ncoi\ndict\nConfiguration options for column names\n\n\nfn_lut\ncallable\nFunction that returns a lookup table\n\n\n\n\n\nExported source\n# TO BE REFACTORED\nclass RemapDetectionLimitCB(Callback):\n \"Remap value type to MARIS format.\"\n def __init__(self, \n coi:dict, # Configuration options for column names\n fn_lut:callable # Function that returns a lookup table\n ):\n fc.store_attr()\n\n def __call__(self, tfm):\n \"Remap detection limits in the DataFrames using the lookup table.\"\n lut = self.fn_lut()\n \n for grp in tfm.dfs:\n df = tfm.dfs[grp]\n self._update_detection_limit(df, grp, lut)\n \n def _update_detection_limit(self, \n df:pd.DataFrame, # The DataFrame to modify\n grp:str, # The group name to get the column configuration\n lut:dict # The lookup table dictionary\n ):\n \"Update detection limit column in the DataFrame based on lookup table and rules.\"\n detection_col = self.coi[grp]['dl']\n value_col = self.coi[grp]['val']\n uncertainty_col = self.coi[grp]['unc']\n \n # Copy detection limit column\n df['detection_limit'] = df[detection_col]\n \n # Fill values with '=' or 'Not Available'\n condition = ((df[value_col].notna()) & (df[uncertainty_col].notna()) &\n (~df['detection_limit'].isin(lut.keys())))\n df.loc[condition, 'detection_limit'] = '='\n df.loc[~df['detection_limit'].isin(lut.keys()), 'detection_limit'] = 'Not Available'\n \n # Perform lookup\n df['detection_limit'] = df['detection_limit'].map(lut)\n\n\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[\n NormalizeUncCB(),\n SanitizeValue(coi_val), \n RemapUnitCB(),\n RemapDetectionLimitCB(coi_dl, lut_dl)])\n\n\nfor grp in ['biota', 'sediment', 'seawater']:\n print(f\"{grp}: {tfm()[grp]['detection_limit'].unique()}\")\n\nbiota: [2 1 0]\nsediment: [1 2 0]\nseawater: [1 2 0]", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#remap-filtering-status", + "href": "handlers/helcom.html#remap-filtering-status", + "title": "HELCOM", + "section": "Remap filtering status", + "text": "Remap filtering status\nHELCOM filtered status is encoded as follows in the FILT column:\n\ndfs = load_data(fname_in)\nget_unique_across_dfs(dfs, col_name='FILT', as_df=True).head(5)\n\n\n\n\n\n\n\n\nindex\nvalue\n\n\n\n\n0\n0\nNaN\n\n\n1\n1\nN\n\n\n2\n2\nF\n\n\n3\n3\nn\n\n\n\n\n\n\n\nWhile MARIS uses a different encoding for filtered status:\n\npd.read_excel(filtered_lut_path())\n\n\n\n\n\n\n\n\nid\nname\n\n\n\n\n0\n-1\nNot applicable\n\n\n1\n0\nNot available\n\n\n2\n1\nYes\n\n\n3\n2\nNo\n\n\n\n\n\n\n\nFor only four categories to remap, the Remapper is an overkill. We can use a simple dictionary to map the values:\n\n\nExported source\nlut_filtered = {\n 'N': 2,\n 'n': 2,\n 'F': 1\n}\n\n\nRemapFiltCB converts the HELCOM FILT format to the MARIS FILT format.\n\nsource\n\nRemapFiltCB\n\n RemapFiltCB (lut_filtered:dict={'N': 2, 'n': 2, 'F': 1})\n\nLookup FILT value in dataframe using the lookup table.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nlut_filtered\ndict\n{‘N’: 2, ‘n’: 2, ‘F’: 1}\nDictionary mapping FILT codes to their corresponding names\n\n\n\n\n\nExported source\nclass RemapFiltCB(Callback):\n \"Lookup FILT value in dataframe using the lookup table.\"\n def __init__(self,\n lut_filtered:dict=lut_filtered, # Dictionary mapping FILT codes to their corresponding names\n ):\n fc.store_attr()\n\n def __call__(self, tfm):\n for df in tfm.dfs.values():\n if 'FILT' in df.columns:\n df['FILT'] = df['FILT'].map(lambda x: self.lut_filtered.get(x, 0))\n\n\nFor instance:\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[RemapFiltCB(lut_filtered)])\n\nprint(tfm()['seawater']['FILT'].unique())\n\n[0 2 1]", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#add-sample-laboratory-code", + "href": "handlers/helcom.html#add-sample-laboratory-code", + "title": "HELCOM", + "section": "Add Sample Laboratory code", + "text": "Add Sample Laboratory code\nSample Laboratory code is currently stored in MARIS master DB but not encoded as NetCDF variable. Decision to include it in the NetCDF output is TBD.\n\nsource\n\nAddSampleLabCodeCB\n\n AddSampleLabCodeCB ()\n\nRemap KEY column to samplabcode in each DataFrame.\n\n\nExported source\nclass AddSampleLabCodeCB(Callback):\n \"Remap `KEY` column to `samplabcode` in each DataFrame.\"\n def __call__(self, tfm):\n for grp in tfm.dfs:\n self._remap_sample_id(tfm.dfs[grp])\n \n def _remap_sample_id(self, df:pd.DataFrame):\n df['samplabcode'] = df['KEY']\n\n\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[\n AddSampleLabCodeCB(),\n CompareDfsAndTfmCB(dfs)\n ])\n\nprint(tfm()['seawater']['samplabcode'].unique())\nprint(pd.DataFrame.from_dict(tfm.compare_stats) , '\\n')\n\n['WKRIL2012003' 'WKRIL2012004' 'WKRIL2012005' ... 'WSSSM2021006'\n 'WSSSM2021007' 'WSSSM2021008']\n seawater sediment biota\nNumber of rows in dfs 21216 39817 15827\nNumber of rows in tfm.dfs 21216 39817 15827\nNumber of dropped rows 0 0 0\nNumber of rows in tfm.dfs + Number of dropped rows 21216 39817 15827", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#add-masurement-note", + "href": "handlers/helcom.html#add-masurement-note", + "title": "HELCOM", + "section": "Add masurement note", + "text": "Add masurement note\nThe HELCOM dataset includes a look-up table ANALYSIS_METHOD.csv capturing the measurement method used as described by HELCOM. For instance:\n\npd.read_csv(Path(fname_in) / 'ANALYSIS_METHOD.csv').head()\n\n\n\n\n\n\n\n\nMETHOD\nDESCRIPTION\nCOUNTRY\n\n\n\n\n0\nBFFG01\nGammaspectrometric analysis with Germanium det...\n6\n\n\n1\nBFFG02\nSr-90, a) Y-90 extraction method dried ash and...\n6\n\n\n2\nBFFG03\nPu238, Pu239241; Ashing and and drying the tra...\n6\n\n\n3\nBFFG04\nAm-241 (not to in use any more)\n6\n\n\n4\nCLOR01\n137Cs and 40K activity concentrations are dete...\n67\n\n\n\n\n\n\n\n\nsource\n\nAddMeasurementNoteCB\n\n AddMeasurementNoteCB (fn_lut:<built-infunctioncallable>)\n\nRecord measurement notes by adding a ‘measurenote’ column to DataFrames.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nfn_lut\ncallable\nFunction that returns the lookup dictionary with METHOD as key and DESCRIPTION as value\n\n\n\n\n\nExported source\nlut_method = lambda: pd.read_csv(Path(fname_in) / 'ANALYSIS_METHOD.csv').set_index('METHOD').to_dict()['DESCRIPTION']\n\n\n\n\nExported source\nclass AddMeasurementNoteCB(Callback):\n \"Record measurement notes by adding a 'measurenote' column to DataFrames.\"\n def __init__(self, \n fn_lut:callable # Function that returns the lookup dictionary with `METHOD` as key and `DESCRIPTION` as value\n ):\n fc.store_attr()\n \n def __call__(self, tfm):\n lut = self.fn_lut()\n for df in tfm.dfs.values():\n if 'METHOD' in df.columns:\n df['measurementnote'] = df['METHOD'].map(lambda x: lut.get(x, 0))\n\n\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[AddMeasurementNoteCB(lut_method),\n CompareDfsAndTfmCB(dfs)])\n\ntfm()\nprint(tfm.dfs['seawater']['measurementnote'].unique()[:5])\nprint(pd.DataFrame.from_dict(tfm.compare_stats) , '\\n')\n\n[0\n 'Radiochemical method Radiocaesium separation from seawater samples.134+137Cs was adsorbed on AMP mat, dissolved with NaOH and after purification precipitated as chloroplatinate (Cs2PtCl6).Counting with low background anticoincidence beta counter.'\n 'Radiochem. meth of Sr90. Precipation with oxalate and separation of calcium, barium, radium and ytrium couting with low background anticoincidence beta counter. 1982-1994'\n 'For tritium liquid scintialtion counting, combined with electrolytic enrichment of analysed water samples, double distilled, before and after electrolysis in cells. Liquid Scintillation spectrometer LKB Wallac model 1410'\n 'Pretreatment drying (sediment, biota samples) and ashing (biota samples)or vaporization to 1000 ml (sea water samples), measured by gamma-spectrometry using HPGe detectors sediment, biota, sea water /Cs-137, Cs-134, K-40']\n seawater sediment biota\nNumber of rows in dfs 21216 39817 15827\nNumber of rows in tfm.dfs 21216 39817 15827\nNumber of dropped rows 0 0 0\nNumber of rows in tfm.dfs + Number of dropped rows 21216 39817 15827", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#add-station", + "href": "handlers/helcom.html#add-station", + "title": "HELCOM", + "section": "Add station", + "text": "Add station\nNot included in the NetCDF output.\n\nsource\n\nRemapStationIdCB\n\n RemapStationIdCB ()\n\nRemap Station ID to MARIS format.\n\n\nExported source\nclass RemapStationIdCB(Callback):\n \"Remap Station ID to MARIS format.\"\n def __init__(self):\n fc.store_attr()\n\n def __call__(self, tfm:Transformer):\n \"Iterate through all DataFrames in the transformer object and remap `STATION` to `station_id`.\"\n for grp in tfm.dfs.keys(): \n tfm.dfs[grp]['station'] = tfm.dfs[grp]['STATION']\n\n\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[\n RemapStationIdCB(),\n CompareDfsAndTfmCB(dfs)\n ])\ntfm()\nprint(pd.DataFrame.from_dict(tfm.compare_stats) , '\\n')\n\n seawater sediment biota\nNumber of rows in dfs 21216 39817 15827\nNumber of rows in tfm.dfs 21216 39817 15827\nNumber of dropped rows 0 0 0\nNumber of rows in tfm.dfs + Number of dropped rows 21216 39817 15827", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#add-slice-position-top-and-bottom", + "href": "handlers/helcom.html#add-slice-position-top-and-bottom", + "title": "HELCOM", + "section": "Add slice position (top and bottom)", + "text": "Add slice position (top and bottom)\nNot included in the NetCDF output.\n\nsource\n\nRemapSedSliceTopBottomCB\n\n RemapSedSliceTopBottomCB ()\n\nRemap Sediment slice top and bottom to MARIS format.\n\n\nExported source\nclass RemapSedSliceTopBottomCB(Callback):\n \"Remap Sediment slice top and bottom to MARIS format.\"\n def __call__(self, tfm:Transformer):\n \"Iterate through all DataFrames in the transformer object and remap sediment slice top and bottom.\"\n tfm.dfs['sediment']['top'] = tfm.dfs['sediment']['UPPSLI']\n tfm.dfs['sediment']['bottom'] = tfm.dfs['sediment']['LOWSLI']\n\n\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[RemapSedSliceTopBottomCB()])\ntfm()\nprint(tfm.dfs['sediment'][['top','bottom']].head())\n\n top bottom\n0 15.0 20.0\n1 20.0 27.0\n2 0.0 2.0\n3 2.0 4.0\n4 4.0 6.0", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#add-dry-to-wet-ratio", + "href": "handlers/helcom.html#add-dry-to-wet-ratio", + "title": "HELCOM", + "section": "Add dry to wet ratio", + "text": "Add dry to wet ratio\nDW% is not included in the NetCDF output currently.\nHELCOM Description:\nSediment: 1. DW%: DRY WEIGHT AS PERCENTAGE (%) OF FRESH WEIGHT. 2. VALUE_Bq/kg: Measured radioactivity concentration in Bq/kg dry wt. in scientific format(e.g. 123 = 1.23E+02, 0.076 = 7.6E-02)\nBiota: 1. WEIGHT: Average weight (in g) of specimen in the sample 2. DW%: DRY WEIGHT AS PERCENTAGE (%) OF FRESH WEIGHT\n\nsource\n\nLookupDryWetRatio\n\n LookupDryWetRatio ()\n\nLookup dry-wet ratio and format for MARIS.\n\n\nExported source\nclass LookupDryWetRatio(Callback):\n \"Lookup dry-wet ratio and format for MARIS.\"\n def __call__(self, tfm:Transformer):\n \"Iterate through all DataFrames in the transformer object and apply the dry-wet ratio lookup.\"\n for grp in tfm.dfs.keys():\n if 'DW%' in tfm.dfs[grp].columns:\n self._apply_dry_wet_ratio(tfm.dfs[grp])\n\n def _apply_dry_wet_ratio(self, df: pd.DataFrame):\n \"Apply dry-wet ratio conversion and formatting to the given DataFrame.\"\n df['dry_wet_ratio'] = df['DW%']\n # Convert 'DW%' = 0% to NaN.\n df.loc[df['dry_wet_ratio'] == 0, 'dry_wet_ratio'] = np.NaN\n\n\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[\n LookupDryWetRatio(),\n CompareDfsAndTfmCB(dfs)\n ])\n\ntfm()\nprint(pd.DataFrame.from_dict(tfm.compare_stats) , '\\n')\nprint(tfm.dfs['biota']['dry_wet_ratio'].head())\n\n seawater sediment biota\nNumber of rows in dfs 21216 39817 15827\nNumber of rows in tfm.dfs 21216 39817 15827\nNumber of dropped rows 0 0 0\nNumber of rows in tfm.dfs + Number of dropped rows 21216 39817 15827 \n\n0 18.453\n1 18.453\n2 18.453\n3 18.453\n4 18.458\nName: dry_wet_ratio, dtype: float64", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#standardize-coordinates", + "href": "handlers/helcom.html#standardize-coordinates", + "title": "HELCOM", + "section": "Standardize Coordinates", + "text": "Standardize Coordinates\n\nParsing\nUse decimal degree coordinates if available; otherwise, convert from degree-minute format to decimal degrees.\n\nsource\n\n\nddmmmm2dddddd\n\n ddmmmm2dddddd (ddmmmm:float)\n\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nddmmmm\nfloat\nCoordinates in ddmmmm format where dd are degrees and mmmm`` are minutes | | **Returns** | **float** | **Coordinates indddddd`` format**\n\n\n\n\n\nExported source\ncoi_coordinates = {\n 'seawater': {\n 'lon_d': 'LONGITUDE (dddddd)',\n 'lat_d': 'LATITUDE (dddddd)',\n 'lon_m': 'LONGITUDE (ddmmmm)',\n 'lat_m': 'LATITUDE (ddmmmm)'\n },\n 'biota': {\n 'lon_d': 'LONGITUDE dddddd',\n 'lat_d': 'LATITUDE dddddd',\n 'lon_m': 'LONGITUDE ddmmmm',\n 'lat_m': 'LATITUDE ddmmmm'\n },\n 'sediment': {\n 'lon_d': 'LONGITUDE (dddddd)',\n 'lat_d': 'LATITUDE (dddddd)',\n 'lon_m': 'LONGITUDE (ddmmmm)',\n 'lat_m': 'LATITUDE (ddmmmm)'\n }\n}\n\n\n\n\nExported source\ndef ddmmmm2dddddd(\n ddmmmm:float # Coordinates in `ddmmmm` format where `dd` are degrees and `mmmm`` are minutes\n ) -> float: # Coordinates in `dddddd`` format\n # Split into degrees and minutes\n mins, degs = modf(ddmmmm)\n # Convert minutes to decimal\n mins = mins * 100\n # Convert to 'dddddd' format\n return round(int(degs) + (mins / 60), 6)\n\n\n\nsource\n\n\nFormatCoordinates\n\n FormatCoordinates (coi:dict, fn_convert_cor:Callable)\n\nFormat coordinates for MARIS. Converts coordinates from ‘ddmmmm’ to ‘dddddd’ format if needed.\n\n\n\n\nType\nDetails\n\n\n\n\ncoi\ndict\nColumn names mapping for coordinates\n\n\nfn_convert_cor\nCallable\nFunction to convert coordinates\n\n\n\n\n\nExported source\nclass FormatCoordinates(Callback):\n \"Format coordinates for MARIS. Converts coordinates from 'ddmmmm' to 'dddddd' format if needed.\"\n def __init__(self, \n coi:dict, # Column names mapping for coordinates\n fn_convert_cor:Callable # Function to convert coordinates\n ):\n fc.store_attr()\n\n def __call__(self, tfm:Transformer):\n \"Apply formatting to coordinates in the DataFrame.\"\n for grp in tfm.dfs.keys():\n self._format_coordinates(tfm.dfs[grp], grp)\n\n def _format_coordinates(self, \n df:pd.DataFrame, # DataFrame to modify\n grp: str # Group name to determine column names\n ):\n \"Format coordinates in the DataFrame for a specific group.\"\n lon_col_d = self.coi[grp]['lon_d']\n lat_col_d = self.coi[grp]['lat_d']\n lon_col_m = self.coi[grp]['lon_m']\n lat_col_m = self.coi[grp]['lat_m']\n \n # Define condition where 'dddddd' format is not available or is zero\n condition = (\n (df[lon_col_d].isna() | (df[lon_col_d] == 0)) |\n (df[lat_col_d].isna() | (df[lat_col_d] == 0))\n )\n \n # Apply conversion function only to non-null and non-zero values\n df['lon'] = np.where(\n condition,\n df[lon_col_m].apply(lambda x: self._safe_convert(x)),\n df[lon_col_d]\n )\n \n df['lat'] = np.where(\n condition,\n df[lat_col_m].apply(lambda x: self._safe_convert(x)),\n df[lat_col_d]\n )\n \n # Drop rows where coordinate columns contain NaN values\n df.dropna(subset=['lat', 'lon'], inplace=True)\n\n def _safe_convert(self, \n value:float # Coordinate value to convert\n ):\n \"Convert coordinate value safely, handling NaN values.\"\n if pd.isna(value):\n return value # Return NaN if value is NaN\n try:\n return self.fn_convert_cor(value)\n except Exception as e:\n print(f\"Error converting value {value}: {e}\")\n return value # Return original value if an error occurs\n\n\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[ \n FormatCoordinates(coi_coordinates, ddmmmm2dddddd),\n CompareDfsAndTfmCB(dfs)\n ])\ntfm()\nprint(pd.DataFrame.from_dict(tfm.compare_stats) , '\\n')\nprint(tfm.dfs['biota'][['lat','lon']])\n\n seawater sediment biota\nNumber of rows in dfs 21216 39817 15827\nNumber of rows in tfm.dfs 21208 39816 15827\nNumber of dropped rows 8 1 0\nNumber of rows in tfm.dfs + Number of dropped rows 21216 39817 15827 \n\n lat lon\n0 54.283333 12.316667\n1 54.283333 12.316667\n2 54.283333 12.316667\n3 54.283333 12.316667\n4 54.283333 12.316667\n... ... ...\n15822 60.373333 18.395667\n15823 60.373333 18.395667\n15824 60.503333 18.366667\n15825 60.503333 18.366667\n15826 60.503333 18.366667\n\n[15827 rows x 2 columns]\n\n\n\n\nSanitizing\nSanitize coordinates drops a row when both longitude & latitude equal 0 or data contains unrealistic longitude & latitude values. Converts longitude & latitude , separator to . separator.”\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[\n FormatCoordinates(coi_coordinates, ddmmmm2dddddd),\n SanitizeLonLatCB(),\n CompareDfsAndTfmCB(dfs)\n ])\n\ntfm()\nprint(pd.DataFrame.from_dict(tfm.compare_stats) , '\\n')\nprint(tfm.dfs['biota'][['lat','lon']])\n\n seawater sediment biota\nNumber of rows in dfs 21216 39817 15827\nNumber of rows in tfm.dfs 21208 39816 15827\nNumber of dropped rows 8 1 0\nNumber of rows in tfm.dfs + Number of dropped rows 21216 39817 15827 \n\n lat lon\n0 54.283333 12.316667\n1 54.283333 12.316667\n2 54.283333 12.316667\n3 54.283333 12.316667\n4 54.283333 12.316667\n... ... ...\n15822 60.373333 18.395667\n15823 60.373333 18.395667\n15824 60.503333 18.366667\n15825 60.503333 18.366667\n15826 60.503333 18.366667\n\n[15827 rows x 2 columns]", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#review-all-callbacks", + "href": "handlers/helcom.html#review-all-callbacks", + "title": "HELCOM", + "section": "Review all callbacks", + "text": "Review all callbacks\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[\n AddSampleTypeIdColumnCB(),\n LowerStripNameCB(col_src='NUCLIDE'),\n RemapNuclideNameCB(lut_nuclides),\n AddNuclideIdColumnCB(col_value='NUCLIDE'),\n ParseTimeCB(),\n EncodeTimeCB(cfg()),\n SanitizeValue(coi_val), \n NormalizeUncCB(),\n RemapBiotaSpeciesCB(lut_biota),\n RemapBiotaBodyPartCB(lut_tissues),\n RemapBiogroupCB(lut_biogroup),\n RemapTaxonInformationCB(lut_taxon),\n RemapSedimentCB(lut_sediments),\n RemapUnitCB(),\n RemapDetectionLimitCB(coi_dl, lut_dl),\n RemapFiltCB(lut_filtered),\n AddSampleLabCodeCB(),\n AddMeasurementNoteCB(lut_method),\n RemapStationIdCB(),\n RemapSedSliceTopBottomCB(),\n LookupDryWetRatio(),\n FormatCoordinates(coi_coordinates, ddmmmm2dddddd),\n SanitizeLonLatCB(),\n CompareDfsAndTfmCB(dfs)\n ])\n\ntfm()\nprint(pd.DataFrame.from_dict(tfm.compare_stats) , '\\n')\n\n seawater sediment biota\nNumber of rows in dfs 21216 39817 15827\nNumber of rows in tfm.dfs 21114 39531 15798\nNumber of dropped rows 102 286 29\nNumber of rows in tfm.dfs + Number of dropped rows 21216 39817 15827 \n\n\n\nFor instance, to inspect dropped rows:\n\ntfm.dfs_dropped['seawater'].head()\n\n\n\n\n\n\n\n\nKEY\nNUCLIDE\nMETHOD\n< VALUE_Bq/m³\nVALUE_Bq/m³\nERROR%_m³\nDATE_OF_ENTRY_x\nCOUNTRY\nLABORATORY\nSEQUENCE\n...\nLONGITUDE (ddmmmm)\nLONGITUDE (dddddd)\nTDEPTH\nSDEPTH\nSALIN\nTTEMP\nFILT\nMORS_SUBBASIN\nHELCOM_SUBBASIN\nDATE_OF_ENTRY_y\n\n\n\n\n13439\nWRISO2001025\nCS137\nRISO02\nNaN\nNaN\n10.0\nNaN\n26.0\nRISO\n2001025.0\n...\n10.500\n10.833333\n22.0\n20.0\n0.00\nNaN\nN\n5.0\n5.0\nNaN\n\n\n14017\nWLEPA2002001\nCS134\nLEPA02\n<\nNaN\nNaN\nNaN\n93.0\nLEPA\n2002001.0\n...\n21.030\n21.050000\n16.0\n0.0\n3.77\n14.40\nN\n4.0\n9.0\nNaN\n\n\n14020\nWLEPA2002002\nCS134\nLEPA02\n<\nNaN\nNaN\nNaN\n93.0\nLEPA\n2002004.0\n...\n20.574\n20.956667\n14.0\n0.0\n6.57\n11.95\nN\n4.0\n9.0\nNaN\n\n\n14023\nWLEPA2002003\nCS134\nLEPA02\n<\nNaN\nNaN\nNaN\n93.0\nLEPA\n2002007.0\n...\n19.236\n19.393333\n73.0\n0.0\n7.00\n9.19\nN\n4.0\n9.0\nNaN\n\n\n14026\nWLEPA2002004\nCS134\nLEPA02\n<\nNaN\nNaN\nNaN\n93.0\nLEPA\n2002010.0\n...\n20.205\n20.341700\n47.0\n0.0\n7.06\n8.65\nN\n4.0\n9.0\nNaN\n\n\n\n\n5 rows × 27 columns", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#rename-columns-of-interest-for-netcdf-or-open-refine", + "href": "handlers/helcom.html#rename-columns-of-interest-for-netcdf-or-open-refine", + "title": "HELCOM", + "section": "Rename columns of interest for NetCDF or Open Refine", + "text": "Rename columns of interest for NetCDF or Open Refine\n\nColumn names are standardized to MARIS NetCDF format (i.e. PEP8 ).\n\n\nsource\n\nget_renaming_rules\n\n get_renaming_rules (encoding_type='netcdf')\n\nDefine columns of interest (keys) and renaming rules (values).\n\n\nExported source\n# TO BE REFACTORED\ndef get_renaming_rules(encoding_type='netcdf'):\n \"Define columns of interest (keys) and renaming rules (values).\"\n vars = cdl_cfg()['vars']\n if encoding_type == 'netcdf':\n return OrderedDict({\n ('seawater', 'biota', 'sediment'): {\n # DEFAULT\n 'lat': vars['defaults']['lat']['name'],\n 'lon': vars['defaults']['lon']['name'],\n 'time': vars['defaults']['time']['name'],\n 'NUCLIDE': 'nuclide',\n 'detection_limit': vars['suffixes']['detection_limit']['name'],\n 'unit': vars['suffixes']['unit']['name'],\n 'value': 'value',\n 'uncertainty': vars['suffixes']['uncertainty']['name'],\n 'counting_method': vars['suffixes']['counting_method']['name'],\n 'sampling_method': vars['suffixes']['sampling_method']['name'],\n 'preparation_method': vars['suffixes']['preparation_method']['name']\n },\n ('seawater',): {\n # SEAWATER\n 'SALIN': vars['suffixes']['salinity']['name'],\n 'SDEPTH': vars['defaults']['smp_depth']['name'],\n #'FILT': vars['suffixes']['filtered']['name'], Need to fix\n 'TTEMP': vars['suffixes']['temperature']['name'],\n 'TDEPTH': vars['defaults']['tot_depth']['name'],\n\n },\n ('biota',): {\n # BIOTA\n 'SDEPTH': vars['defaults']['smp_depth']['name'],\n 'species': vars['bio']['species']['name'],\n 'body_part': vars['bio']['body_part']['name'],\n 'bio_group': vars['bio']['bio_group']['name']\n },\n ('sediment',): {\n # SEDIMENT\n 'sed_type': vars['sed']['sed_type']['name'],\n 'TDEPTH': vars['defaults']['tot_depth']['name'],\n }\n })\n \n elif encoding_type == 'openrefine':\n return OrderedDict({\n ('seawater', 'biota', 'sediment'): {\n # DEFAULT\n 'samptype_id': 'samptype_id',\n 'lat': 'latitude',\n 'lon': 'longitude',\n 'station': 'station',\n 'begperiod': 'begperiod',\n 'samplabcode': 'samplabcode',\n #'endperiod': 'endperiod',\n 'nuclide_id': 'nuclide_id',\n 'detection_limit': 'detection',\n 'unit': 'unit_id',\n 'value': 'activity',\n 'uncertainty': 'uncertaint',\n #'vartype': 'vartype',\n #'rangelow': 'rangelow',\n #'rangeupp': 'rangeupp',\n #'rl_detection': 'rl_detection',\n #'ru_detection': 'ru_detection',\n #'freq': 'freq',\n 'SDEPTH': 'sampdepth',\n #'samparea': 'samparea',\n 'SALIN': 'salinity',\n 'TTEMP': 'temperatur',\n 'FILT': 'filtered',\n #'oxygen': 'oxygen',\n #'sampquality': 'sampquality',\n #'station': 'station',\n #'samplabcode': 'samplabcode',\n #'profile': 'profile',\n #'transect': 'transect',\n #'IODE_QualityFlag': 'IODE_QualityFlag',\n 'TDEPTH': 'totdepth',\n #'counmet_id': 'counting_method',\n #'sampmet_id': 'sampling_method',\n #'prepmet_id': 'preparation_method',\n 'sampnote': 'sampnote',\n 'measurenote': 'measurenote'\n },\n ('seawater',) : {\n # SEAWATER\n #'volume': 'volume',\n #'filtpore': 'filtpore',\n #'acid': 'acid'\n },\n ('biota',) : {\n # BIOTA\n 'species': 'species_id',\n 'Taxonname': 'Taxonname',\n 'TaxonRepName': 'TaxonRepName',\n #'Commonname': 'Commonname',\n 'Taxonrank': 'Taxonrank',\n 'TaxonDB': 'TaxonDB',\n 'TaxonDBID': 'TaxonDBID',\n 'TaxonDBURL': 'TaxonDBURL',\n 'body_part': 'bodypar_id',\n #'drywt': 'drywt',\n #'wetwt': 'wetwt',\n 'dry_wet_ratio': 'percentwt',\n #'drymet_id': 'drymet_id'\n },\n ('sediment',): {\n # SEDIMENT\n 'sed_type': 'sedtype_id',\n #'sedtrap': 'sedtrap',\n 'top': 'sliceup',\n 'bottom': 'slicedown',\n 'SedRepName': 'SedRepName',\n #'drywt': 'drywt',\n #'wetwt': 'wetwt',\n 'dry_wet_ratio': 'percentwt',\n #'drymet_id': 'drymet_id'\n \n }\n })\n else:\n print(\"Invalid encoding_type provided. Please use 'netcdf' or 'openrefine'.\")\n return None\n\n\n\nsource\n\n\nSelectAndRenameColumnCB\n\n SelectAndRenameColumnCB (fn_renaming_rules:Callable,\n encoding_type:str='netcdf', verbose:bool=False)\n\nSelect and rename columns in a DataFrame based on renaming rules for a specified encoding type.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nfn_renaming_rules\nCallable\n\nA function that returns an OrderedDict of renaming rules\n\n\nencoding_type\nstr\nnetcdf\nThe encoding type (netcdf or openrefine) to determine which renaming rules to use\n\n\nverbose\nbool\nFalse\nWhether to print out renaming rules that were not applied\n\n\n\n\n\nExported source\nclass SelectAndRenameColumnCB(Callback):\n \"Select and rename columns in a DataFrame based on renaming rules for a specified encoding type.\"\n def __init__(self, \n fn_renaming_rules:Callable, # A function that returns an OrderedDict of renaming rules \n encoding_type:str='netcdf', # The encoding type (`netcdf` or `openrefine`) to determine which renaming rules to use\n verbose:bool=False # Whether to print out renaming rules that were not applied\n ):\n fc.store_attr()\n\n def __call__(self, tfm:Transformer):\n \"Apply column selection and renaming to DataFrames in the transformer, and identify unused rules.\"\n try:\n renaming_rules = self.fn_renaming_rules(self.encoding_type)\n except ValueError as e:\n print(f\"Error fetching renaming rules: {e}\")\n return\n\n for group in tfm.dfs.keys():\n # Get relevant renaming rules for the current group\n group_rules = self._get_group_rules(renaming_rules, group)\n\n if not group_rules:\n continue\n\n # Apply renaming rules and track keys not found in the DataFrame\n df = tfm.dfs[group]\n df, not_found_keys = self._apply_renaming(df, group_rules)\n tfm.dfs[group] = df\n \n # Print any renaming rules that were not used\n if not_found_keys and self.verbose:\n print(f\"\\nGroup '{group}' has the following renaming rules not applied:\")\n for old_col in not_found_keys:\n print(f\"Key '{old_col}' from renaming rules was not found in the DataFrame.\")\n\n def _get_group_rules(self, \n renaming_rules:OrderedDict, # Renaming rules\n group:str # Group name to filter rules\n ) -> OrderedDict: # Renaming rules applicable to the specified group\n \"Retrieve and merge renaming rules for the specified group based on the encoding type.\"\n relevant_rules = [rules for key, rules in renaming_rules.items() if group in key]\n merged_rules = OrderedDict()\n for rules in relevant_rules:\n merged_rules.update(rules)\n return merged_rules\n\n def _apply_renaming(self, \n df:pd.DataFrame, # DataFrame to modify\n rename_rules:OrderedDict # Renaming rules\n ) -> tuple: # (Renamed and filtered df, Column names from renaming rules that were not found in the DataFrame)\n \"\"\"\n Select columns based on renaming rules and apply renaming, only for existing columns\n while maintaining the order of the dictionary columns.\"\"\"\n existing_columns = set(df.columns)\n valid_rules = OrderedDict((old_col, new_col) for old_col, new_col in rename_rules.items() if old_col in existing_columns)\n\n # Create a list to maintain the order of columns\n columns_to_keep = [col for col in rename_rules.keys() if col in existing_columns]\n columns_to_keep += [new_col for old_col, new_col in valid_rules.items() if new_col in df.columns]\n\n df = df[list(OrderedDict.fromkeys(columns_to_keep))]\n\n # Apply renaming\n df.rename(columns=valid_rules, inplace=True)\n\n # Determine which keys were not found\n not_found_keys = set(rename_rules.keys()) - existing_columns\n return df, not_found_keys\n\n\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[AddSampleTypeIdColumnCB(),\n LowerStripNameCB(col_src='NUCLIDE'),\n RemapNuclideNameCB(lut_nuclides),\n AddNuclideIdColumnCB(col_value='NUCLIDE'),\n ParseTimeCB(),\n EncodeTimeCB(cfg()),\n SanitizeValue(coi_val), \n NormalizeUncCB(),\n RemapBiotaSpeciesCB(lut_biota),\n RemapBiotaBodyPartCB(lut_tissues),\n RemapBiogroupCB(lut_biogroup),\n RemapTaxonInformationCB(lut_taxon),\n RemapSedimentCB(lut_sediments),\n RemapUnitCB(),\n RemapDetectionLimitCB(coi_dl, lut_dl),\n RemapFiltCB(lut_filtered),\n AddSampleLabCodeCB(),\n AddMeasurementNoteCB(lut_method),\n RemapStationIdCB(),\n RemapSedSliceTopBottomCB(),\n LookupDryWetRatio(),\n FormatCoordinates(coi_coordinates, ddmmmm2dddddd),\n SanitizeLonLatCB(),\n CompareDfsAndTfmCB(dfs),\n SelectAndRenameColumnCB(get_renaming_rules, encoding_type='netcdf'),\n ])\n\ntfm()\nfor grp in tfm.dfs.keys():\n print(f'{grp} columns:')\n print(tfm.dfs[grp].columns)\n\nseawater columns:\nIndex(['lat', 'lon', 'time', 'nuclide', '_dl', '_unit', 'value', '_unc',\n '_sal', 'smp_depth', '_temp', 'tot_depth'],\n dtype='object')\nsediment columns:\nIndex(['lat', 'lon', 'time', 'nuclide', '_dl', '_unit', 'value', '_unc',\n 'sed_type', 'tot_depth'],\n dtype='object')\nbiota columns:\nIndex(['lat', 'lon', 'time', 'nuclide', '_dl', '_unit', 'value', '_unc',\n 'smp_depth', 'species', 'body_part', 'bio_group'],\n dtype='object')", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#reshape-long-to-wide", + "href": "handlers/helcom.html#reshape-long-to-wide", + "title": "HELCOM", + "section": "Reshape: long to wide", + "text": "Reshape: long to wide\nConvert data from long to wide and rename columns to comply with NetCDF format.\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[AddSampleTypeIdColumnCB(),\n LowerStripNameCB(col_src='NUCLIDE'),\n RemapNuclideNameCB(lut_nuclides),\n AddNuclideIdColumnCB(col_value='NUCLIDE'),\n ParseTimeCB(),\n EncodeTimeCB(cfg()),\n SanitizeValue(coi_val), \n NormalizeUncCB(),\n RemapBiotaSpeciesCB(lut_biota),\n RemapBiotaBodyPartCB(lut_tissues),\n RemapBiogroupCB(lut_biogroup),\n RemapTaxonInformationCB(lut_taxon),\n RemapSedimentCB(lut_sediments),\n RemapUnitCB(),\n RemapDetectionLimitCB(coi_dl, lut_dl),\n RemapFiltCB(lut_filtered),\n AddSampleLabCodeCB(),\n AddMeasurementNoteCB(lut_method),\n RemapStationIdCB(),\n RemapSedSliceTopBottomCB(),\n LookupDryWetRatio(),\n FormatCoordinates(coi_coordinates, ddmmmm2dddddd),\n SanitizeLonLatCB(),\n SelectAndRenameColumnCB(get_renaming_rules, encoding_type='netcdf'),\n ReshapeLongToWide()\n ])\n\ntfm()\nfor grp in tfm.dfs.keys():\n print(f'{grp} columns:')\n print(tfm.dfs[grp].columns)\n\nseawater columns:\nIndex(['lon', 'lat', 'tot_depth', 'time', 'smp_depth', 'ag110m_dl', 'am241_dl',\n 'ba140_dl', 'ce144_dl', 'cm242_dl',\n ...\n 'pu240', 'ru103', 'ru106', 'sb125', 'sr89', 'sr90', 'tc99', 'u234',\n 'u238', 'zr95'],\n dtype='object', length=175)\nsediment columns:\nIndex(['sed_type', 'lon', 'lat', 'tot_depth', 'time', 'ac228_dl', 'ag110m_dl',\n 'am241_dl', 'ba140_dl', 'be7_dl',\n ...\n 'sb124', 'sb125', 'sr90', 'th228', 'th232', 'th234', 'tl208', 'u235',\n 'zn65', 'zr95'],\n dtype='object', length=177)\nbiota columns:\nIndex(['body_part', 'lon', 'bio_group', 'lat', 'species', 'time', 'smp_depth',\n 'ac228_dl', 'ag108m_dl', 'ag110m_dl',\n ...\n 'sr89', 'sr90', 'tc99', 'te129m', 'th228', 'th232', 'tl208', 'u235',\n 'zn65', 'zr95'],\n dtype='object', length=211)", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#netcdf-encoder", + "href": "handlers/helcom.html#netcdf-encoder", + "title": "HELCOM", + "section": "NetCDF encoder", + "text": "NetCDF encoder\n\nExample change logs\n\ndfs = load_data(fname_in)\n\ntfm = Transformer(dfs, cbs=[AddSampleTypeIdColumnCB(),\n LowerStripNameCB(col_src='NUCLIDE'),\n RemapNuclideNameCB(lut_nuclides),\n AddNuclideIdColumnCB(col_value='NUCLIDE'),\n ParseTimeCB(),\n EncodeTimeCB(cfg()),\n SanitizeValue(coi_val), \n NormalizeUncCB(),\n RemapBiotaSpeciesCB(lut_biota),\n RemapBiotaBodyPartCB(lut_tissues),\n RemapBiogroupCB(lut_biogroup),\n RemapTaxonInformationCB(lut_taxon),\n RemapSedimentCB(lut_sediments),\n RemapUnitCB(),\n RemapDetectionLimitCB(coi_dl, lut_dl),\n RemapFiltCB(lut_filtered),\n AddSampleLabCodeCB(),\n AddMeasurementNoteCB(lut_method),\n RemapStationIdCB(),\n RemapSedSliceTopBottomCB(),\n LookupDryWetRatio(),\n FormatCoordinates(coi_coordinates, ddmmmm2dddddd),\n SanitizeLonLatCB(),\n SelectAndRenameColumnCB(get_renaming_rules, encoding_type='netcdf'),\n ReshapeLongToWide()\n ])\n\ntfm()\ntfm.logs\n\n[\"Convert values from 'NUCLIDE' to lowercase, strip spaces, and store in 'None'.\",\n 'Encode time as `int` representing seconds since xxx',\n 'Remap `KEY` column to `samplabcode` in each DataFrame.',\n 'Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator.']\n\n\n\n\nFeed global attributes\n\nsource\n\n\nget_attrs\n\n get_attrs (tfm, zotero_key, kw=['oceanography', 'Earth Science > Oceans >\n Ocean Chemistry> Radionuclides', 'Earth Science > Human\n Dimensions > Environmental Impacts > Nuclear Radiation\n Exposure', 'Earth Science > Oceans > Ocean Chemistry > Ocean\n Tracers, Earth Science > Oceans > Marine Sediments', 'Earth\n Science > Oceans > Ocean Chemistry, Earth Science > Oceans >\n Sea Ice > Isotopes', 'Earth Science > Oceans > Water Quality >\n Ocean Contaminants', 'Earth Science > Biological\n Classification > Animals/Vertebrates > Fish', 'Earth Science >\n Biosphere > Ecosystems > Marine Ecosystems', 'Earth Science >\n Biological Classification > Animals/Invertebrates > Mollusks',\n 'Earth Science > Biological Classification >\n Animals/Invertebrates > Arthropods > Crustaceans', 'Earth\n Science > Biological Classification > Plants > Macroalgae\n (Seaweeds)'])\n\nRetrieve all global attributes.\n\n\nExported source\ndef get_attrs(tfm, zotero_key, kw=kw):\n \"Retrieve all global attributes.\"\n return GlobAttrsFeeder(tfm.dfs, cbs=[\n BboxCB(),\n DepthRangeCB(),\n TimeRangeCB(cfg()),\n ZoteroCB(zotero_key, cfg=cfg()),\n KeyValuePairCB('keywords', ', '.join(kw)),\n KeyValuePairCB('publisher_postprocess_logs', ', '.join(tfm.logs))\n ])()\n\n\n\nget_attrs(tfm, zotero_key=zotero_key, kw=kw)\n\n{'geospatial_lat_min': '31.17',\n 'geospatial_lat_max': '65.75',\n 'geospatial_lon_min': '9.6333',\n 'geospatial_lon_max': '53.5',\n 'geospatial_bounds': 'POLYGON ((9.6333 53.5, 31.17 53.5, 31.17 65.75, 9.6333 65.75, 9.6333 53.5))',\n 'time_coverage_start': '1984-01-10T00:00:00',\n 'time_coverage_end': '2021-12-15T00:00:00',\n 'title': 'Environmental database - Helsinki Commission Monitoring of Radioactive Substances',\n 'summary': 'MORS Environment database has been used to collate data resulting from monitoring of environmental radioactivity in the Baltic Sea based on HELCOM Recommendation 26/3.\\n\\nThe database is structured according to HELCOM Guidelines on Monitoring of Radioactive Substances (https://www.helcom.fi/wp-content/uploads/2019/08/Guidelines-for-Monitoring-of-Radioactive-Substances.pdf), which specifies reporting format, database structure, data types and obligatory parameters used for reporting data under Recommendation 26/3.\\n\\nThe database is updated and quality assured annually by HELCOM MORS EG.',\n 'creator_name': '[{\"creatorType\": \"author\", \"name\": \"HELCOM MORS\"}]',\n 'keywords': 'oceanography, Earth Science > Oceans > Ocean Chemistry> Radionuclides, Earth Science > Human Dimensions > Environmental Impacts > Nuclear Radiation Exposure, Earth Science > Oceans > Ocean Chemistry > Ocean Tracers, Earth Science > Oceans > Marine Sediments, Earth Science > Oceans > Ocean Chemistry, Earth Science > Oceans > Sea Ice > Isotopes, Earth Science > Oceans > Water Quality > Ocean Contaminants, Earth Science > Biological Classification > Animals/Vertebrates > Fish, Earth Science > Biosphere > Ecosystems > Marine Ecosystems, Earth Science > Biological Classification > Animals/Invertebrates > Mollusks, Earth Science > Biological Classification > Animals/Invertebrates > Arthropods > Crustaceans, Earth Science > Biological Classification > Plants > Macroalgae (Seaweeds)',\n 'publisher_postprocess_logs': \"Convert values from 'NUCLIDE' to lowercase, strip spaces, and store in 'None'., Encode time as `int` representing seconds since xxx, Remap `KEY` column to `samplabcode` in each DataFrame., Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator.\"}\n\n\n\nsource\n\n\nenums_xtra\n\n enums_xtra (tfm, vars)\n\nRetrieve a subset of the lengthy enum as species_t for instance.\n\n\nExported source\ndef enums_xtra(tfm, vars):\n \"Retrieve a subset of the lengthy enum as `species_t` for instance.\"\n enums = Enums(lut_src_dir=lut_path(), cdl_enums=cdl_cfg()['enums'])\n xtras = {}\n for var in vars:\n unique_vals = tfm.unique(var)\n if unique_vals.any():\n xtras[f'{var}_t'] = enums.filter(f'{var}_t', unique_vals)\n return xtras\n\n\n\n\nEncoding NetCDF\n\nsource\n\n\nencode\n\n encode (fname_in, fname_out_nc, nc_tpl_path, **kwargs)\n\n\n\nExported source\ndef encode(fname_in, fname_out_nc, nc_tpl_path, **kwargs):\n dfs = load_data(fname_in)\n tfm = Transformer(dfs, cbs=[AddSampleTypeIdColumnCB(),\n LowerStripNameCB(col_src='NUCLIDE'),\n RemapNuclideNameCB(lut_nuclides),\n AddNuclideIdColumnCB(col_value='NUCLIDE'),\n ParseTimeCB(),\n EncodeTimeCB(cfg()),\n SanitizeValue(coi_val), \n NormalizeUncCB(),\n RemapBiotaSpeciesCB(lut_biota),\n RemapBiotaBodyPartCB(lut_tissues),\n RemapBiogroupCB(lut_biogroup),\n RemapTaxonInformationCB(lut_taxon),\n RemapSedimentCB(lut_sediments),\n RemapUnitCB(),\n RemapDetectionLimitCB(coi_dl, lut_dl),\n RemapFiltCB(lut_filtered),\n AddSampleLabCodeCB(),\n AddMeasurementNoteCB(lut_method),\n RemapStationIdCB(),\n RemapSedSliceTopBottomCB(),\n LookupDryWetRatio(),\n FormatCoordinates(coi_coordinates, ddmmmm2dddddd),\n SanitizeLonLatCB(),\n SelectAndRenameColumnCB(get_renaming_rules, encoding_type='netcdf'),\n ReshapeLongToWide()\n ])\n tfm()\n encoder = NetCDFEncoder(tfm.dfs, \n src_fname=nc_tpl_path,\n dest_fname=fname_out_nc, \n global_attrs=get_attrs(tfm, zotero_key=zotero_key, kw=kw),\n verbose=kwargs.get('verbose', False),\n enums_xtra=enums_xtra(tfm, vars=['species', 'body_part'])\n )\n encoder.encode()\n\n\n\nencode(fname_in, fname_out_nc, nc_tpl_path(), verbose=False)", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#open-refine-pipeline-wip", + "href": "handlers/helcom.html#open-refine-pipeline-wip", + "title": "HELCOM", + "section": "Open Refine Pipeline (WIP)", + "text": "Open Refine Pipeline (WIP)\n\nRename columns for Open Refine\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[\n AddSampleTypeIdColumnCB(),\n LowerStripRdnNameCB(col_src='NUCLIDE'),\n RemapRdnNameCB(),\n ParseTimeCB(),\n EncodeTimeCB(cfg()), \n SanitizeValue(coi_val), \n NormalizeUncCB(),\n LookupBiotaSpeciesCB(get_maris_species),\n LookupBiotaBodyPartCB(get_maris_bodypart), \n LookupBiogroupCB(partial(get_biogroup_lut, species_lut_path())),\n LookupTaxonInformationCB(partial(get_taxon_info_lut, species_lut_path())),\n LookupSedimentCB(get_maris_sediments),\n LookupUnitCB(),\n LookupDetectionLimitCB(), \n RemapDataProviderSampleIdCB(),\n RecordMeasurementNoteCB(get_helcom_method_desc),\n LookupFiltCB(),\n RemapStationIdCB(),\n RemapSedSliceTopBottomCB(),\n LookupDryWetRatio(),\n FormatCoordinates(coi_coordinates, ddmmmm2dddddd),\n SanitizeLonLatCB(),\n SelectAndRenameColumnCB(get_renaming_rules, encoding_type='openrefine', verbose=True),\n CompareDfsAndTfmCB(dfs)\n ])\n\ntfm()\nprint(pd.DataFrame.from_dict(tfm.compare_stats) , '\\n')\n\n\nGroup 'seawater' has the following renaming rules not applied:\nKey 'sampnote' from renaming rules was not found in the DataFrame.\n\nGroup 'sediment' has the following renaming rules not applied:\nKey 'FILT' from renaming rules was not found in the DataFrame.\nKey 'TTEMP' from renaming rules was not found in the DataFrame.\nKey 'SDEPTH' from renaming rules was not found in the DataFrame.\nKey 'SALIN' from renaming rules was not found in the DataFrame.\nKey 'sampnote' from renaming rules was not found in the DataFrame.\n\nGroup 'biota' has the following renaming rules not applied:\nKey 'TDEPTH' from renaming rules was not found in the DataFrame.\nKey 'FILT' from renaming rules was not found in the DataFrame.\nKey 'TTEMP' from renaming rules was not found in the DataFrame.\nKey 'SALIN' from renaming rules was not found in the DataFrame.\nKey 'sampnote' from renaming rules was not found in the DataFrame.\n seawater sediment biota\nNumber of rows in dfs 21216 39817 15827\nNumber of rows in tfm.dfs 21114 39531 15798\nNumber of dropped rows 102 286 29\nNumber of rows in tfm.dfs + Number of dropped rows 21216 39817 15827 \n\n\n\nExample of data included in dfs_dropped.\nMain reasons for data to be dropped from dfs: - No activity value reported (e.g. VALUE_Bq/kg) - No time value reported.\n\ngrp='sediment'\n#grp='seawater'\n#grp='biota'\n\ntfm.dfs_dropped[grp]\n\n\n\n\n\n\n\n\nKEY\nNUCLIDE\nMETHOD\n< VALUE_Bq/kg\nVALUE_Bq/kg\nERROR%_kg\n< VALUE_Bq/m²\nVALUE_Bq/m²\nERROR%_m²\nDATE_OF_ENTRY_x\n...\nLOWSLI\nAREA\nSEDI\nOXIC\nDW%\nLOI%\nMORS_SUBBASIN\nHELCOM_SUBBASIN\nSUM_LINK\nDATE_OF_ENTRY_y\n\n\n\n\n11784\nSLREB1998021\nSR90\n2\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n...\n12.0\n0.02100\n55.0\nO\nNaN\nNaN\n14.0\n14.0\na\nNaN\n\n\n11824\nSLVDC1997023\nCS137\n1\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n...\n14.0\n0.02100\n55.0\nO\nNaN\nNaN\n9.0\n9.0\na\nNaN\n\n\n11832\nSLVDC1997031\nCS137\n1\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n...\n14.0\n0.02100\n55.0\nO\nNaN\nNaN\n9.0\n9.0\na\nNaN\n\n\n11841\nSLVDC1997040\nCS137\n1\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n...\n16.0\n0.02100\n55.0\nO\nNaN\nNaN\n9.0\n9.0\na\nNaN\n\n\n11849\nSLVDC1998011\nCS137\n1\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n...\n16.0\n0.02100\n55.0\nO\nNaN\nNaN\n14.0\n14.0\na\nNaN\n\n\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n\n\n39769\nSSSSM2021030\nCO60\nSSSM43\n<\nNaN\nNaN\n<\nNaN\nNaN\n09/06/22 00:00:00\n...\n2.0\n0.01608\nNaN\nNaN\n28.200000\n15.0\n12.0\n12.0\nNaN\n09/06/22 00:00:00\n\n\n39774\nSSSSM2021030\nRA226\nSSSM43\n<\nNaN\nNaN\n<\nNaN\nNaN\n09/06/22 00:00:00\n...\n2.0\n0.01608\nNaN\nNaN\n28.200000\n15.0\n12.0\n12.0\nNaN\n09/06/22 00:00:00\n\n\n39775\nSSSSM2021030\nRA223\nSSSM43\n<\nNaN\nNaN\n<\nNaN\nNaN\n09/06/22 00:00:00\n...\n2.0\n0.01608\nNaN\nNaN\n28.200000\n15.0\n12.0\n12.0\nNaN\n09/06/22 00:00:00\n\n\n39777\nSSSSM2021031\nCS137\nSSSM43\n<\nNaN\nNaN\n<\n0.0\nNaN\n09/06/22 00:00:00\n...\n2.0\n0.01608\nNaN\nNaN\n31.993243\nNaN\n13.0\n13.0\nNaN\n09/06/22 00:00:00\n\n\n39779\nSSSSM2021031\nCO60\nSSSM43\n<\nNaN\nNaN\n<\nNaN\nNaN\n09/06/22 00:00:00\n...\n2.0\n0.01608\nNaN\nNaN\n31.993243\nNaN\n13.0\n13.0\nNaN\n09/06/22 00:00:00\n\n\n\n\n286 rows × 35 columns", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/helcom.html#open-refine-encoder-wip", + "href": "handlers/helcom.html#open-refine-encoder-wip", + "title": "HELCOM", + "section": "Open Refine encoder (WIP)", + "text": "Open Refine encoder (WIP)\n\ndef encode_or(fname_in, fname_out_csv, ref_id, **kwargs):\n dfs = load_data(fname_in)\n tfm = Transformer(dfs, cbs=[\n AddSampleTypeIdColumnCB(),\n LowerStripRdnNameCB(col_src='NUCLIDE'),\n RemapRdnNameCB(),\n ParseTimeCB(),\n EncodeTimeCB(cfg()), \n SanitizeValue(coi_val), \n NormalizeUncCB(),\n LookupBiotaSpeciesCB(get_maris_species),\n LookupBiotaBodyPartCB(get_maris_bodypart), \n LookupBiogroupCB(partial(get_biogroup_lut, species_lut_path())),\n LookupTaxonInformationCB(partial(get_taxon_info_lut, species_lut_path())),\n LookupSedimentCB(get_maris_sediments),\n LookupUnitCB(),\n LookupDetectionLimitCB(), \n RemapDataProviderSampleIdCB(),\n RecordMeasurementNoteCB(get_helcom_method_desc),\n LookupFiltCB(),\n RemapStationIdCB(),\n RemapSedSliceTopBottomCB(),\n LookupDryWetRatio(),\n FormatCoordinates(coi_coordinates, ddmmmm2dddddd),\n SanitizeLonLatCB(),\n SelectAndRenameColumnCB(get_renaming_rules, encoding_type='openrefine'),\n CompareDfsAndTfmCB(dfs)\n ])\n tfm()\n\n encoder = OpenRefineCsvEncoder(tfm.dfs, \n dest_fname=fname_out_csv, \n ref_id = ref_id,\n verbose = True\n )\n encoder.encode()\n\n\nencode_or(fname_in, fname_out_csv, ref_id, verbose=True)\n\n\nOpen Refine Variables not included in Helcom\n\n\n\nField name\nFull name\nHELCOM\n\n\n\n\nsampquality\nSample quality\nN\n\n\nlab_id\nLaboratory ID\nN\n\n\nprofile_id\nProfile ID\nN\n\n\ntransect_id\nTransect ID\nN\n\n\nendperiod\nEnd period\nN\n\n\nvartype\nVariable type\nN\n\n\nfreq\nFrequency\nN\n\n\nrl_detection\nRange low detection\nN\n\n\nrangelow\nRange low\nN\n\n\nrangeupp\nRange upper\nN\n\n\nCommonname\nCommon name\nN\n\n\nvolume\nVolume\nN\n\n\nfiltpore\nFilter pore\nN\n\n\nacid\nAcidified\nN\n\n\noxygen\nOxygen\nN\n\n\nsamparea\nSample area\nN\n\n\ndrywt\nDry weight\nN\n\n\nwetwt\nWet weight\nN\n\n\nsampmet_id\nSampling method ID\nN\n\n\ndrymet_id\nDrying method ID\nN\n\n\nprepmet_id\nPreparation method ID\nN\n\n\ncounmet_id\nCounting method ID\nN\n\n\nrefnote\nReference note\nN\n\n\nsampnote\nSample note\nN\n\n\ngfe\nGood for export\n?\n\n\n\nTODO:\n\nShould we use a single encoder for both NetCDF and OpenRefine? If so, should we have a single encode function that accepts a variable ‘encoding_type’.\n\nTODO: Include FILT for NetCDF\nTODO: Check sediment ‘DW%’ data that is less than 1%. Is this realistic? Check the ‘DW%’ data that is 0%. Run below before SelectAndRenameColumnCB.\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[LowerStripRdnNameCB(col_src='NUCLIDE'),\n ])\ntfm()\n\n{'seawater': KEY NUCLIDE METHOD < VALUE_Bq/m³ VALUE_Bq/m³ ERROR%_m³ \\\n 0 WKRIL2012003 cs137 NaN NaN 5.3 32.000000 \n 1 WKRIL2012004 cs137 NaN NaN 19.9 20.000000 \n 2 WKRIL2012005 cs137 NaN NaN 25.5 20.000000 \n 3 WKRIL2012006 cs137 NaN NaN 17.0 29.000000 \n 4 WKRIL2012007 cs137 NaN NaN 22.2 18.000000 \n ... ... ... ... ... ... ... \n 21211 WSSSM2021005 h3 SSM45 NaN 1030.0 93.203883 \n 21212 WSSSM2021006 h3 SSM45 NaN 2240.0 43.303571 \n 21213 WSSSM2021007 h3 SSM45 NaN 2060.0 47.087379 \n 21214 WSSSM2021008 h3 SSM45 NaN 2300.0 43.478261 \n 21215 WSSSM2021004 h3 SSM45 < NaN NaN \n \n DATE_OF_ENTRY_x COUNTRY LABORATORY SEQUENCE ... \\\n 0 08/20/14 00:00:00 90.0 KRIL 2012003.0 ... \n 1 08/20/14 00:00:00 90.0 KRIL 2012004.0 ... \n 2 08/20/14 00:00:00 90.0 KRIL 2012005.0 ... \n 3 08/20/14 00:00:00 90.0 KRIL 2012006.0 ... \n 4 08/20/14 00:00:00 90.0 KRIL 2012007.0 ... \n ... ... ... ... ... ... \n 21211 09/06/22 00:00:00 77.0 SSSM 202105.0 ... \n 21212 09/06/22 00:00:00 77.0 SSSM 202106.0 ... \n 21213 09/06/22 00:00:00 77.0 SSSM 202107.0 ... \n 21214 09/06/22 00:00:00 77.0 SSSM 202108.0 ... \n 21215 09/06/22 00:00:00 77.0 SSSM 202104.0 ... \n \n LONGITUDE (ddmmmm) LONGITUDE (dddddd) TDEPTH SDEPTH SALIN TTEMP \\\n 0 29.2000 29.3333 NaN 0.0 NaN NaN \n 1 29.2000 29.3333 NaN 29.0 NaN NaN \n 2 23.0900 23.1500 NaN 0.0 NaN NaN \n 3 27.5900 27.9833 NaN 0.0 NaN NaN \n 4 27.5900 27.9833 NaN 39.0 NaN NaN \n ... ... ... ... ... ... ... \n 21211 18.2143 18.3572 NaN 1.0 NaN NaN \n 21212 17.0000 17.0000 NaN 1.0 NaN NaN \n 21213 11.5671 11.9452 NaN 1.0 NaN NaN \n 21214 11.5671 11.9452 NaN 1.0 NaN NaN \n 21215 11.1470 11.2450 NaN 1.0 NaN NaN \n \n FILT MORS_SUBBASIN HELCOM_SUBBASIN DATE_OF_ENTRY_y \n 0 NaN 11.0 11.0 08/20/14 00:00:00 \n 1 NaN 11.0 11.0 08/20/14 00:00:00 \n 2 NaN 11.0 3.0 08/20/14 00:00:00 \n 3 NaN 11.0 11.0 08/20/14 00:00:00 \n 4 NaN 11.0 11.0 08/20/14 00:00:00 \n ... ... ... ... ... \n 21211 N 1.0 8.0 09/06/22 00:00:00 \n 21212 N 10.0 10.0 09/06/22 00:00:00 \n 21213 N 12.0 12.0 09/06/22 00:00:00 \n 21214 N 12.0 12.0 09/06/22 00:00:00 \n 21215 N 15.0 18.0 09/06/22 00:00:00 \n \n [21216 rows x 27 columns],\n 'sediment': KEY NUCLIDE METHOD < VALUE_Bq/kg VALUE_Bq/kg ERROR%_kg \\\n 0 SKRIL2012048 ra226 NaN NaN 35.0 26.00 \n 1 SKRIL2012049 ra226 NaN NaN 36.0 22.00 \n 2 SKRIL2012050 ra226 NaN NaN 38.0 24.00 \n 3 SKRIL2012051 ra226 NaN NaN 36.0 25.00 \n 4 SKRIL2012052 ra226 NaN NaN 30.0 23.00 \n ... ... ... ... ... ... ... \n 39812 SSSSM2020029 ac228 SSSM43 NaN 37.5 5.00 \n 39813 SSSSM2020030 k40 SSSM43 NaN 526.0 1.72 \n 39814 SSSSM2020030 cs137 SSSM43 NaN 17.2 2.21 \n 39815 SSSSM2020031 k40 SSSM43 NaN 1000.0 1.80 \n 39816 SSSSM2020031 cs137 SSSM43 NaN 64.0 1.20 \n \n < VALUE_Bq/m² VALUE_Bq/m² ERROR%_m² DATE_OF_ENTRY_x ... LOWSLI \\\n 0 NaN NaN NaN 08/20/14 00:00:00 ... 20.0 \n 1 NaN NaN NaN 08/20/14 00:00:00 ... 27.0 \n 2 NaN NaN NaN 08/20/14 00:00:00 ... 2.0 \n 3 NaN NaN NaN 08/20/14 00:00:00 ... 4.0 \n 4 NaN NaN NaN 08/20/14 00:00:00 ... 6.0 \n ... ... ... ... ... ... ... \n 39812 NaN 255.0 28.0 04/22/22 00:00:00 ... 2.0 \n 39813 NaN 5690.0 2.0 04/22/22 00:00:00 ... 2.0 \n 39814 NaN 186.0 2.0 04/22/22 00:00:00 ... 2.0 \n 39815 NaN 16000.0 2.0 04/22/22 00:00:00 ... 2.0 \n 39816 NaN 1020.0 1.0 04/22/22 00:00:00 ... 2.0 \n \n AREA SEDI OXIC DW% LOI% MORS_SUBBASIN HELCOM_SUBBASIN SUM_LINK \\\n 0 0.006 NaN NaN NaN NaN 11.0 11.0 NaN \n 1 0.006 NaN NaN NaN NaN 11.0 11.0 NaN \n 2 0.006 NaN NaN NaN NaN 11.0 11.0 NaN \n 3 0.006 NaN NaN NaN NaN 11.0 11.0 NaN \n 4 0.006 NaN NaN NaN NaN 11.0 11.0 NaN \n ... ... ... ... ... ... ... ... ... \n 39812 0.019 0.0 O 28.73 14.0 13.0 13.0 NaN \n 39813 0.019 0.0 O 32.03 NaN 12.0 12.0 NaN \n 39814 0.019 0.0 O 32.03 NaN 12.0 12.0 NaN \n 39815 0.017 0.0 O 48.77 NaN 1.0 8.0 NaN \n 39816 0.017 0.0 O 48.77 NaN 1.0 8.0 NaN \n \n DATE_OF_ENTRY_y \n 0 08/20/14 00:00:00 \n 1 08/20/14 00:00:00 \n 2 08/20/14 00:00:00 \n 3 08/20/14 00:00:00 \n 4 08/20/14 00:00:00 \n ... ... \n 39812 04/22/22 00:00:00 \n 39813 04/22/22 00:00:00 \n 39814 04/22/22 00:00:00 \n 39815 04/22/22 00:00:00 \n 39816 04/22/22 00:00:00 \n \n [39817 rows x 35 columns],\n 'biota': KEY NUCLIDE METHOD < VALUE_Bq/kg VALUE_Bq/kg BASIS ERROR% \\\n 0 BVTIG2012041 cs134 VTIG01 < 0.010140 W NaN \n 1 BVTIG2012041 k40 VTIG01 135.300000 W 3.57 \n 2 BVTIG2012041 co60 VTIG01 < 0.013980 W NaN \n 3 BVTIG2012041 cs137 VTIG01 4.338000 W 3.48 \n 4 BVTIG2012040 cs134 VTIG01 < 0.009614 W NaN \n ... ... ... ... ... ... ... ... \n 15822 BSSSM2020016 k40 SSSM42 NaN 65.000000 D 10.20 \n 15823 BSSSM2020016 cs137 SSSM42 NaN 4.500000 D 6.20 \n 15824 BSSSM2020017 be7 SSSM42 NaN 94.000000 D 3.40 \n 15825 BSSSM2020017 k40 SSSM42 NaN 1100.000000 D 1.60 \n 15826 BSSSM2020017 cs137 SSSM42 NaN 13.000000 D 2.50 \n \n NUMBER DATE_OF_ENTRY_x COUNTRY ... BIOTATYPE TISSUE NO \\\n 0 NaN 02/27/14 00:00:00 6.0 ... F 5 16.0 \n 1 NaN 02/27/14 00:00:00 6.0 ... F 5 16.0 \n 2 NaN 02/27/14 00:00:00 6.0 ... F 5 16.0 \n 3 NaN 02/27/14 00:00:00 6.0 ... F 5 16.0 \n 4 NaN 02/27/14 00:00:00 6.0 ... F 5 17.0 \n ... ... ... ... ... ... ... ... \n 15822 NaN 04/22/22 00:00:00 77.0 ... B 41 319.0 \n 15823 NaN 04/22/22 00:00:00 77.0 ... B 41 319.0 \n 15824 NaN 04/22/22 00:00:00 77.0 ... P 51 NaN \n 15825 NaN 04/22/22 00:00:00 77.0 ... P 51 NaN \n 15826 NaN 04/22/22 00:00:00 77.0 ... P 51 NaN \n \n LENGTH WEIGHT DW% LOI% MORS_SUBBASIN HELCOM_SUBBASIN \\\n 0 45.7 948.0 18.453 92.9 2.0 16 \n 1 45.7 948.0 18.453 92.9 2.0 16 \n 2 45.7 948.0 18.453 92.9 2.0 16 \n 3 45.7 948.0 18.453 92.9 2.0 16 \n 4 45.9 964.0 18.458 92.9 2.0 16 \n ... ... ... ... ... ... ... \n 15822 NaN NaN 41.000 0.0 1.0 8 \n 15823 NaN NaN 41.000 0.0 1.0 8 \n 15824 NaN NaN 21.000 0.0 1.0 8 \n 15825 NaN NaN 21.000 0.0 1.0 8 \n 15826 NaN NaN 21.000 0.0 1.0 8 \n \n DATE_OF_ENTRY_y \n 0 02/27/14 00:00:00 \n 1 02/27/14 00:00:00 \n 2 02/27/14 00:00:00 \n 3 02/27/14 00:00:00 \n 4 02/27/14 00:00:00 \n ... ... \n 15822 04/22/22 00:00:00 \n 15823 04/22/22 00:00:00 \n 15824 04/22/22 00:00:00 \n 15825 04/22/22 00:00:00 \n 15826 04/22/22 00:00:00 \n \n [15827 rows x 33 columns]}\n\n\n\ngrp='sediment'\ncheck_data_sediment=tfm.dfs[grp][(tfm.dfs[grp]['DW%'] < 1) & (tfm.dfs[grp]['DW%'] > 0.001) ]\ncheck_data_sediment\n\n\n\n\n\n\n\n\nKEY\nNUCLIDE\nMETHOD\n< VALUE_Bq/kg\nVALUE_Bq/kg\nERROR%_kg\n< VALUE_Bq/m²\nVALUE_Bq/m²\nERROR%_m²\nDATE_OF_ENTRY_x\n...\nLOWSLI\nAREA\nSEDI\nOXIC\nDW%\nLOI%\nMORS_SUBBASIN\nHELCOM_SUBBASIN\nSUM_LINK\nDATE_OF_ENTRY_y\n\n\n\n\n30938\nSLVEA2010001\ncs137\nLVEA01\nNaN\n334.25\n1.57\nNaN\n131.886\n41179.0\nNaN\n...\n2.0\n0.0151\n5.0\nO\n0.115\n0.9\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30939\nSLVEA2010002\ncs137\nLVEA01\nNaN\n343.58\n1.49\nNaN\n132.092\n41179.0\nNaN\n...\n4.0\n0.0151\n5.0\nA\n0.159\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30940\nSLVEA2010003\ncs137\nLVEA01\nNaN\n334.69\n1.56\nNaN\n134.390\n41179.0\nNaN\n...\n6.0\n0.0151\n5.0\nA\n0.189\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30941\nSLVEA2010004\ncs137\nLVEA01\nNaN\n348.50\n1.56\nNaN\n136.699\n41179.0\nNaN\n...\n8.0\n0.0151\n5.0\nA\n0.194\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30942\nSLVEA2010005\ncs137\nLVEA01\nNaN\n258.67\n1.73\nNaN\n104.894\n41179.0\nNaN\n...\n10.0\n0.0151\n5.0\nA\n0.195\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30943\nSLVEA2010006\ncs137\nLVEA01\nNaN\n182.02\n2.05\nNaN\n77.523\n41179.0\nNaN\n...\n12.0\n0.0151\n5.0\nA\n0.221\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30944\nSLVEA2010007\ncs137\nLVEA01\nNaN\n116.34\n2.79\nNaN\n46.946\n41179.0\nNaN\n...\n14.0\n0.0151\n5.0\nA\n0.238\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30945\nSLVEA2010008\ncs137\nLVEA01\nNaN\n94.07\n2.61\nNaN\n38.162\n41179.0\nNaN\n...\n16.0\n0.0151\n5.0\nA\n0.234\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30946\nSLVEA2010009\ncs137\nLVEA01\nNaN\n69.70\n3.12\nNaN\n27.444\n41179.0\nNaN\n...\n18.0\n0.0151\n5.0\nA\n0.242\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30947\nSLVEA2010010\ncs137\nLVEA01\nNaN\n59.63\n3.40\nNaN\n24.220\n41179.0\nNaN\n...\n20.0\n0.0151\n5.0\nA\n0.257\n0.7\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30948\nSLVEA2010011\ncs137\nLVEA01\n<\n12.24\n3.88\n<\n5.035\n41179.0\nNaN\n...\n22.0\n0.0151\n5.0\nA\n0.264\n0.7\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30949\nSLVEA2010012\ncs137\nLVEA01\n<\n0.83\nNaN\n<\n0.330\n41179.0\nNaN\n...\n24.0\n0.0151\n5.0\nA\n0.244\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30950\nSLVEA2010013\ncs137\nLVEA01\nNaN\n331.61\n1.40\nNaN\n125.566\n41179.0\nNaN\n...\n2.0\n0.0151\n5.0\nO\n0.115\n0.9\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30951\nSLVEA2010014\ncs137\nLVEA01\nNaN\n352.06\n1.33\nNaN\n144.516\n41179.0\nNaN\n...\n4.0\n0.0151\n5.0\nA\n0.164\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30952\nSLVEA2010015\ncs137\nLVEA01\nNaN\n367.11\n1.36\nNaN\n139.434\n41179.0\nNaN\n...\n6.0\n0.0151\n5.0\nA\n0.191\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30953\nSLVEA2010016\ncs137\nLVEA01\nNaN\n328.97\n1.42\nNaN\n124.348\n41179.0\nNaN\n...\n8.0\n0.0151\n5.0\nA\n0.188\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30954\nSLVEA2010017\ncs137\nLVEA01\nNaN\n356.30\n1.37\nNaN\n135.447\n41179.0\nNaN\n...\n10.0\n0.0151\n5.0\nA\n0.179\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30955\nSLVEA2010018\ncs137\nLVEA01\nNaN\n314.75\n1.42\nNaN\n118.765\n41179.0\nNaN\n...\n12.0\n0.0151\n5.0\nA\n0.186\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30956\nSLVEA2010019\ncs137\nLVEA01\nNaN\n261.64\n1.52\nNaN\n104.580\n41179.0\nNaN\n...\n14.0\n0.0151\n5.0\nA\n0.194\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30957\nSLVEA2010020\ncs137\nLVEA01\nNaN\n181.00\n1.76\nNaN\n74.058\n41179.0\nNaN\n...\n16.0\n0.0151\n5.0\nA\n0.209\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30958\nSLVEA2010021\ncs137\nLVEA01\nNaN\n143.65\n2.02\nNaN\n57.680\n41179.0\nNaN\n...\n18.0\n0.0151\n5.0\nA\n0.214\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30959\nSLVEA2010022\ncs137\nLVEA01\nNaN\n109.36\n2.15\nNaN\n42.153\n41179.0\nNaN\n...\n20.0\n0.0151\n5.0\nA\n0.218\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30960\nSLVEA2010023\ncs137\nLVEA01\nNaN\n94.12\n1.39\nNaN\n35.873\n41179.0\nNaN\n...\n22.0\n0.0151\n5.0\nA\n0.212\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n30961\nSLVEA2010024\ncs137\nLVEA01\nNaN\n96.63\n1.35\nNaN\n38.864\n41179.0\nNaN\n...\n24.0\n0.0151\n5.0\nA\n0.217\n0.8\n14.0\n14.0\nNaN\n11/11/11 00:00:00\n\n\n\n\n24 rows × 35 columns\n\n\n\n\ngrp='sediment'\ncheck_data_sediment=tfm.dfs[grp][(tfm.dfs[grp]['DW%'] == 0) ]\ncheck_data_sediment\n\n\n\n\n\n\n\n\nKEY\nNUCLIDE\nMETHOD\n< VALUE_Bq/kg\nVALUE_Bq/kg\nERROR%_kg\n< VALUE_Bq/m²\nVALUE_Bq/m²\nERROR%_m²\nDATE_OF_ENTRY_x\n...\nLOWSLI\nAREA\nSEDI\nOXIC\nDW%\nLOI%\nMORS_SUBBASIN\nHELCOM_SUBBASIN\nSUM_LINK\nDATE_OF_ENTRY_y\n\n\n\n\n9824\nSERPC1997001\ncs134\nNaN\nNaN\n3.80\n20.0\nNaN\n5.75\nNaN\nNaN\n...\n2.0\n0.008\n5.0\nA\n0.0\n0.0\n11.0\n11.0\na\nNaN\n\n\n9825\nSERPC1997001\ncs137\nNaN\nNaN\n389.00\n4.0\nNaN\n589.00\nNaN\nNaN\n...\n2.0\n0.008\n5.0\nA\n0.0\n0.0\n11.0\n11.0\na\nNaN\n\n\n9826\nSERPC1997002\ncs134\nNaN\nNaN\n4.78\n13.0\nNaN\n12.00\nNaN\nNaN\n...\n4.0\n0.008\n5.0\nA\n0.0\n0.0\n11.0\n11.0\na\nNaN\n\n\n9827\nSERPC1997002\ncs137\nNaN\nNaN\n420.00\n4.0\nNaN\n1060.00\nNaN\nNaN\n...\n4.0\n0.008\n5.0\nA\n0.0\n0.0\n11.0\n11.0\na\nNaN\n\n\n9828\nSERPC1997003\ncs134\nNaN\nNaN\n3.12\n17.0\nNaN\n12.00\nNaN\nNaN\n...\n6.0\n0.008\n5.0\nA\n0.0\n0.0\n11.0\n11.0\na\nNaN\n\n\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n\n\n15257\nSKRIL1999062\nth228\n1\nNaN\n68.00\nNaN\nNaN\nNaN\nNaN\nNaN\n...\n15.0\n0.006\n0.0\nO\n0.0\n0.0\n11.0\n11.0\na\nNaN\n\n\n15258\nSKRIL1999063\nk40\n1\nNaN\n1210.00\nNaN\nNaN\nNaN\nNaN\nNaN\n...\n21.5\n0.006\n0.0\nO\n0.0\n0.0\n11.0\n11.0\na\nNaN\n\n\n15259\nSKRIL1999063\nra226\nKRIL01\nNaN\n56.50\nNaN\nNaN\nNaN\nNaN\nNaN\n...\n21.5\n0.006\n0.0\nO\n0.0\n0.0\n11.0\n11.0\na\nNaN\n\n\n15260\nSKRIL1999063\nra228\nKRIL01\nNaN\n72.20\nNaN\nNaN\nNaN\nNaN\nNaN\n...\n21.5\n0.006\n0.0\nO\n0.0\n0.0\n11.0\n11.0\na\nNaN\n\n\n15261\nSKRIL1999063\nth228\n1\nNaN\n74.20\nNaN\nNaN\nNaN\nNaN\nNaN\n...\n21.5\n0.006\n0.0\nO\n0.0\n0.0\n11.0\n11.0\na\nNaN\n\n\n\n\n302 rows × 35 columns\n\n\n\n\ngrp='biota'\ncheck_data_sediment=tfm.dfs[grp][(tfm.dfs[grp]['DW%'] == 0) ]\ncheck_data_sediment\n\n\n\n\n\n\n\n\nKEY\nNUCLIDE\nMETHOD\n< VALUE_Bq/kg\nVALUE_Bq/kg\nBASIS\nERROR%\nNUMBER\nDATE_OF_ENTRY_x\nCOUNTRY\n...\nBIOTATYPE\nTISSUE\nNO\nLENGTH\nWEIGHT\nDW%\nLOI%\nMORS_SUBBASIN\nHELCOM_SUBBASIN\nDATE_OF_ENTRY_y\n\n\n\n\n5971\nBERPC1997002\nk40\nNaN\nNaN\n116.00\nW\n3.0\nNaN\nNaN\n91.0\n...\nF\n5\n0.0\n0.0\n0.0\n0.0\n0.0\n11.0\n11\nNaN\n\n\n5972\nBERPC1997002\ncs137\nNaN\nNaN\n12.60\nW\n4.0\nNaN\nNaN\n91.0\n...\nF\n5\n0.0\n0.0\n0.0\n0.0\n0.0\n11.0\n11\nNaN\n\n\n5973\nBERPC1997002\ncs134\nNaN\nNaN\n0.14\nW\n18.0\nNaN\nNaN\n91.0\n...\nF\n5\n0.0\n0.0\n0.0\n0.0\n0.0\n11.0\n11\nNaN\n\n\n5974\nBERPC1997001\nk40\nNaN\nNaN\n116.00\nW\n4.0\nNaN\nNaN\n91.0\n...\nF\n5\n0.0\n0.0\n0.0\n0.0\n0.0\n11.0\n11\nNaN\n\n\n5975\nBERPC1997001\ncs137\nNaN\nNaN\n12.00\nW\n4.0\nNaN\nNaN\n91.0\n...\nF\n5\n0.0\n0.0\n0.0\n0.0\n0.0\n11.0\n11\nNaN\n\n\n5976\nBERPC1997001\ncs134\nNaN\nNaN\n0.21\nW\n24.0\nNaN\nNaN\n91.0\n...\nF\n5\n0.0\n0.0\n0.0\n0.0\n0.0\n11.0\n11\nNaN\n\n\n\n\n6 rows × 33 columns", + "crumbs": [ + "Handlers", + "HELCOM" + ] + }, + { + "objectID": "handlers/geotraces.html", + "href": "handlers/geotraces.html", + "title": "Geotraces", + "section": "", + "text": "TODO & QUESTIONS:" + }, + { + "objectID": "handlers/geotraces.html#packages-import", + "href": "handlers/geotraces.html#packages-import", + "title": "Geotraces", + "section": "Packages import", + "text": "Packages import\n\n\n\nThe autoreload extension is already loaded. To reload it, use:\n %reload_ext autoreload\n\n\n\npd.set_option('display.max_rows', 100)\n\n\nimport warnings\nwarnings.filterwarnings('ignore')" + }, + { + "objectID": "handlers/geotraces.html#input-and-output-file-names", + "href": "handlers/geotraces.html#input-and-output-file-names", + "title": "Geotraces", + "section": "Input and output file names", + "text": "Input and output file names" + }, + { + "objectID": "handlers/geotraces.html#load-data", + "href": "handlers/geotraces.html#load-data", + "title": "Geotraces", + "section": "Load data", + "text": "Load data\n\ndf = pd.read_csv(fname_in)\ndf.head()\n\n\n\n\n\n\n\n\nCruise\nStation:METAVAR:INDEXED_TEXT\nType\nyyyy-mm-ddThh:mm:ss.sss\nLongitude [degrees_east]\nLatitude [degrees_north]\nBot. Depth [m]\nOperator's Cruise Name:METAVAR:INDEXED_TEXT\nShip Name:METAVAR:INDEXED_TEXT\nPeriod:METAVAR:INDEXED_TEXT\n...\nQV:SEADATANET.581\nCo_CELL_CONC_BOTTLE [amol/cell]\nQV:SEADATANET.582\nNi_CELL_CONC_BOTTLE [amol/cell]\nQV:SEADATANET.583\nCu_CELL_CONC_BOTTLE [amol/cell]\nQV:SEADATANET.584\nZn_CELL_CONC_BOTTLE [amol/cell]\nQV:SEADATANET.585\nQV:ODV:SAMPLE\n\n\n\n\n0\nGA01\n0\nB\n2014-05-17T22:29:00\n349.29999\n38.4329\n4854.0\nGEOVIDE\nPourquoi pas?\n15/05/2014 - 30/06/2014\n...\n9\nNaN\n9\nNaN\n9\nNaN\n9\nNaN\n9\n1\n\n\n1\nGA01\n0\nB\n2014-05-17T22:29:00\n349.29999\n38.4329\n4854.0\nGEOVIDE\nPourquoi pas?\n15/05/2014 - 30/06/2014\n...\n9\nNaN\n9\nNaN\n9\nNaN\n9\nNaN\n9\n1\n\n\n2\nGA01\n0\nB\n2014-05-17T22:29:00\n349.29999\n38.4329\n4854.0\nGEOVIDE\nPourquoi pas?\n15/05/2014 - 30/06/2014\n...\n9\nNaN\n9\nNaN\n9\nNaN\n9\nNaN\n9\n1\n\n\n3\nGA01\n0\nB\n2014-05-17T22:29:00\n349.29999\n38.4329\n4854.0\nGEOVIDE\nPourquoi pas?\n15/05/2014 - 30/06/2014\n...\n9\nNaN\n9\nNaN\n9\nNaN\n9\nNaN\n9\n1\n\n\n4\nGA01\n0\nB\n2014-05-17T22:29:00\n349.29999\n38.4329\n4854.0\nGEOVIDE\nPourquoi pas?\n15/05/2014 - 30/06/2014\n...\n9\nNaN\n9\nNaN\n9\nNaN\n9\nNaN\n9\n1\n\n\n\n\n5 rows × 1188 columns\n\n\n\n\ndef find_print_col(s, cols, lower=True):\n cols = cols if not lower else [col.lower() for col in cols]\n for col in cols:\n if s in col: print(col)\n\nfind_print_col('sal', df.columns)\nfind_print_col('tmp', df.columns)\nfind_print_col('oxy', df.columns)\nfind_print_col('U_236_238', df.columns, lower=False)\n\nctdsal_d_conc_sensor [pss-78]\nsalinity_d_conc_bottle\nsalinity_d_conc_pump\nsalinity_d_conc_fish\nsalinity_d_conc_uway\nsalinity_d_conc_boat_pump\nctdtmp_t_value_sensor [deg c]\noxygen_d_conc_bottle [umol/kg]\nctdoxy_d_conc_sensor [umol/kg]\nU_236_238_T_RATIO_BOTTLE [per 10^12]" + }, + { + "objectID": "handlers/geotraces.html#data-transformation-pipeline", + "href": "handlers/geotraces.html#data-transformation-pipeline", + "title": "Geotraces", + "section": "Data transformation pipeline", + "text": "Data transformation pipeline\n\nSelect columns of interest\n\n# U_236_238\n# Done: Th_232, I_129, Ac_227\n\n\nsource\n\n\nSelectColsOfInterestCB\n\n SelectColsOfInterestCB (common_coi, nuclides_pattern)\n\nSelect columns of interest.\n\ndf = pd.read_csv(fname_in)\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern)\n])\n\n\ndf_test = tfm()\ndf_test.head()\n\n\n\n\n\n\n\n\nyyyy-mm-ddThh:mm:ss.sss\nLongitude [degrees_east]\nLatitude [degrees_north]\nBot. Depth [m]\nDEPTH [m]\nTRITIUM_D_CONC_BOTTLE [TU]\nCs_137_D_CONC_BOTTLE [uBq/kg]\nI_129_D_CONC_BOTTLE [atoms/kg]\nNp_237_D_CONC_BOTTLE [uBq/kg]\nPu_239_D_CONC_BOTTLE [uBq/kg]\n...\nTh_230_TP_CONC_PUMP [uBq/kg]\nTh_230_SPT_CONC_PUMP [uBq/kg]\nTh_230_LPT_CONC_PUMP [uBq/kg]\nTh_232_TP_CONC_PUMP [pmol/kg]\nTh_232_SPT_CONC_PUMP [pmol/kg]\nTh_232_LPT_CONC_PUMP [pmol/kg]\nTh_234_SPT_CONC_PUMP [mBq/kg]\nTh_234_LPT_CONC_PUMP [mBq/kg]\nPo_210_TP_CONC_UWAY [mBq/kg]\nPb_210_TP_CONC_UWAY [mBq/kg]\n\n\n\n\n0\n2014-05-17T22:29:00\n349.29999\n38.4329\n4854.0\n2957.1\nNaN\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n1\n2014-05-17T22:29:00\n349.29999\n38.4329\n4854.0\n2957.2\nNaN\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n2\n2014-05-17T22:29:00\n349.29999\n38.4329\n4854.0\n2957.2\nNaN\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n3\n2014-05-17T22:29:00\n349.29999\n38.4329\n4854.0\n2957.2\nNaN\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n4\n2014-05-17T22:29:00\n349.29999\n38.4329\n4854.0\n2957.2\nNaN\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n\n\n5 rows × 85 columns\n\n\n\n\n\nReshape: wide to long\nSo that we can extract information such as sample methodology, filtering status, units included in Geotraces nuclides name.\n\nsource\n\n\nWideToLongCB\n\n WideToLongCB (common_coi, nuclides_pattern, var_name='nuclide',\n value_name='value')\n\nGet Geotraces nuclide names as values not column names to extract contained information (unit, sampling method, …).\n\ndf = pd.read_csv(fname_in)\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern),\n WideToLongCB(common_coi, nuclides_pattern)\n])\n\ndf_test = tfm()\ndf_test.shape\n\n(26745, 7)\n\n\n\n\nExtract\n\nUnit\n\nsource\n\n\n\nExtractUnitCB\n\n ExtractUnitCB (var_name='nuclide')\n\nExtract units from nuclide names.\n\ndf = pd.read_csv(fname_in)\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern),\n WideToLongCB(common_coi, nuclides_pattern),\n ExtractUnitCB()\n])\n\ndf_test = tfm()\ndf_test.head()\n\n\n\n\n\n\n\n\nyyyy-mm-ddThh:mm:ss.sss\nLongitude [degrees_east]\nLatitude [degrees_north]\nBot. Depth [m]\nDEPTH [m]\nnuclide\nvalue\n_unit\n\n\n\n\n9223\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n17.8\nTRITIUM_D_CONC_BOTTLE [TU]\n0.733\nTU\n\n\n9231\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n34.7\nTRITIUM_D_CONC_BOTTLE [TU]\n0.696\nTU\n\n\n9237\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n67.5\nTRITIUM_D_CONC_BOTTLE [TU]\n0.718\nTU\n\n\n9244\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n91.9\nTRITIUM_D_CONC_BOTTLE [TU]\n0.709\nTU\n\n\n9256\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n136.6\nTRITIUM_D_CONC_BOTTLE [TU]\n0.692\nTU\n\n\n\n\n\n\n\n\nFiltering status\n\n#\\export\nphase = {\n 'D': {'filt': 1, 'group': 'seawater'},\n 'T': {'filt': 2, 'group': 'seawater'},\n 'TP': {'filt': 1, 'group': 'suspended-matter'}, \n 'LPT': {'filt': 1, 'group': 'suspended-matter'},\n 'SPT': {'filt': 1, 'group': 'suspended-matter'}}\n\n\nsource\n\n\n\nExtractFilteringStatusCB\n\n ExtractFilteringStatusCB (phase, var_name='nuclide')\n\nExtract filtering status from nuclide names.\n\ndf = pd.read_csv(fname_in)\n\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern),\n WideToLongCB(common_coi, nuclides_pattern),\n ExtractUnitCB(),\n ExtractFilteringStatusCB(phase)\n])\n\ndf_test = tfm()\ndf_test.head()\n\n\n\n\n\n\n\n\nyyyy-mm-ddThh:mm:ss.sss\nLongitude [degrees_east]\nLatitude [degrees_north]\nBot. Depth [m]\nDEPTH [m]\nnuclide\nvalue\n_unit\n_filt\ngroup\n\n\n\n\n9223\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n17.8\nTRITIUM_D_CONC_BOTTLE [TU]\n0.733\nTU\n1\nseawater\n\n\n9231\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n34.7\nTRITIUM_D_CONC_BOTTLE [TU]\n0.696\nTU\n1\nseawater\n\n\n9237\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n67.5\nTRITIUM_D_CONC_BOTTLE [TU]\n0.718\nTU\n1\nseawater\n\n\n9244\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n91.9\nTRITIUM_D_CONC_BOTTLE [TU]\n0.709\nTU\n1\nseawater\n\n\n9256\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n136.6\nTRITIUM_D_CONC_BOTTLE [TU]\n0.692\nTU\n1\nseawater\n\n\n\n\n\n\n\n\nSampling method\n\n#\\export\n# To be validated\nsmp_method = {\n 'BOTTLE': 1,\n 'FISH': 18,\n 'PUMP': 14,\n 'UWAY': 24}\n\n\nsource\n\n\n\nExtractSamplingMethodCB\n\n ExtractSamplingMethodCB (smp_method, var_name='nuclide')\n\nExtract sampling method from nuclide names.\n\ndf = pd.read_csv(fname_in)\n\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern),\n WideToLongCB(common_coi, nuclides_pattern),\n ExtractUnitCB(),\n ExtractFilteringStatusCB(phase),\n ExtractSamplingMethodCB(smp_method)\n])\n\ndf_test = tfm()\ndf_test.head()\n\n\n\n\n\n\n\n\nyyyy-mm-ddThh:mm:ss.sss\nLongitude [degrees_east]\nLatitude [degrees_north]\nBot. Depth [m]\nDEPTH [m]\nnuclide\nvalue\n_unit\n_filt\ngroup\n_sampmet\n\n\n\n\n9223\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n17.8\nTRITIUM_D_CONC_BOTTLE [TU]\n0.733\nTU\n1\nseawater\n1\n\n\n9231\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n34.7\nTRITIUM_D_CONC_BOTTLE [TU]\n0.696\nTU\n1\nseawater\n1\n\n\n9237\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n67.5\nTRITIUM_D_CONC_BOTTLE [TU]\n0.718\nTU\n1\nseawater\n1\n\n\n9244\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n91.9\nTRITIUM_D_CONC_BOTTLE [TU]\n0.709\nTU\n1\nseawater\n1\n\n\n9256\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n136.6\nTRITIUM_D_CONC_BOTTLE [TU]\n0.692\nTU\n1\nseawater\n1\n\n\n\n\n\n\n\n\n\nRemap to MARIS nuclide names\n\n#\\export\nnuclides_name = {'TRITIUM': 'h3', 'Pu_239_Pu_240': 'pu239_240_tot'}\n\n\nsource\n\n\nRenameNuclideCB\n\n RenameNuclideCB (nuclides_name, var_name='nuclide')\n\nRemap nuclides name to MARIS standard.\n\ndf = pd.read_csv(fname_in)\n\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern),\n WideToLongCB(common_coi, nuclides_pattern),\n ExtractUnitCB(),\n ExtractFilteringStatusCB(phase),\n ExtractSamplingMethodCB(smp_method),\n RenameNuclideCB(nuclides_name)\n])\n\ndf_test = tfm()\ndf_test.head()\n\n\n\n\n\n\n\n\nyyyy-mm-ddThh:mm:ss.sss\nLongitude [degrees_east]\nLatitude [degrees_north]\nBot. Depth [m]\nDEPTH [m]\nnuclide\nvalue\n_unit\n_filt\ngroup\n_sampmet\n\n\n\n\n9223\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n17.8\nh3\n0.733\nTU\n1\nseawater\n1\n\n\n9231\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n34.7\nh3\n0.696\nTU\n1\nseawater\n1\n\n\n9237\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n67.5\nh3\n0.718\nTU\n1\nseawater\n1\n\n\n9244\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n91.9\nh3\n0.709\nTU\n1\nseawater\n1\n\n\n9256\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n136.6\nh3\n0.692\nTU\n1\nseawater\n1\n\n\n\n\n\n\n\n\ndf_test.nuclide.unique()\n\narray(['h3', 'cs137', 'i129', 'np237', 'pu239', 'pu239_240_tot', 'pu240',\n 'u236', 'pa231', 'pb210', 'po210', 'ra224', 'ra226', 'ra228',\n 'th230', 'th232', 'th234', 'ac227', 'be7', 'ra223', 'th228'],\n dtype=object)\n\n\n\n\nStandardize unit\n\n#\\export\nunits_lut = {\n 'TU': {'id': 7, 'factor': 1},\n 'uBq/kg': {'id': 3, 'factor': 1e-6},\n 'atoms/kg': {'id': 9, 'factor': 1},\n 'mBq/kg': {'id': 3, 'factor': 1e-3}}\n\n\nsource\n\n\nStandardizeUnitCB\n\n StandardizeUnitCB (units_lut, var_name='value')\n\nRemap unit to MARIS standard ones and apply conversion where needed.\n\ndf = pd.read_csv(fname_in)\n\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern),\n WideToLongCB(common_coi, nuclides_pattern),\n ExtractUnitCB(),\n ExtractFilteringStatusCB(phase),\n ExtractSamplingMethodCB(smp_method),\n RenameNuclideCB(nuclides_name),\n StandardizeUnitCB(units_lut)\n])\n\ndf_test = tfm()\nprint(df_test.head())\nprint(df_test.columns)\n\n yyyy-mm-ddThh:mm:ss.sss Longitude [degrees_east] \\\n9223 2010-10-17T00:13:29 350.33792 \n9231 2010-10-17T00:13:29 350.33792 \n9237 2010-10-17T00:13:29 350.33792 \n9244 2010-10-17T00:13:29 350.33792 \n9256 2010-10-17T00:13:29 350.33792 \n\n Latitude [degrees_north] Bot. Depth [m] DEPTH [m] nuclide value \\\n9223 38.3271 2827.0 17.8 h3 0.733 \n9231 38.3271 2827.0 34.7 h3 0.696 \n9237 38.3271 2827.0 67.5 h3 0.718 \n9244 38.3271 2827.0 91.9 h3 0.709 \n9256 38.3271 2827.0 136.6 h3 0.692 \n\n _unit _filt group _sampmet \n9223 7.0 1 seawater 1 \n9231 7.0 1 seawater 1 \n9237 7.0 1 seawater 1 \n9244 7.0 1 seawater 1 \n9256 7.0 1 seawater 1 \nIndex(['yyyy-mm-ddThh:mm:ss.sss', 'Longitude [degrees_east]',\n 'Latitude [degrees_north]', 'Bot. Depth [m]', 'DEPTH [m]', 'nuclide',\n 'value', '_unit', '_filt', 'group', '_sampmet'],\n dtype='object')\n\n\n\n\nRename common columns\n\nsource\n\n\nrenaming_rules\n\n renaming_rules ()\n\n\nsource\n\n\nRenameColumnCB\n\n RenameColumnCB (renaming_rules=<function renaming_rules>)\n\nRenaming variables to MARIS standard names.\n\ndf = pd.read_csv(fname_in)\n\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern),\n WideToLongCB(common_coi, nuclides_pattern),\n ExtractUnitCB(),\n ExtractFilteringStatusCB(phase),\n ExtractSamplingMethodCB(smp_method),\n RenameNuclideCB(nuclides_name),\n StandardizeUnitCB(units_lut),\n RenameColumnCB(renaming_rules)\n])\n\ndf_test = tfm()\ndf_test.head()\n\n\n\n\n\n\n\n\ntime\nlon\nlat\ntot_depth\nsmp_depth\nnuclide\nvalue\n_unit\n_filt\ngroup\n_sampmet\n\n\n\n\n9223\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n17.8\nh3\n0.733\n7.0\n1\nseawater\n1\n\n\n9231\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n34.7\nh3\n0.696\n7.0\n1\nseawater\n1\n\n\n9237\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n67.5\nh3\n0.718\n7.0\n1\nseawater\n1\n\n\n9244\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n91.9\nh3\n0.709\n7.0\n1\nseawater\n1\n\n\n9256\n2010-10-17T00:13:29\n350.33792\n38.3271\n2827.0\n136.6\nh3\n0.692\n7.0\n1\nseawater\n1\n\n\n\n\n\n\n\n\n\nUnshift longitudes\n\nsource\n\n\nUnshiftLongitudeCB\n\n UnshiftLongitudeCB ()\n\nLongitudes are coded between 0 and 360 in Geotraces. We rescale it between -180 and 180 instead.\n\ndf = pd.read_csv(fname_in)\n\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern),\n WideToLongCB(common_coi, nuclides_pattern),\n ExtractUnitCB(),\n ExtractFilteringStatusCB(phase),\n ExtractSamplingMethodCB(smp_method),\n RenameNuclideCB(nuclides_name),\n StandardizeUnitCB(units_lut),\n RenameColumnCB(renaming_rules),\n UnshiftLongitudeCB()\n])\n\ndf_test = tfm()\ndf_test.head()\n\n\n\n\n\n\n\n\ntime\nlon\nlat\ntot_depth\nsmp_depth\nnuclide\nvalue\n_unit\n_filt\ngroup\n_sampmet\n\n\n\n\n9223\n2010-10-17T00:13:29\n170.33792\n38.3271\n2827.0\n17.8\nh3\n0.733\n7.0\n1\nseawater\n1\n\n\n9231\n2010-10-17T00:13:29\n170.33792\n38.3271\n2827.0\n34.7\nh3\n0.696\n7.0\n1\nseawater\n1\n\n\n9237\n2010-10-17T00:13:29\n170.33792\n38.3271\n2827.0\n67.5\nh3\n0.718\n7.0\n1\nseawater\n1\n\n\n9244\n2010-10-17T00:13:29\n170.33792\n38.3271\n2827.0\n91.9\nh3\n0.709\n7.0\n1\nseawater\n1\n\n\n9256\n2010-10-17T00:13:29\n170.33792\n38.3271\n2827.0\n136.6\nh3\n0.692\n7.0\n1\nseawater\n1\n\n\n\n\n\n\n\n\n\nDispatch to groups\n\nsource\n\n\nDispatchToGroupCB\n\n DispatchToGroupCB (group_name='group')\n\nConvert to a dictionary of dataframe with sample type (seawater,…) as keys.\n\ndf = pd.read_csv(fname_in)\n\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern),\n WideToLongCB(common_coi, nuclides_pattern),\n ExtractUnitCB(),\n ExtractFilteringStatusCB(phase),\n ExtractSamplingMethodCB(smp_method),\n RenameNuclideCB(nuclides_name),\n StandardizeUnitCB(units_lut),\n RenameColumnCB(renaming_rules),\n UnshiftLongitudeCB(),\n DispatchToGroupCB()\n])\n\ntfm()\n\n{'seawater': time lon lat tot_depth smp_depth \\\n 9223 2010-10-17T00:13:29 170.33792 38.3271 2827.0 17.8 \n 9231 2010-10-17T00:13:29 170.33792 38.3271 2827.0 34.7 \n 9237 2010-10-17T00:13:29 170.33792 38.3271 2827.0 67.5 \n 9244 2010-10-17T00:13:29 170.33792 38.3271 2827.0 91.9 \n 9256 2010-10-17T00:13:29 170.33792 38.3271 2827.0 136.6 \n ... ... ... ... ... ... \n 6173855 2015-09-04T09:15:18 3.25999 88.4058 3960.0 5.0 \n 6173858 2015-09-04T09:15:18 3.25999 88.4058 3960.0 20.0 \n 6174035 2015-09-07T14:20:39 -90.74920 89.9809 4229.0 0.5 \n 6174038 2015-09-07T14:20:39 -90.74920 89.9809 4229.0 1.5 \n 6174041 2015-09-07T14:20:39 -90.74920 89.9809 4229.0 5.0 \n \n nuclide value _unit _filt _sampmet \n 9223 h3 0.7330 7.0 1 1 \n 9231 h3 0.6960 7.0 1 1 \n 9237 h3 0.7180 7.0 1 1 \n 9244 h3 0.7090 7.0 1 1 \n 9256 h3 0.6920 7.0 1 1 \n ... ... ... ... ... ... \n 6173855 th234 0.0294 3.0 2 14 \n 6173858 th234 0.0347 3.0 2 14 \n 6174035 th234 0.0279 3.0 2 14 \n 6174038 th234 0.0282 3.0 2 14 \n 6174041 th234 0.0323 3.0 2 14 \n \n [19139 rows x 10 columns],\n 'suspended-matter': time lon lat tot_depth smp_depth \\\n 6260008 2008-02-13T21:05:05 -171.00616 -42.3413 4569.0 24.8 \n 6260022 2008-02-13T21:05:05 -171.00616 -42.3413 4569.0 100.2 \n 6260033 2008-02-13T21:05:05 -171.00616 -42.3413 4569.0 200.3 \n 6260044 2008-02-13T21:05:05 -171.00616 -42.3413 4569.0 500.1 \n 6260049 2008-02-13T21:05:05 -171.00616 -42.3413 4569.0 741.4 \n ... ... ... ... ... ... \n 8378864 2007-09-22T11:19:17 -56.58100 77.3723 1124.0 7.0 \n 8379044 2007-09-23T00:28:00 -57.12800 76.8946 94.0 7.0 \n 8379071 2007-09-23T10:28:16 -57.85300 76.1809 75.0 7.0 \n 8379153 2007-09-23T18:58:30 -58.23000 75.7056 65.0 7.0 \n 8379186 2007-09-23T23:55:04 -58.63800 75.2003 49.0 7.0 \n \n nuclide value _unit _filt _sampmet \n 6260008 po210 0.000091 3.0 1 1 \n 6260022 po210 0.000029 3.0 1 1 \n 6260033 po210 0.000017 3.0 1 1 \n 6260044 po210 0.000040 3.0 1 1 \n 6260049 po210 0.000047 3.0 1 1 \n ... ... ... ... ... ... \n 8378864 pb210 0.000213 3.0 1 24 \n 8379044 pb210 0.000201 3.0 1 24 \n 8379071 pb210 0.000394 3.0 1 24 \n 8379153 pb210 0.000212 3.0 1 24 \n 8379186 pb210 0.000077 3.0 1 24 \n \n [7606 rows x 10 columns]}\n\n\n\n\nRehape: long to wide\n\nsource\n\n\nReshapeLongToWide\n\n ReshapeLongToWide (columns='nuclide', values=['value'])\n\nConvert data from long to wide with renamed columns.\n\ndf = pd.read_csv(fname_in)\n\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern),\n WideToLongCB(common_coi, nuclides_pattern),\n ExtractUnitCB(),\n ExtractFilteringStatusCB(phase),\n ExtractSamplingMethodCB(smp_method),\n RenameNuclideCB(nuclides_name),\n StandardizeUnitCB(units_lut),\n RenameColumnCB(renaming_rules),\n UnshiftLongitudeCB(),\n DispatchToGroupCB(),\n ReshapeLongToWide()\n])\n\ndfs_test = tfm()['seawater']\nprint('shape: ', dfs_test.shape)\nprint('columns: ', dfs_test.columns)\ndfs_test.head()\n\nshape: (19139, 88)\ncolumns: Index(['lat', 'lon', 'time', 'sample', 'tot_depth', 'smp_depth', 'ac227_filt',\n 'be7_filt', 'cs137_filt', 'h3_filt', 'i129_filt', 'np237_filt',\n 'pa231_filt', 'pb210_filt', 'po210_filt', 'pu239_filt',\n 'pu239_240_tot_filt', 'pu240_filt', 'ra223_filt', 'ra224_filt',\n 'ra226_filt', 'ra228_filt', 'th228_filt', 'th230_filt', 'th232_filt',\n 'th234_filt', 'u236_filt', 'ac227_sampmet', 'be7_sampmet',\n 'cs137_sampmet', 'h3_sampmet', 'i129_sampmet', 'np237_sampmet',\n 'pa231_sampmet', 'pb210_sampmet', 'po210_sampmet', 'pu239_sampmet',\n 'pu239_240_tot_sampmet', 'pu240_sampmet', 'ra223_sampmet',\n 'ra224_sampmet', 'ra226_sampmet', 'ra228_sampmet', 'th228_sampmet',\n 'th230_sampmet', 'th232_sampmet', 'th234_sampmet', 'u236_sampmet',\n 'ac227_unit', 'be7_unit', 'cs137_unit', 'h3_unit', 'i129_unit',\n 'np237_unit', 'pa231_unit', 'pb210_unit', 'po210_unit', 'pu239_unit',\n 'pu239_240_tot_unit', 'pu240_unit', 'ra223_unit', 'ra224_unit',\n 'ra226_unit', 'ra228_unit', 'th228_unit', 'th230_unit', 'th234_unit',\n 'u236_unit', 'ac227', 'be7', 'cs137', 'h3', 'i129', 'np237', 'pa231',\n 'pb210', 'po210', 'pu239', 'pu239_240_tot', 'pu240', 'ra223', 'ra224',\n 'ra226', 'ra228', 'th228', 'th230', 'th234', 'u236'],\n dtype='object')\n\n\n\n\n\n\n\n\n\nlat\nlon\ntime\nsample\ntot_depth\nsmp_depth\nac227_filt\nbe7_filt\ncs137_filt\nh3_filt\n...\npu239_240_tot\npu240\nra223\nra224\nra226\nra228\nth228\nth230\nth234\nu236\n\n\n\n\n0\n-70.5744\n171.8772\n2008-03-05T13:57:45\n1306733\n136.0\n9.7\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n1\n-70.5744\n171.8772\n2008-03-05T13:57:45\n1306747\n136.0\n135.6\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n2\n-70.5744\n171.8772\n2008-03-05T13:57:45\n2150069\n136.0\n9.7\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n0.000002\nNaN\nNaN\n\n\n3\n-70.5744\n171.8772\n2008-03-05T13:57:45\n2150083\n136.0\n135.6\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n0.000003\nNaN\nNaN\n\n\n4\n-70.5744\n171.8772\n2008-03-05T13:57:45\n2360903\n136.0\n9.7\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n\n\n5 rows × 88 columns\n\n\n\n\n\nParse time\n\nsource\n\n\nParseTimeCB\n\n ParseTimeCB ()\n\nBase class for callbacks.\n\ndf = pd.read_csv(fname_in)\n\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern),\n WideToLongCB(common_coi, nuclides_pattern),\n ExtractUnitCB(),\n ExtractFilteringStatusCB(phase),\n ExtractSamplingMethodCB(smp_method),\n RenameNuclideCB(nuclides_name),\n StandardizeUnitCB(units_lut),\n RenameColumnCB(renaming_rules),\n UnshiftLongitudeCB(),\n DispatchToGroupCB(),\n ReshapeLongToWide(),\n ParseTimeCB()\n])\n\nprint('time data type: ', tfm()['seawater'].time.dtype)\n\ntime data type: datetime64[ns]\n\n\n\n\nEncode time (seconds since …)\n\ndf = pd.read_csv(fname_in)\n\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern),\n WideToLongCB(common_coi, nuclides_pattern),\n ExtractUnitCB(),\n ExtractFilteringStatusCB(phase),\n ExtractSamplingMethodCB(smp_method),\n RenameNuclideCB(nuclides_name),\n StandardizeUnitCB(units_lut),\n RenameColumnCB(renaming_rules),\n UnshiftLongitudeCB(),\n DispatchToGroupCB(),\n ReshapeLongToWide(),\n ParseTimeCB(),\n EncodeTimeCB(cfg())\n])\n\ndfs_test = tfm()['seawater']\ndfs_test.head()\n\n\n\n\n\n\n\n\nlat\nlon\ntime\nsample\ntot_depth\nsmp_depth\nac227_filt\nbe7_filt\ncs137_filt\nh3_filt\n...\npu239_240_tot\npu240\nra223\nra224\nra226\nra228\nth228\nth230\nth234\nu236\n\n\n\n\n0\n-70.5744\n171.8772\n1204725465\n1306733\n136.0\n9.7\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n1\n-70.5744\n171.8772\n1204725465\n1306747\n136.0\n135.6\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n2\n-70.5744\n171.8772\n1204725465\n2150069\n136.0\n9.7\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n0.000002\nNaN\nNaN\n\n\n3\n-70.5744\n171.8772\n1204725465\n2150083\n136.0\n135.6\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n0.000003\nNaN\nNaN\n\n\n4\n-70.5744\n171.8772\n1204725465\n2360903\n136.0\n9.7\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n\n\n5 rows × 88 columns\n\n\n\n\n\nSanitize coordinates\n\ndf = pd.read_csv(fname_in)\n\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern),\n WideToLongCB(common_coi, nuclides_pattern),\n ExtractUnitCB(),\n ExtractFilteringStatusCB(phase),\n ExtractSamplingMethodCB(smp_method),\n RenameNuclideCB(nuclides_name),\n StandardizeUnitCB(units_lut),\n RenameColumnCB(renaming_rules),\n UnshiftLongitudeCB(),\n DispatchToGroupCB(),\n ReshapeLongToWide(),\n ParseTimeCB(),\n EncodeTimeCB(cfg()),\n SanitizeLonLatCB()\n])\ndfs_test = tfm()['seawater']\ndfs_test.head()\n\n\n\n\n\n\n\n\nlat\nlon\ntime\nsample\ntot_depth\nsmp_depth\nac227_filt\nbe7_filt\ncs137_filt\nh3_filt\n...\npu239_240_tot\npu240\nra223\nra224\nra226\nra228\nth228\nth230\nth234\nu236\n\n\n\n\n0\n-70.5744\n171.8772\n1204725465\n1306733\n136.0\n9.7\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n1\n-70.5744\n171.8772\n1204725465\n1306747\n136.0\n135.6\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n2\n-70.5744\n171.8772\n1204725465\n2150069\n136.0\n9.7\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n0.000002\nNaN\nNaN\n\n\n3\n-70.5744\n171.8772\n1204725465\n2150083\n136.0\n135.6\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n0.000003\nNaN\nNaN\n\n\n4\n-70.5744\n171.8772\n1204725465\n2360903\n136.0\n9.7\nNaN\nNaN\nNaN\nNaN\n...\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\nNaN\n\n\n\n\n5 rows × 88 columns" + }, + { + "objectID": "handlers/geotraces.html#netcdf-encoder", + "href": "handlers/geotraces.html#netcdf-encoder", + "title": "Geotraces", + "section": "NetCDF encoder", + "text": "NetCDF encoder\n\nExample change logs\n\ndf = pd.read_csv(fname_in)\n\ntfm = Transformer(df, cbs=[\n SelectColsOfInterestCB(common_coi, nuclides_pattern),\n WideToLongCB(common_coi, nuclides_pattern),\n ExtractUnitCB(),\n ExtractFilteringStatusCB(phase),\n ExtractSamplingMethodCB(smp_method),\n RenameNuclideCB(nuclides_name),\n StandardizeUnitCB(units_lut),\n RenameColumnCB(renaming_rules),\n UnshiftLongitudeCB(),\n DispatchToGroupCB(),\n ReshapeLongToWide(),\n ParseTimeCB(),\n EncodeTimeCB(cfg()),\n SanitizeLonLatCB()\n])\n\ntfm();\n\n\ntfm.logs\n\n['Select columns of interest.',\n '\\n Get Geotraces nuclide names as values not column names \\n to extract contained information (unit, sampling method, ...).\\n ',\n '\\n Extract units from nuclide names.\\n ',\n '\\n Extract filtering status from nuclide names.\\n ',\n '\\n Extract sampling method from nuclide names.\\n ',\n '\\n Remap nuclides name to MARIS standard.\\n ',\n '\\n Remap unit to MARIS standard ones and apply conversion where needed.\\n ',\n 'Renaming variables to MARIS standard names.',\n 'Longitudes are coded between 0 and 360 in Geotraces. We rescale it between -180 and 180 instead.',\n 'Convert to a dictionary of dataframe with sample type (seawater,...) as keys.',\n 'Convert data from long to wide with renamed columns.',\n 'Encode time as `int` representing seconds since xxx',\n 'Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator.']\n\n\n\n\nFeed global attributes\n\nsource\n\n\nget_attrs\n\n get_attrs (tfm, zotero_key, kw=['oceanography', 'Earth Science > Oceans >\n Ocean Chemistry> Radionuclides', 'Earth Science > Human\n Dimensions > Environmental Impacts > Nuclear Radiation\n Exposure', 'Earth Science > Oceans > Ocean Chemistry > Ocean\n Tracers, Earth Science > Oceans > Marine Sediments', 'Earth\n Science > Oceans > Ocean Chemistry, Earth Science > Oceans >\n Sea Ice > Isotopes', 'Earth Science > Oceans > Water Quality >\n Ocean Contaminants', 'Earth Science > Biological\n Classification > Animals/Vertebrates > Fish', 'Earth Science >\n Biosphere > Ecosystems > Marine Ecosystems', 'Earth Science >\n Biological Classification > Animals/Invertebrates > Mollusks',\n 'Earth Science > Biological Classification >\n Animals/Invertebrates > Arthropods > Crustaceans', 'Earth\n Science > Biological Classification > Plants > Macroalgae\n (Seaweeds)'])\n\n\nzotero_metadata = get_attrs(tfm, zotero_key='97UIMEXN', kw=kw)\nprint('Keys: ', zotero_metadata.keys())\nprint('Title: ', zotero_metadata['title'])\n\nKeys: dict_keys(['geospatial_lat_min', 'geospatial_lat_max', 'geospatial_lon_min', 'geospatial_lon_max', 'geospatial_bounds', 'time_coverage_start', 'time_coverage_end', 'title', 'summary', 'creator_name', 'keywords', 'publisher_postprocess_logs'])\nTitle: The GEOTRACES Intermediate Data Product 2017\n\n\n\n\nEncoding\n\nsource\n\n\nencode\n\n encode (fname_in, fname_out, nc_tpl_path, **kwargs)\n\n\nencode(fname_in, fname_out, nc_tpl_path(), verbose=False)" + } +] \ No newline at end of file diff --git a/site_libs/bootstrap/bootstrap-icons.css b/site_libs/bootstrap/bootstrap-icons.css new file mode 100644 index 0000000..285e444 --- /dev/null +++ b/site_libs/bootstrap/bootstrap-icons.css @@ -0,0 +1,2078 @@ +/*! + * Bootstrap Icons v1.11.1 (https://icons.getbootstrap.com/) + * Copyright 2019-2023 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/icons/blob/main/LICENSE) + */ + +@font-face { + font-display: block; + font-family: "bootstrap-icons"; + src: +url("./bootstrap-icons.woff?2820a3852bdb9a5832199cc61cec4e65") format("woff"); +} + +.bi::before, +[class^="bi-"]::before, +[class*=" bi-"]::before { + display: inline-block; + font-family: bootstrap-icons !important; + font-style: normal; + font-weight: normal !important; + font-variant: normal; + text-transform: none; + line-height: 1; + vertical-align: -.125em; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.bi-123::before { content: "\f67f"; } +.bi-alarm-fill::before { content: "\f101"; } +.bi-alarm::before { content: "\f102"; } +.bi-align-bottom::before { content: "\f103"; } +.bi-align-center::before { content: "\f104"; } +.bi-align-end::before { content: "\f105"; } +.bi-align-middle::before { content: "\f106"; } +.bi-align-start::before { content: "\f107"; } +.bi-align-top::before { content: "\f108"; } +.bi-alt::before { content: "\f109"; } +.bi-app-indicator::before { content: "\f10a"; } +.bi-app::before { content: "\f10b"; } +.bi-archive-fill::before { content: "\f10c"; } +.bi-archive::before { content: "\f10d"; } +.bi-arrow-90deg-down::before { content: "\f10e"; } +.bi-arrow-90deg-left::before { content: "\f10f"; } +.bi-arrow-90deg-right::before { content: "\f110"; } +.bi-arrow-90deg-up::before { content: "\f111"; } +.bi-arrow-bar-down::before { content: "\f112"; } +.bi-arrow-bar-left::before { content: "\f113"; } +.bi-arrow-bar-right::before { content: "\f114"; } +.bi-arrow-bar-up::before { content: "\f115"; } +.bi-arrow-clockwise::before { content: "\f116"; } +.bi-arrow-counterclockwise::before { content: "\f117"; } +.bi-arrow-down-circle-fill::before { content: "\f118"; } +.bi-arrow-down-circle::before { content: "\f119"; } +.bi-arrow-down-left-circle-fill::before { content: "\f11a"; } +.bi-arrow-down-left-circle::before { content: "\f11b"; } +.bi-arrow-down-left-square-fill::before { content: "\f11c"; } +.bi-arrow-down-left-square::before { content: "\f11d"; } +.bi-arrow-down-left::before { content: "\f11e"; } +.bi-arrow-down-right-circle-fill::before { content: "\f11f"; } +.bi-arrow-down-right-circle::before { content: "\f120"; } +.bi-arrow-down-right-square-fill::before { content: "\f121"; } +.bi-arrow-down-right-square::before { content: "\f122"; } +.bi-arrow-down-right::before { content: "\f123"; } +.bi-arrow-down-short::before { content: "\f124"; } +.bi-arrow-down-square-fill::before { content: "\f125"; } +.bi-arrow-down-square::before { content: "\f126"; } +.bi-arrow-down-up::before { content: "\f127"; } +.bi-arrow-down::before { content: "\f128"; } +.bi-arrow-left-circle-fill::before { content: "\f129"; } +.bi-arrow-left-circle::before { content: "\f12a"; } +.bi-arrow-left-right::before { content: "\f12b"; } +.bi-arrow-left-short::before { content: "\f12c"; } +.bi-arrow-left-square-fill::before { content: "\f12d"; } +.bi-arrow-left-square::before { content: "\f12e"; } +.bi-arrow-left::before { content: "\f12f"; } +.bi-arrow-repeat::before { content: "\f130"; } +.bi-arrow-return-left::before { content: "\f131"; } +.bi-arrow-return-right::before { content: "\f132"; } +.bi-arrow-right-circle-fill::before { content: "\f133"; } +.bi-arrow-right-circle::before { content: "\f134"; } +.bi-arrow-right-short::before { content: "\f135"; } +.bi-arrow-right-square-fill::before { content: "\f136"; } +.bi-arrow-right-square::before { content: "\f137"; } +.bi-arrow-right::before { content: "\f138"; } +.bi-arrow-up-circle-fill::before { content: "\f139"; } +.bi-arrow-up-circle::before { content: "\f13a"; } +.bi-arrow-up-left-circle-fill::before { content: "\f13b"; } +.bi-arrow-up-left-circle::before { content: "\f13c"; } +.bi-arrow-up-left-square-fill::before { content: "\f13d"; } +.bi-arrow-up-left-square::before { content: "\f13e"; } +.bi-arrow-up-left::before { content: "\f13f"; } +.bi-arrow-up-right-circle-fill::before { content: "\f140"; } +.bi-arrow-up-right-circle::before { content: "\f141"; } +.bi-arrow-up-right-square-fill::before { content: "\f142"; } +.bi-arrow-up-right-square::before { content: "\f143"; } +.bi-arrow-up-right::before { content: "\f144"; } +.bi-arrow-up-short::before { content: "\f145"; } +.bi-arrow-up-square-fill::before { content: "\f146"; } +.bi-arrow-up-square::before { content: "\f147"; } +.bi-arrow-up::before { content: "\f148"; } +.bi-arrows-angle-contract::before { content: "\f149"; } +.bi-arrows-angle-expand::before { content: "\f14a"; } +.bi-arrows-collapse::before { content: "\f14b"; } +.bi-arrows-expand::before { content: "\f14c"; } +.bi-arrows-fullscreen::before { content: "\f14d"; } +.bi-arrows-move::before { content: "\f14e"; } +.bi-aspect-ratio-fill::before { content: "\f14f"; } +.bi-aspect-ratio::before { content: "\f150"; } +.bi-asterisk::before { content: "\f151"; } +.bi-at::before { content: "\f152"; } +.bi-award-fill::before { content: "\f153"; } +.bi-award::before { content: "\f154"; } +.bi-back::before { content: "\f155"; } +.bi-backspace-fill::before { content: "\f156"; } +.bi-backspace-reverse-fill::before { content: "\f157"; } +.bi-backspace-reverse::before { content: "\f158"; } +.bi-backspace::before { content: "\f159"; } +.bi-badge-3d-fill::before { content: "\f15a"; } +.bi-badge-3d::before { content: "\f15b"; } +.bi-badge-4k-fill::before { content: "\f15c"; } +.bi-badge-4k::before { content: "\f15d"; } +.bi-badge-8k-fill::before { content: "\f15e"; } +.bi-badge-8k::before { content: "\f15f"; } +.bi-badge-ad-fill::before { content: "\f160"; } +.bi-badge-ad::before { content: "\f161"; } +.bi-badge-ar-fill::before { content: "\f162"; } +.bi-badge-ar::before { content: "\f163"; } +.bi-badge-cc-fill::before { content: "\f164"; } +.bi-badge-cc::before { content: "\f165"; } +.bi-badge-hd-fill::before { content: "\f166"; } +.bi-badge-hd::before { content: "\f167"; } +.bi-badge-tm-fill::before { content: "\f168"; } +.bi-badge-tm::before { content: "\f169"; } +.bi-badge-vo-fill::before { content: "\f16a"; } +.bi-badge-vo::before { content: "\f16b"; } +.bi-badge-vr-fill::before { content: "\f16c"; } +.bi-badge-vr::before { content: "\f16d"; } +.bi-badge-wc-fill::before { content: "\f16e"; } +.bi-badge-wc::before { content: "\f16f"; } +.bi-bag-check-fill::before { content: "\f170"; } +.bi-bag-check::before { content: "\f171"; } +.bi-bag-dash-fill::before { content: "\f172"; } +.bi-bag-dash::before { content: "\f173"; } +.bi-bag-fill::before { content: "\f174"; } +.bi-bag-plus-fill::before { content: "\f175"; } +.bi-bag-plus::before { content: "\f176"; } +.bi-bag-x-fill::before { content: "\f177"; } +.bi-bag-x::before { content: "\f178"; } +.bi-bag::before { content: "\f179"; } +.bi-bar-chart-fill::before { content: "\f17a"; } +.bi-bar-chart-line-fill::before { content: "\f17b"; } +.bi-bar-chart-line::before { content: "\f17c"; } +.bi-bar-chart-steps::before { content: "\f17d"; } +.bi-bar-chart::before { content: "\f17e"; } +.bi-basket-fill::before { content: "\f17f"; } +.bi-basket::before { content: "\f180"; } +.bi-basket2-fill::before { content: "\f181"; } +.bi-basket2::before { content: "\f182"; } +.bi-basket3-fill::before { content: "\f183"; } +.bi-basket3::before { content: "\f184"; } +.bi-battery-charging::before { content: "\f185"; } +.bi-battery-full::before { content: "\f186"; } +.bi-battery-half::before { content: "\f187"; } +.bi-battery::before { content: "\f188"; } +.bi-bell-fill::before { content: "\f189"; } +.bi-bell::before { content: "\f18a"; } +.bi-bezier::before { content: "\f18b"; } +.bi-bezier2::before { content: "\f18c"; } +.bi-bicycle::before { content: "\f18d"; } +.bi-binoculars-fill::before { content: "\f18e"; } +.bi-binoculars::before { content: "\f18f"; } +.bi-blockquote-left::before { content: "\f190"; } +.bi-blockquote-right::before { content: "\f191"; } +.bi-book-fill::before { content: "\f192"; } +.bi-book-half::before { content: "\f193"; } +.bi-book::before { content: "\f194"; } +.bi-bookmark-check-fill::before { content: "\f195"; } +.bi-bookmark-check::before { content: "\f196"; } +.bi-bookmark-dash-fill::before { content: "\f197"; } +.bi-bookmark-dash::before { content: "\f198"; } +.bi-bookmark-fill::before { content: "\f199"; } +.bi-bookmark-heart-fill::before { content: "\f19a"; } +.bi-bookmark-heart::before { content: "\f19b"; } +.bi-bookmark-plus-fill::before { content: "\f19c"; } +.bi-bookmark-plus::before { content: "\f19d"; } +.bi-bookmark-star-fill::before { content: "\f19e"; } +.bi-bookmark-star::before { content: "\f19f"; } +.bi-bookmark-x-fill::before { content: "\f1a0"; } +.bi-bookmark-x::before { content: "\f1a1"; } +.bi-bookmark::before { content: "\f1a2"; } +.bi-bookmarks-fill::before { content: "\f1a3"; } +.bi-bookmarks::before { content: "\f1a4"; } +.bi-bookshelf::before { content: "\f1a5"; } +.bi-bootstrap-fill::before { content: "\f1a6"; } +.bi-bootstrap-reboot::before { content: "\f1a7"; } +.bi-bootstrap::before { content: "\f1a8"; } +.bi-border-all::before { content: "\f1a9"; } +.bi-border-bottom::before { content: "\f1aa"; } +.bi-border-center::before { content: "\f1ab"; } +.bi-border-inner::before { content: "\f1ac"; } +.bi-border-left::before { content: "\f1ad"; } +.bi-border-middle::before { content: "\f1ae"; } +.bi-border-outer::before { content: "\f1af"; } +.bi-border-right::before { content: "\f1b0"; } +.bi-border-style::before { content: "\f1b1"; } +.bi-border-top::before { content: "\f1b2"; } +.bi-border-width::before { content: "\f1b3"; } +.bi-border::before { content: "\f1b4"; } +.bi-bounding-box-circles::before { content: "\f1b5"; } +.bi-bounding-box::before { content: "\f1b6"; } +.bi-box-arrow-down-left::before { content: "\f1b7"; } +.bi-box-arrow-down-right::before { content: "\f1b8"; } +.bi-box-arrow-down::before { content: "\f1b9"; } +.bi-box-arrow-in-down-left::before { content: "\f1ba"; } +.bi-box-arrow-in-down-right::before { content: "\f1bb"; } +.bi-box-arrow-in-down::before { content: "\f1bc"; } +.bi-box-arrow-in-left::before { content: "\f1bd"; } +.bi-box-arrow-in-right::before { content: "\f1be"; } +.bi-box-arrow-in-up-left::before { content: "\f1bf"; } +.bi-box-arrow-in-up-right::before { content: "\f1c0"; } +.bi-box-arrow-in-up::before { content: "\f1c1"; } +.bi-box-arrow-left::before { content: "\f1c2"; } +.bi-box-arrow-right::before { content: "\f1c3"; } +.bi-box-arrow-up-left::before { content: "\f1c4"; } +.bi-box-arrow-up-right::before { content: "\f1c5"; } +.bi-box-arrow-up::before { content: "\f1c6"; } +.bi-box-seam::before { content: "\f1c7"; } +.bi-box::before { content: "\f1c8"; } +.bi-braces::before { content: "\f1c9"; } +.bi-bricks::before { content: "\f1ca"; } +.bi-briefcase-fill::before { content: "\f1cb"; } +.bi-briefcase::before { content: "\f1cc"; } +.bi-brightness-alt-high-fill::before { content: "\f1cd"; } +.bi-brightness-alt-high::before { content: "\f1ce"; } +.bi-brightness-alt-low-fill::before { content: "\f1cf"; } +.bi-brightness-alt-low::before { content: "\f1d0"; } +.bi-brightness-high-fill::before { content: "\f1d1"; } +.bi-brightness-high::before { content: "\f1d2"; } +.bi-brightness-low-fill::before { content: "\f1d3"; } +.bi-brightness-low::before { content: "\f1d4"; } +.bi-broadcast-pin::before { content: "\f1d5"; } +.bi-broadcast::before { content: "\f1d6"; } +.bi-brush-fill::before { content: "\f1d7"; } +.bi-brush::before { content: "\f1d8"; } +.bi-bucket-fill::before { content: "\f1d9"; } +.bi-bucket::before { content: "\f1da"; } +.bi-bug-fill::before { content: "\f1db"; } +.bi-bug::before { content: "\f1dc"; } +.bi-building::before { content: "\f1dd"; } +.bi-bullseye::before { content: "\f1de"; } +.bi-calculator-fill::before { content: "\f1df"; } +.bi-calculator::before { content: "\f1e0"; } +.bi-calendar-check-fill::before { content: "\f1e1"; } +.bi-calendar-check::before { content: "\f1e2"; } +.bi-calendar-date-fill::before { content: "\f1e3"; } +.bi-calendar-date::before { content: "\f1e4"; } +.bi-calendar-day-fill::before { content: "\f1e5"; } +.bi-calendar-day::before { content: "\f1e6"; } +.bi-calendar-event-fill::before { content: "\f1e7"; } +.bi-calendar-event::before { content: "\f1e8"; } +.bi-calendar-fill::before { content: "\f1e9"; } +.bi-calendar-minus-fill::before { content: "\f1ea"; } +.bi-calendar-minus::before { content: "\f1eb"; } +.bi-calendar-month-fill::before { content: "\f1ec"; } +.bi-calendar-month::before { content: "\f1ed"; } +.bi-calendar-plus-fill::before { content: "\f1ee"; } +.bi-calendar-plus::before { content: "\f1ef"; } +.bi-calendar-range-fill::before { content: "\f1f0"; } +.bi-calendar-range::before { content: "\f1f1"; } +.bi-calendar-week-fill::before { content: "\f1f2"; } +.bi-calendar-week::before { content: "\f1f3"; } +.bi-calendar-x-fill::before { content: "\f1f4"; } +.bi-calendar-x::before { content: "\f1f5"; } +.bi-calendar::before { content: "\f1f6"; } +.bi-calendar2-check-fill::before { content: "\f1f7"; } +.bi-calendar2-check::before { content: "\f1f8"; } +.bi-calendar2-date-fill::before { content: "\f1f9"; } +.bi-calendar2-date::before { content: "\f1fa"; } +.bi-calendar2-day-fill::before { content: "\f1fb"; } +.bi-calendar2-day::before { content: "\f1fc"; } +.bi-calendar2-event-fill::before { content: "\f1fd"; } +.bi-calendar2-event::before { content: "\f1fe"; } +.bi-calendar2-fill::before { content: "\f1ff"; } +.bi-calendar2-minus-fill::before { content: "\f200"; } +.bi-calendar2-minus::before { content: "\f201"; } +.bi-calendar2-month-fill::before { content: "\f202"; } +.bi-calendar2-month::before { content: "\f203"; } +.bi-calendar2-plus-fill::before { content: "\f204"; } +.bi-calendar2-plus::before { content: "\f205"; } +.bi-calendar2-range-fill::before { content: "\f206"; } +.bi-calendar2-range::before { content: "\f207"; } +.bi-calendar2-week-fill::before { content: "\f208"; } +.bi-calendar2-week::before { content: "\f209"; } +.bi-calendar2-x-fill::before { content: "\f20a"; } +.bi-calendar2-x::before { content: "\f20b"; } +.bi-calendar2::before { content: "\f20c"; } +.bi-calendar3-event-fill::before { content: "\f20d"; } +.bi-calendar3-event::before { content: "\f20e"; } +.bi-calendar3-fill::before { content: "\f20f"; } +.bi-calendar3-range-fill::before { content: "\f210"; } +.bi-calendar3-range::before { content: "\f211"; } +.bi-calendar3-week-fill::before { content: "\f212"; } +.bi-calendar3-week::before { content: "\f213"; } +.bi-calendar3::before { content: "\f214"; } +.bi-calendar4-event::before { content: "\f215"; } +.bi-calendar4-range::before { content: "\f216"; } +.bi-calendar4-week::before { content: "\f217"; } +.bi-calendar4::before { content: "\f218"; } +.bi-camera-fill::before { content: "\f219"; } +.bi-camera-reels-fill::before { content: "\f21a"; } +.bi-camera-reels::before { content: "\f21b"; } +.bi-camera-video-fill::before { content: "\f21c"; } +.bi-camera-video-off-fill::before { content: "\f21d"; } +.bi-camera-video-off::before { content: "\f21e"; } +.bi-camera-video::before { content: "\f21f"; } +.bi-camera::before { content: "\f220"; } +.bi-camera2::before { content: "\f221"; } +.bi-capslock-fill::before { content: "\f222"; } +.bi-capslock::before { content: "\f223"; } +.bi-card-checklist::before { content: "\f224"; } +.bi-card-heading::before { content: "\f225"; } +.bi-card-image::before { content: "\f226"; } +.bi-card-list::before { content: "\f227"; } +.bi-card-text::before { content: "\f228"; } +.bi-caret-down-fill::before { content: "\f229"; } +.bi-caret-down-square-fill::before { content: "\f22a"; } +.bi-caret-down-square::before { content: "\f22b"; } +.bi-caret-down::before { content: "\f22c"; } +.bi-caret-left-fill::before { content: "\f22d"; } +.bi-caret-left-square-fill::before { content: "\f22e"; } +.bi-caret-left-square::before { content: "\f22f"; } +.bi-caret-left::before { content: "\f230"; } +.bi-caret-right-fill::before { content: "\f231"; } +.bi-caret-right-square-fill::before { content: "\f232"; } +.bi-caret-right-square::before { content: "\f233"; } +.bi-caret-right::before { content: "\f234"; } +.bi-caret-up-fill::before { content: "\f235"; } +.bi-caret-up-square-fill::before { content: "\f236"; } +.bi-caret-up-square::before { content: "\f237"; } +.bi-caret-up::before { content: "\f238"; } +.bi-cart-check-fill::before { content: "\f239"; } +.bi-cart-check::before { content: "\f23a"; } +.bi-cart-dash-fill::before { content: "\f23b"; } +.bi-cart-dash::before { content: "\f23c"; } +.bi-cart-fill::before { content: "\f23d"; } +.bi-cart-plus-fill::before { content: "\f23e"; } +.bi-cart-plus::before { content: "\f23f"; } +.bi-cart-x-fill::before { content: "\f240"; } +.bi-cart-x::before { content: "\f241"; } +.bi-cart::before { content: "\f242"; } +.bi-cart2::before { content: "\f243"; } +.bi-cart3::before { content: "\f244"; } +.bi-cart4::before { content: "\f245"; } +.bi-cash-stack::before { content: "\f246"; } +.bi-cash::before { content: "\f247"; } +.bi-cast::before { content: "\f248"; } +.bi-chat-dots-fill::before { content: "\f249"; } +.bi-chat-dots::before { content: "\f24a"; } +.bi-chat-fill::before { content: "\f24b"; } +.bi-chat-left-dots-fill::before { content: "\f24c"; } +.bi-chat-left-dots::before { content: "\f24d"; } +.bi-chat-left-fill::before { content: "\f24e"; } +.bi-chat-left-quote-fill::before { content: "\f24f"; } +.bi-chat-left-quote::before { content: "\f250"; } +.bi-chat-left-text-fill::before { content: "\f251"; } +.bi-chat-left-text::before { content: "\f252"; } +.bi-chat-left::before { content: "\f253"; } +.bi-chat-quote-fill::before { content: "\f254"; } +.bi-chat-quote::before { content: "\f255"; } +.bi-chat-right-dots-fill::before { content: "\f256"; } +.bi-chat-right-dots::before { content: "\f257"; } +.bi-chat-right-fill::before { content: "\f258"; } +.bi-chat-right-quote-fill::before { content: "\f259"; } +.bi-chat-right-quote::before { content: "\f25a"; } +.bi-chat-right-text-fill::before { content: "\f25b"; } +.bi-chat-right-text::before { content: "\f25c"; } +.bi-chat-right::before { content: "\f25d"; } +.bi-chat-square-dots-fill::before { content: "\f25e"; } +.bi-chat-square-dots::before { content: "\f25f"; } +.bi-chat-square-fill::before { content: "\f260"; } +.bi-chat-square-quote-fill::before { content: "\f261"; } +.bi-chat-square-quote::before { content: "\f262"; } +.bi-chat-square-text-fill::before { content: "\f263"; } +.bi-chat-square-text::before { content: "\f264"; } +.bi-chat-square::before { content: "\f265"; } +.bi-chat-text-fill::before { content: "\f266"; } +.bi-chat-text::before { content: "\f267"; } +.bi-chat::before { content: "\f268"; } +.bi-check-all::before { content: "\f269"; } +.bi-check-circle-fill::before { content: "\f26a"; } +.bi-check-circle::before { content: "\f26b"; } +.bi-check-square-fill::before { content: "\f26c"; } +.bi-check-square::before { content: "\f26d"; } +.bi-check::before { content: "\f26e"; } +.bi-check2-all::before { content: "\f26f"; } +.bi-check2-circle::before { content: "\f270"; } +.bi-check2-square::before { content: "\f271"; } +.bi-check2::before { content: "\f272"; } +.bi-chevron-bar-contract::before { content: "\f273"; } +.bi-chevron-bar-down::before { content: "\f274"; } +.bi-chevron-bar-expand::before { content: "\f275"; } +.bi-chevron-bar-left::before { content: "\f276"; } +.bi-chevron-bar-right::before { content: "\f277"; } +.bi-chevron-bar-up::before { content: "\f278"; } +.bi-chevron-compact-down::before { content: "\f279"; } +.bi-chevron-compact-left::before { content: "\f27a"; } +.bi-chevron-compact-right::before { content: "\f27b"; } +.bi-chevron-compact-up::before { content: "\f27c"; } +.bi-chevron-contract::before { content: "\f27d"; } +.bi-chevron-double-down::before { content: "\f27e"; } +.bi-chevron-double-left::before { content: "\f27f"; } +.bi-chevron-double-right::before { content: "\f280"; } +.bi-chevron-double-up::before { content: "\f281"; } +.bi-chevron-down::before { content: "\f282"; } +.bi-chevron-expand::before { content: "\f283"; } +.bi-chevron-left::before { content: "\f284"; } +.bi-chevron-right::before { content: "\f285"; } +.bi-chevron-up::before { content: "\f286"; } +.bi-circle-fill::before { content: "\f287"; } +.bi-circle-half::before { content: "\f288"; } +.bi-circle-square::before { content: "\f289"; } +.bi-circle::before { content: "\f28a"; } +.bi-clipboard-check::before { content: "\f28b"; } +.bi-clipboard-data::before { content: "\f28c"; } +.bi-clipboard-minus::before { content: "\f28d"; } +.bi-clipboard-plus::before { content: "\f28e"; } +.bi-clipboard-x::before { content: "\f28f"; } +.bi-clipboard::before { content: "\f290"; } +.bi-clock-fill::before { content: "\f291"; } +.bi-clock-history::before { content: "\f292"; } +.bi-clock::before { content: "\f293"; } +.bi-cloud-arrow-down-fill::before { content: "\f294"; } +.bi-cloud-arrow-down::before { content: "\f295"; } +.bi-cloud-arrow-up-fill::before { content: "\f296"; } +.bi-cloud-arrow-up::before { content: "\f297"; } +.bi-cloud-check-fill::before { content: "\f298"; } +.bi-cloud-check::before { content: "\f299"; } +.bi-cloud-download-fill::before { content: "\f29a"; } +.bi-cloud-download::before { content: "\f29b"; } +.bi-cloud-drizzle-fill::before { content: "\f29c"; } +.bi-cloud-drizzle::before { content: "\f29d"; } +.bi-cloud-fill::before { content: "\f29e"; } +.bi-cloud-fog-fill::before { content: "\f29f"; } +.bi-cloud-fog::before { content: "\f2a0"; } +.bi-cloud-fog2-fill::before { content: "\f2a1"; } +.bi-cloud-fog2::before { content: "\f2a2"; } +.bi-cloud-hail-fill::before { content: "\f2a3"; } +.bi-cloud-hail::before { content: "\f2a4"; } +.bi-cloud-haze-fill::before { content: "\f2a6"; } +.bi-cloud-haze::before { content: "\f2a7"; } +.bi-cloud-haze2-fill::before { content: "\f2a8"; } +.bi-cloud-lightning-fill::before { content: "\f2a9"; } +.bi-cloud-lightning-rain-fill::before { content: "\f2aa"; } +.bi-cloud-lightning-rain::before { content: "\f2ab"; } +.bi-cloud-lightning::before { content: "\f2ac"; } +.bi-cloud-minus-fill::before { content: "\f2ad"; } +.bi-cloud-minus::before { content: "\f2ae"; } +.bi-cloud-moon-fill::before { content: "\f2af"; } +.bi-cloud-moon::before { content: "\f2b0"; } +.bi-cloud-plus-fill::before { content: "\f2b1"; } +.bi-cloud-plus::before { content: "\f2b2"; } +.bi-cloud-rain-fill::before { content: "\f2b3"; } +.bi-cloud-rain-heavy-fill::before { content: "\f2b4"; } +.bi-cloud-rain-heavy::before { content: "\f2b5"; } +.bi-cloud-rain::before { content: "\f2b6"; } +.bi-cloud-slash-fill::before { content: "\f2b7"; } +.bi-cloud-slash::before { content: "\f2b8"; } +.bi-cloud-sleet-fill::before { content: "\f2b9"; } +.bi-cloud-sleet::before { content: "\f2ba"; } +.bi-cloud-snow-fill::before { content: "\f2bb"; } +.bi-cloud-snow::before { content: "\f2bc"; } +.bi-cloud-sun-fill::before { content: "\f2bd"; } +.bi-cloud-sun::before { content: "\f2be"; } +.bi-cloud-upload-fill::before { content: "\f2bf"; } +.bi-cloud-upload::before { content: "\f2c0"; } +.bi-cloud::before { content: "\f2c1"; } +.bi-clouds-fill::before { content: "\f2c2"; } +.bi-clouds::before { content: "\f2c3"; } +.bi-cloudy-fill::before { content: "\f2c4"; } +.bi-cloudy::before { content: "\f2c5"; } +.bi-code-slash::before { content: "\f2c6"; } +.bi-code-square::before { content: "\f2c7"; } +.bi-code::before { content: "\f2c8"; } +.bi-collection-fill::before { content: "\f2c9"; } +.bi-collection-play-fill::before { content: "\f2ca"; } +.bi-collection-play::before { content: "\f2cb"; } +.bi-collection::before { content: "\f2cc"; } +.bi-columns-gap::before { content: "\f2cd"; } +.bi-columns::before { content: "\f2ce"; } +.bi-command::before { content: "\f2cf"; } +.bi-compass-fill::before { content: "\f2d0"; } +.bi-compass::before { content: "\f2d1"; } +.bi-cone-striped::before { content: "\f2d2"; } +.bi-cone::before { content: "\f2d3"; } +.bi-controller::before { content: "\f2d4"; } +.bi-cpu-fill::before { content: "\f2d5"; } +.bi-cpu::before { content: "\f2d6"; } +.bi-credit-card-2-back-fill::before { content: "\f2d7"; } +.bi-credit-card-2-back::before { content: "\f2d8"; } +.bi-credit-card-2-front-fill::before { content: "\f2d9"; } +.bi-credit-card-2-front::before { content: "\f2da"; } +.bi-credit-card-fill::before { content: "\f2db"; } +.bi-credit-card::before { content: "\f2dc"; } +.bi-crop::before { content: "\f2dd"; } +.bi-cup-fill::before { content: "\f2de"; } +.bi-cup-straw::before { content: "\f2df"; } +.bi-cup::before { content: "\f2e0"; } +.bi-cursor-fill::before { content: "\f2e1"; } +.bi-cursor-text::before { content: "\f2e2"; } +.bi-cursor::before { content: "\f2e3"; } +.bi-dash-circle-dotted::before { content: "\f2e4"; } +.bi-dash-circle-fill::before { content: "\f2e5"; } +.bi-dash-circle::before { content: "\f2e6"; } +.bi-dash-square-dotted::before { content: "\f2e7"; } +.bi-dash-square-fill::before { content: "\f2e8"; } +.bi-dash-square::before { content: "\f2e9"; } +.bi-dash::before { content: "\f2ea"; } +.bi-diagram-2-fill::before { content: "\f2eb"; } +.bi-diagram-2::before { content: "\f2ec"; } +.bi-diagram-3-fill::before { content: "\f2ed"; } +.bi-diagram-3::before { content: "\f2ee"; } +.bi-diamond-fill::before { content: "\f2ef"; } +.bi-diamond-half::before { content: "\f2f0"; } +.bi-diamond::before { content: "\f2f1"; } +.bi-dice-1-fill::before { content: "\f2f2"; } +.bi-dice-1::before { content: "\f2f3"; } +.bi-dice-2-fill::before { content: "\f2f4"; } +.bi-dice-2::before { content: "\f2f5"; } +.bi-dice-3-fill::before { content: "\f2f6"; } +.bi-dice-3::before { content: "\f2f7"; } +.bi-dice-4-fill::before { content: "\f2f8"; } +.bi-dice-4::before { content: "\f2f9"; } +.bi-dice-5-fill::before { content: "\f2fa"; } +.bi-dice-5::before { content: "\f2fb"; } +.bi-dice-6-fill::before { content: "\f2fc"; } +.bi-dice-6::before { content: "\f2fd"; } +.bi-disc-fill::before { content: "\f2fe"; } +.bi-disc::before { content: "\f2ff"; } +.bi-discord::before { content: "\f300"; } +.bi-display-fill::before { content: "\f301"; } +.bi-display::before { content: "\f302"; } +.bi-distribute-horizontal::before { content: "\f303"; } +.bi-distribute-vertical::before { content: "\f304"; } +.bi-door-closed-fill::before { content: "\f305"; } +.bi-door-closed::before { content: "\f306"; } +.bi-door-open-fill::before { content: "\f307"; } +.bi-door-open::before { content: "\f308"; } +.bi-dot::before { content: "\f309"; } +.bi-download::before { content: "\f30a"; } +.bi-droplet-fill::before { content: "\f30b"; } +.bi-droplet-half::before { content: "\f30c"; } +.bi-droplet::before { content: "\f30d"; } +.bi-earbuds::before { content: "\f30e"; } +.bi-easel-fill::before { content: "\f30f"; } +.bi-easel::before { content: "\f310"; } +.bi-egg-fill::before { content: "\f311"; } +.bi-egg-fried::before { content: "\f312"; } +.bi-egg::before { content: "\f313"; } +.bi-eject-fill::before { content: "\f314"; } +.bi-eject::before { content: "\f315"; } +.bi-emoji-angry-fill::before { content: "\f316"; } +.bi-emoji-angry::before { content: "\f317"; } +.bi-emoji-dizzy-fill::before { content: "\f318"; } +.bi-emoji-dizzy::before { content: "\f319"; } +.bi-emoji-expressionless-fill::before { content: "\f31a"; } +.bi-emoji-expressionless::before { content: "\f31b"; } +.bi-emoji-frown-fill::before { content: "\f31c"; } +.bi-emoji-frown::before { content: "\f31d"; } +.bi-emoji-heart-eyes-fill::before { content: "\f31e"; } +.bi-emoji-heart-eyes::before { content: "\f31f"; } +.bi-emoji-laughing-fill::before { content: "\f320"; } +.bi-emoji-laughing::before { content: "\f321"; } +.bi-emoji-neutral-fill::before { content: "\f322"; } +.bi-emoji-neutral::before { content: "\f323"; } +.bi-emoji-smile-fill::before { content: "\f324"; } +.bi-emoji-smile-upside-down-fill::before { content: "\f325"; } +.bi-emoji-smile-upside-down::before { content: "\f326"; } +.bi-emoji-smile::before { content: "\f327"; } +.bi-emoji-sunglasses-fill::before { content: "\f328"; } +.bi-emoji-sunglasses::before { content: "\f329"; } +.bi-emoji-wink-fill::before { content: "\f32a"; } +.bi-emoji-wink::before { content: "\f32b"; } +.bi-envelope-fill::before { content: "\f32c"; } +.bi-envelope-open-fill::before { content: "\f32d"; } +.bi-envelope-open::before { content: "\f32e"; } +.bi-envelope::before { content: "\f32f"; } +.bi-eraser-fill::before { content: "\f330"; } +.bi-eraser::before { content: "\f331"; } +.bi-exclamation-circle-fill::before { content: "\f332"; } +.bi-exclamation-circle::before { content: "\f333"; } +.bi-exclamation-diamond-fill::before { content: "\f334"; } +.bi-exclamation-diamond::before { content: "\f335"; } +.bi-exclamation-octagon-fill::before { content: "\f336"; } +.bi-exclamation-octagon::before { content: "\f337"; } +.bi-exclamation-square-fill::before { content: "\f338"; } +.bi-exclamation-square::before { content: "\f339"; } +.bi-exclamation-triangle-fill::before { content: "\f33a"; } +.bi-exclamation-triangle::before { content: "\f33b"; } +.bi-exclamation::before { content: "\f33c"; } +.bi-exclude::before { content: "\f33d"; } +.bi-eye-fill::before { content: "\f33e"; } +.bi-eye-slash-fill::before { content: "\f33f"; } +.bi-eye-slash::before { content: "\f340"; } +.bi-eye::before { content: "\f341"; } +.bi-eyedropper::before { content: "\f342"; } +.bi-eyeglasses::before { content: "\f343"; } +.bi-facebook::before { content: "\f344"; } +.bi-file-arrow-down-fill::before { content: "\f345"; } +.bi-file-arrow-down::before { content: "\f346"; } +.bi-file-arrow-up-fill::before { content: "\f347"; } +.bi-file-arrow-up::before { content: "\f348"; } +.bi-file-bar-graph-fill::before { content: "\f349"; } +.bi-file-bar-graph::before { content: "\f34a"; } +.bi-file-binary-fill::before { content: "\f34b"; } +.bi-file-binary::before { content: "\f34c"; } +.bi-file-break-fill::before { content: "\f34d"; } +.bi-file-break::before { content: "\f34e"; } +.bi-file-check-fill::before { content: "\f34f"; } +.bi-file-check::before { content: "\f350"; } +.bi-file-code-fill::before { content: "\f351"; } +.bi-file-code::before { content: "\f352"; } +.bi-file-diff-fill::before { content: "\f353"; } +.bi-file-diff::before { content: "\f354"; } +.bi-file-earmark-arrow-down-fill::before { content: "\f355"; } +.bi-file-earmark-arrow-down::before { content: "\f356"; } +.bi-file-earmark-arrow-up-fill::before { content: "\f357"; } +.bi-file-earmark-arrow-up::before { content: "\f358"; } +.bi-file-earmark-bar-graph-fill::before { content: "\f359"; } +.bi-file-earmark-bar-graph::before { content: "\f35a"; } +.bi-file-earmark-binary-fill::before { content: "\f35b"; } +.bi-file-earmark-binary::before { content: "\f35c"; } +.bi-file-earmark-break-fill::before { content: "\f35d"; } +.bi-file-earmark-break::before { content: "\f35e"; } +.bi-file-earmark-check-fill::before { content: "\f35f"; } +.bi-file-earmark-check::before { content: "\f360"; } +.bi-file-earmark-code-fill::before { content: "\f361"; } +.bi-file-earmark-code::before { content: "\f362"; } +.bi-file-earmark-diff-fill::before { content: "\f363"; } +.bi-file-earmark-diff::before { content: "\f364"; } +.bi-file-earmark-easel-fill::before { content: "\f365"; } +.bi-file-earmark-easel::before { content: "\f366"; } +.bi-file-earmark-excel-fill::before { content: "\f367"; } +.bi-file-earmark-excel::before { content: "\f368"; } +.bi-file-earmark-fill::before { content: "\f369"; } +.bi-file-earmark-font-fill::before { content: "\f36a"; } +.bi-file-earmark-font::before { content: "\f36b"; } +.bi-file-earmark-image-fill::before { content: "\f36c"; } +.bi-file-earmark-image::before { content: "\f36d"; } +.bi-file-earmark-lock-fill::before { content: "\f36e"; } +.bi-file-earmark-lock::before { content: "\f36f"; } +.bi-file-earmark-lock2-fill::before { content: "\f370"; } +.bi-file-earmark-lock2::before { content: "\f371"; } +.bi-file-earmark-medical-fill::before { content: "\f372"; } +.bi-file-earmark-medical::before { content: "\f373"; } +.bi-file-earmark-minus-fill::before { content: "\f374"; } +.bi-file-earmark-minus::before { content: "\f375"; } +.bi-file-earmark-music-fill::before { content: "\f376"; } +.bi-file-earmark-music::before { content: "\f377"; } +.bi-file-earmark-person-fill::before { content: "\f378"; } +.bi-file-earmark-person::before { content: "\f379"; } +.bi-file-earmark-play-fill::before { content: "\f37a"; } +.bi-file-earmark-play::before { content: "\f37b"; } +.bi-file-earmark-plus-fill::before { content: "\f37c"; } +.bi-file-earmark-plus::before { content: "\f37d"; } +.bi-file-earmark-post-fill::before { content: "\f37e"; } +.bi-file-earmark-post::before { content: "\f37f"; } +.bi-file-earmark-ppt-fill::before { content: "\f380"; } +.bi-file-earmark-ppt::before { content: "\f381"; } +.bi-file-earmark-richtext-fill::before { content: "\f382"; } +.bi-file-earmark-richtext::before { content: "\f383"; } +.bi-file-earmark-ruled-fill::before { content: "\f384"; } +.bi-file-earmark-ruled::before { content: "\f385"; } +.bi-file-earmark-slides-fill::before { content: "\f386"; } +.bi-file-earmark-slides::before { content: "\f387"; } +.bi-file-earmark-spreadsheet-fill::before { content: "\f388"; } +.bi-file-earmark-spreadsheet::before { content: "\f389"; } +.bi-file-earmark-text-fill::before { content: "\f38a"; } +.bi-file-earmark-text::before { content: "\f38b"; } +.bi-file-earmark-word-fill::before { content: "\f38c"; } +.bi-file-earmark-word::before { content: "\f38d"; } +.bi-file-earmark-x-fill::before { content: "\f38e"; } +.bi-file-earmark-x::before { content: "\f38f"; } +.bi-file-earmark-zip-fill::before { content: "\f390"; } +.bi-file-earmark-zip::before { content: "\f391"; } +.bi-file-earmark::before { content: "\f392"; } +.bi-file-easel-fill::before { content: "\f393"; } +.bi-file-easel::before { content: "\f394"; } +.bi-file-excel-fill::before { content: "\f395"; } +.bi-file-excel::before { content: "\f396"; } +.bi-file-fill::before { content: "\f397"; } +.bi-file-font-fill::before { content: "\f398"; } +.bi-file-font::before { content: "\f399"; } +.bi-file-image-fill::before { content: "\f39a"; } +.bi-file-image::before { content: "\f39b"; } +.bi-file-lock-fill::before { content: "\f39c"; } +.bi-file-lock::before { content: "\f39d"; } +.bi-file-lock2-fill::before { content: "\f39e"; } +.bi-file-lock2::before { content: "\f39f"; } +.bi-file-medical-fill::before { content: "\f3a0"; } +.bi-file-medical::before { content: "\f3a1"; } +.bi-file-minus-fill::before { content: "\f3a2"; } +.bi-file-minus::before { content: "\f3a3"; } +.bi-file-music-fill::before { content: "\f3a4"; } +.bi-file-music::before { content: "\f3a5"; } +.bi-file-person-fill::before { content: "\f3a6"; } +.bi-file-person::before { content: "\f3a7"; } +.bi-file-play-fill::before { content: "\f3a8"; } +.bi-file-play::before { content: "\f3a9"; } +.bi-file-plus-fill::before { content: "\f3aa"; } +.bi-file-plus::before { content: "\f3ab"; } +.bi-file-post-fill::before { content: "\f3ac"; } +.bi-file-post::before { content: "\f3ad"; } +.bi-file-ppt-fill::before { content: "\f3ae"; } +.bi-file-ppt::before { content: "\f3af"; } +.bi-file-richtext-fill::before { content: "\f3b0"; } +.bi-file-richtext::before { content: "\f3b1"; } +.bi-file-ruled-fill::before { content: "\f3b2"; } +.bi-file-ruled::before { content: "\f3b3"; } +.bi-file-slides-fill::before { content: "\f3b4"; } +.bi-file-slides::before { content: "\f3b5"; } +.bi-file-spreadsheet-fill::before { content: "\f3b6"; } +.bi-file-spreadsheet::before { content: "\f3b7"; } +.bi-file-text-fill::before { content: "\f3b8"; } +.bi-file-text::before { content: "\f3b9"; } +.bi-file-word-fill::before { content: "\f3ba"; } +.bi-file-word::before { content: "\f3bb"; } +.bi-file-x-fill::before { content: "\f3bc"; } +.bi-file-x::before { content: "\f3bd"; } +.bi-file-zip-fill::before { content: "\f3be"; } +.bi-file-zip::before { content: "\f3bf"; } +.bi-file::before { content: "\f3c0"; } +.bi-files-alt::before { content: "\f3c1"; } +.bi-files::before { content: "\f3c2"; } +.bi-film::before { content: "\f3c3"; } +.bi-filter-circle-fill::before { content: "\f3c4"; } +.bi-filter-circle::before { content: "\f3c5"; } +.bi-filter-left::before { content: "\f3c6"; } +.bi-filter-right::before { content: "\f3c7"; } +.bi-filter-square-fill::before { content: "\f3c8"; } +.bi-filter-square::before { content: "\f3c9"; } +.bi-filter::before { content: "\f3ca"; } +.bi-flag-fill::before { content: "\f3cb"; } +.bi-flag::before { content: "\f3cc"; } +.bi-flower1::before { content: "\f3cd"; } +.bi-flower2::before { content: "\f3ce"; } +.bi-flower3::before { content: "\f3cf"; } +.bi-folder-check::before { content: "\f3d0"; } +.bi-folder-fill::before { content: "\f3d1"; } +.bi-folder-minus::before { content: "\f3d2"; } +.bi-folder-plus::before { content: "\f3d3"; } +.bi-folder-symlink-fill::before { content: "\f3d4"; } +.bi-folder-symlink::before { content: "\f3d5"; } +.bi-folder-x::before { content: "\f3d6"; } +.bi-folder::before { content: "\f3d7"; } +.bi-folder2-open::before { content: "\f3d8"; } +.bi-folder2::before { content: "\f3d9"; } +.bi-fonts::before { content: "\f3da"; } +.bi-forward-fill::before { content: "\f3db"; } +.bi-forward::before { content: "\f3dc"; } +.bi-front::before { content: "\f3dd"; } +.bi-fullscreen-exit::before { content: "\f3de"; } +.bi-fullscreen::before { content: "\f3df"; } +.bi-funnel-fill::before { content: "\f3e0"; } +.bi-funnel::before { content: "\f3e1"; } +.bi-gear-fill::before { content: "\f3e2"; } +.bi-gear-wide-connected::before { content: "\f3e3"; } +.bi-gear-wide::before { content: "\f3e4"; } +.bi-gear::before { content: "\f3e5"; } +.bi-gem::before { content: "\f3e6"; } +.bi-geo-alt-fill::before { content: "\f3e7"; } +.bi-geo-alt::before { content: "\f3e8"; } +.bi-geo-fill::before { content: "\f3e9"; } +.bi-geo::before { content: "\f3ea"; } +.bi-gift-fill::before { content: "\f3eb"; } +.bi-gift::before { content: "\f3ec"; } +.bi-github::before { content: "\f3ed"; } +.bi-globe::before { content: "\f3ee"; } +.bi-globe2::before { content: "\f3ef"; } +.bi-google::before { content: "\f3f0"; } +.bi-graph-down::before { content: "\f3f1"; } +.bi-graph-up::before { content: "\f3f2"; } +.bi-grid-1x2-fill::before { content: "\f3f3"; } +.bi-grid-1x2::before { content: "\f3f4"; } +.bi-grid-3x2-gap-fill::before { content: "\f3f5"; } +.bi-grid-3x2-gap::before { content: "\f3f6"; } +.bi-grid-3x2::before { content: "\f3f7"; } +.bi-grid-3x3-gap-fill::before { content: "\f3f8"; } +.bi-grid-3x3-gap::before { content: "\f3f9"; } +.bi-grid-3x3::before { content: "\f3fa"; } +.bi-grid-fill::before { content: "\f3fb"; } +.bi-grid::before { content: "\f3fc"; } +.bi-grip-horizontal::before { content: "\f3fd"; } +.bi-grip-vertical::before { content: "\f3fe"; } +.bi-hammer::before { content: "\f3ff"; } +.bi-hand-index-fill::before { content: "\f400"; } +.bi-hand-index-thumb-fill::before { content: "\f401"; } +.bi-hand-index-thumb::before { content: "\f402"; } +.bi-hand-index::before { content: "\f403"; } +.bi-hand-thumbs-down-fill::before { content: "\f404"; } +.bi-hand-thumbs-down::before { content: "\f405"; } +.bi-hand-thumbs-up-fill::before { content: "\f406"; } +.bi-hand-thumbs-up::before { content: "\f407"; } +.bi-handbag-fill::before { content: "\f408"; } +.bi-handbag::before { content: "\f409"; } +.bi-hash::before { content: "\f40a"; } +.bi-hdd-fill::before { content: "\f40b"; } +.bi-hdd-network-fill::before { content: "\f40c"; } +.bi-hdd-network::before { content: "\f40d"; } +.bi-hdd-rack-fill::before { content: "\f40e"; } +.bi-hdd-rack::before { content: "\f40f"; } +.bi-hdd-stack-fill::before { content: "\f410"; } +.bi-hdd-stack::before { content: "\f411"; } +.bi-hdd::before { content: "\f412"; } +.bi-headphones::before { content: "\f413"; } +.bi-headset::before { content: "\f414"; } +.bi-heart-fill::before { content: "\f415"; } +.bi-heart-half::before { content: "\f416"; } +.bi-heart::before { content: "\f417"; } +.bi-heptagon-fill::before { content: "\f418"; } +.bi-heptagon-half::before { content: "\f419"; } +.bi-heptagon::before { content: "\f41a"; } +.bi-hexagon-fill::before { content: "\f41b"; } +.bi-hexagon-half::before { content: "\f41c"; } +.bi-hexagon::before { content: "\f41d"; } +.bi-hourglass-bottom::before { content: "\f41e"; } +.bi-hourglass-split::before { content: "\f41f"; } +.bi-hourglass-top::before { content: "\f420"; } +.bi-hourglass::before { content: "\f421"; } +.bi-house-door-fill::before { content: "\f422"; } +.bi-house-door::before { content: "\f423"; } +.bi-house-fill::before { content: "\f424"; } +.bi-house::before { content: "\f425"; } +.bi-hr::before { content: "\f426"; } +.bi-hurricane::before { content: "\f427"; } +.bi-image-alt::before { content: "\f428"; } +.bi-image-fill::before { content: "\f429"; } +.bi-image::before { content: "\f42a"; } +.bi-images::before { content: "\f42b"; } +.bi-inbox-fill::before { content: "\f42c"; } +.bi-inbox::before { content: "\f42d"; } +.bi-inboxes-fill::before { content: "\f42e"; } +.bi-inboxes::before { content: "\f42f"; } +.bi-info-circle-fill::before { content: "\f430"; } +.bi-info-circle::before { content: "\f431"; } +.bi-info-square-fill::before { content: "\f432"; } +.bi-info-square::before { content: "\f433"; } +.bi-info::before { content: "\f434"; } +.bi-input-cursor-text::before { content: "\f435"; } +.bi-input-cursor::before { content: "\f436"; } +.bi-instagram::before { content: "\f437"; } +.bi-intersect::before { content: "\f438"; } +.bi-journal-album::before { content: "\f439"; } +.bi-journal-arrow-down::before { content: "\f43a"; } +.bi-journal-arrow-up::before { content: "\f43b"; } +.bi-journal-bookmark-fill::before { content: "\f43c"; } +.bi-journal-bookmark::before { content: "\f43d"; } +.bi-journal-check::before { content: "\f43e"; } +.bi-journal-code::before { content: "\f43f"; } +.bi-journal-medical::before { content: "\f440"; } +.bi-journal-minus::before { content: "\f441"; } +.bi-journal-plus::before { content: "\f442"; } +.bi-journal-richtext::before { content: "\f443"; } +.bi-journal-text::before { content: "\f444"; } +.bi-journal-x::before { content: "\f445"; } +.bi-journal::before { content: "\f446"; } +.bi-journals::before { content: "\f447"; } +.bi-joystick::before { content: "\f448"; } +.bi-justify-left::before { content: "\f449"; } +.bi-justify-right::before { content: "\f44a"; } +.bi-justify::before { content: "\f44b"; } +.bi-kanban-fill::before { content: "\f44c"; } +.bi-kanban::before { content: "\f44d"; } +.bi-key-fill::before { content: "\f44e"; } +.bi-key::before { content: "\f44f"; } +.bi-keyboard-fill::before { content: "\f450"; } +.bi-keyboard::before { content: "\f451"; } +.bi-ladder::before { content: "\f452"; } +.bi-lamp-fill::before { content: "\f453"; } +.bi-lamp::before { content: "\f454"; } +.bi-laptop-fill::before { content: "\f455"; } +.bi-laptop::before { content: "\f456"; } +.bi-layer-backward::before { content: "\f457"; } +.bi-layer-forward::before { content: "\f458"; } +.bi-layers-fill::before { content: "\f459"; } +.bi-layers-half::before { content: "\f45a"; } +.bi-layers::before { content: "\f45b"; } +.bi-layout-sidebar-inset-reverse::before { content: "\f45c"; } +.bi-layout-sidebar-inset::before { content: "\f45d"; } +.bi-layout-sidebar-reverse::before { content: "\f45e"; } +.bi-layout-sidebar::before { content: "\f45f"; } +.bi-layout-split::before { content: "\f460"; } +.bi-layout-text-sidebar-reverse::before { content: "\f461"; } +.bi-layout-text-sidebar::before { content: "\f462"; } +.bi-layout-text-window-reverse::before { content: "\f463"; } +.bi-layout-text-window::before { content: "\f464"; } +.bi-layout-three-columns::before { content: "\f465"; } +.bi-layout-wtf::before { content: "\f466"; } +.bi-life-preserver::before { content: "\f467"; } +.bi-lightbulb-fill::before { content: "\f468"; } +.bi-lightbulb-off-fill::before { content: "\f469"; } +.bi-lightbulb-off::before { content: "\f46a"; } +.bi-lightbulb::before { content: "\f46b"; } +.bi-lightning-charge-fill::before { content: "\f46c"; } +.bi-lightning-charge::before { content: "\f46d"; } +.bi-lightning-fill::before { content: "\f46e"; } +.bi-lightning::before { content: "\f46f"; } +.bi-link-45deg::before { content: "\f470"; } +.bi-link::before { content: "\f471"; } +.bi-linkedin::before { content: "\f472"; } +.bi-list-check::before { content: "\f473"; } +.bi-list-nested::before { content: "\f474"; } +.bi-list-ol::before { content: "\f475"; } +.bi-list-stars::before { content: "\f476"; } +.bi-list-task::before { content: "\f477"; } +.bi-list-ul::before { content: "\f478"; } +.bi-list::before { content: "\f479"; } +.bi-lock-fill::before { content: "\f47a"; } +.bi-lock::before { content: "\f47b"; } +.bi-mailbox::before { content: "\f47c"; } +.bi-mailbox2::before { content: "\f47d"; } +.bi-map-fill::before { content: "\f47e"; } +.bi-map::before { content: "\f47f"; } +.bi-markdown-fill::before { content: "\f480"; } +.bi-markdown::before { content: "\f481"; } +.bi-mask::before { content: "\f482"; } +.bi-megaphone-fill::before { content: "\f483"; } +.bi-megaphone::before { content: "\f484"; } +.bi-menu-app-fill::before { content: "\f485"; } +.bi-menu-app::before { content: "\f486"; } +.bi-menu-button-fill::before { content: "\f487"; } +.bi-menu-button-wide-fill::before { content: "\f488"; } +.bi-menu-button-wide::before { content: "\f489"; } +.bi-menu-button::before { content: "\f48a"; } +.bi-menu-down::before { content: "\f48b"; } +.bi-menu-up::before { content: "\f48c"; } +.bi-mic-fill::before { content: "\f48d"; } +.bi-mic-mute-fill::before { content: "\f48e"; } +.bi-mic-mute::before { content: "\f48f"; } +.bi-mic::before { content: "\f490"; } +.bi-minecart-loaded::before { content: "\f491"; } +.bi-minecart::before { content: "\f492"; } +.bi-moisture::before { content: "\f493"; } +.bi-moon-fill::before { content: "\f494"; } +.bi-moon-stars-fill::before { content: "\f495"; } +.bi-moon-stars::before { content: "\f496"; } +.bi-moon::before { content: "\f497"; } +.bi-mouse-fill::before { content: "\f498"; } +.bi-mouse::before { content: "\f499"; } +.bi-mouse2-fill::before { content: "\f49a"; } +.bi-mouse2::before { content: "\f49b"; } +.bi-mouse3-fill::before { content: "\f49c"; } +.bi-mouse3::before { content: "\f49d"; } +.bi-music-note-beamed::before { content: "\f49e"; } +.bi-music-note-list::before { content: "\f49f"; } +.bi-music-note::before { content: "\f4a0"; } +.bi-music-player-fill::before { content: "\f4a1"; } +.bi-music-player::before { content: "\f4a2"; } +.bi-newspaper::before { content: "\f4a3"; } +.bi-node-minus-fill::before { content: "\f4a4"; } +.bi-node-minus::before { content: "\f4a5"; } +.bi-node-plus-fill::before { content: "\f4a6"; } +.bi-node-plus::before { content: "\f4a7"; } +.bi-nut-fill::before { content: "\f4a8"; } +.bi-nut::before { content: "\f4a9"; } +.bi-octagon-fill::before { content: "\f4aa"; } +.bi-octagon-half::before { content: "\f4ab"; } +.bi-octagon::before { content: "\f4ac"; } +.bi-option::before { content: "\f4ad"; } +.bi-outlet::before { content: "\f4ae"; } +.bi-paint-bucket::before { content: "\f4af"; } +.bi-palette-fill::before { content: "\f4b0"; } +.bi-palette::before { content: "\f4b1"; } +.bi-palette2::before { content: "\f4b2"; } +.bi-paperclip::before { content: "\f4b3"; } +.bi-paragraph::before { content: "\f4b4"; } +.bi-patch-check-fill::before { content: "\f4b5"; } +.bi-patch-check::before { content: "\f4b6"; } +.bi-patch-exclamation-fill::before { content: "\f4b7"; } +.bi-patch-exclamation::before { content: "\f4b8"; } +.bi-patch-minus-fill::before { content: "\f4b9"; } +.bi-patch-minus::before { content: "\f4ba"; } +.bi-patch-plus-fill::before { content: "\f4bb"; } +.bi-patch-plus::before { content: "\f4bc"; } +.bi-patch-question-fill::before { content: "\f4bd"; } +.bi-patch-question::before { content: "\f4be"; } +.bi-pause-btn-fill::before { content: "\f4bf"; } +.bi-pause-btn::before { content: "\f4c0"; } +.bi-pause-circle-fill::before { content: "\f4c1"; } +.bi-pause-circle::before { content: "\f4c2"; } +.bi-pause-fill::before { content: "\f4c3"; } +.bi-pause::before { content: "\f4c4"; } +.bi-peace-fill::before { content: "\f4c5"; } +.bi-peace::before { content: "\f4c6"; } +.bi-pen-fill::before { content: "\f4c7"; } +.bi-pen::before { content: "\f4c8"; } +.bi-pencil-fill::before { content: "\f4c9"; } +.bi-pencil-square::before { content: "\f4ca"; } +.bi-pencil::before { content: "\f4cb"; } +.bi-pentagon-fill::before { content: "\f4cc"; } +.bi-pentagon-half::before { content: "\f4cd"; } +.bi-pentagon::before { content: "\f4ce"; } +.bi-people-fill::before { content: "\f4cf"; } +.bi-people::before { content: "\f4d0"; } +.bi-percent::before { content: "\f4d1"; } +.bi-person-badge-fill::before { content: "\f4d2"; } +.bi-person-badge::before { content: "\f4d3"; } +.bi-person-bounding-box::before { content: "\f4d4"; } +.bi-person-check-fill::before { content: "\f4d5"; } +.bi-person-check::before { content: "\f4d6"; } +.bi-person-circle::before { content: "\f4d7"; } +.bi-person-dash-fill::before { content: "\f4d8"; } +.bi-person-dash::before { content: "\f4d9"; } +.bi-person-fill::before { content: "\f4da"; } +.bi-person-lines-fill::before { content: "\f4db"; } +.bi-person-plus-fill::before { content: "\f4dc"; } +.bi-person-plus::before { content: "\f4dd"; } +.bi-person-square::before { content: "\f4de"; } +.bi-person-x-fill::before { content: "\f4df"; } +.bi-person-x::before { content: "\f4e0"; } +.bi-person::before { content: "\f4e1"; } +.bi-phone-fill::before { content: "\f4e2"; } +.bi-phone-landscape-fill::before { content: "\f4e3"; } +.bi-phone-landscape::before { content: "\f4e4"; } +.bi-phone-vibrate-fill::before { content: "\f4e5"; } +.bi-phone-vibrate::before { content: "\f4e6"; } +.bi-phone::before { content: "\f4e7"; } +.bi-pie-chart-fill::before { content: "\f4e8"; } +.bi-pie-chart::before { content: "\f4e9"; } +.bi-pin-angle-fill::before { content: "\f4ea"; } +.bi-pin-angle::before { content: "\f4eb"; } +.bi-pin-fill::before { content: "\f4ec"; } +.bi-pin::before { content: "\f4ed"; } +.bi-pip-fill::before { content: "\f4ee"; } +.bi-pip::before { content: "\f4ef"; } +.bi-play-btn-fill::before { content: "\f4f0"; } +.bi-play-btn::before { content: "\f4f1"; } +.bi-play-circle-fill::before { content: "\f4f2"; } +.bi-play-circle::before { content: "\f4f3"; } +.bi-play-fill::before { content: "\f4f4"; } +.bi-play::before { content: "\f4f5"; } +.bi-plug-fill::before { content: "\f4f6"; } +.bi-plug::before { content: "\f4f7"; } +.bi-plus-circle-dotted::before { content: "\f4f8"; } +.bi-plus-circle-fill::before { content: "\f4f9"; } +.bi-plus-circle::before { content: "\f4fa"; } +.bi-plus-square-dotted::before { content: "\f4fb"; } +.bi-plus-square-fill::before { content: "\f4fc"; } +.bi-plus-square::before { content: "\f4fd"; } +.bi-plus::before { content: "\f4fe"; } +.bi-power::before { content: "\f4ff"; } +.bi-printer-fill::before { content: "\f500"; } +.bi-printer::before { content: "\f501"; } +.bi-puzzle-fill::before { content: "\f502"; } +.bi-puzzle::before { content: "\f503"; } +.bi-question-circle-fill::before { content: "\f504"; } +.bi-question-circle::before { content: "\f505"; } +.bi-question-diamond-fill::before { content: "\f506"; } +.bi-question-diamond::before { content: "\f507"; } +.bi-question-octagon-fill::before { content: "\f508"; } +.bi-question-octagon::before { content: "\f509"; } +.bi-question-square-fill::before { content: "\f50a"; } +.bi-question-square::before { content: "\f50b"; } +.bi-question::before { content: "\f50c"; } +.bi-rainbow::before { content: "\f50d"; } +.bi-receipt-cutoff::before { content: "\f50e"; } +.bi-receipt::before { content: "\f50f"; } +.bi-reception-0::before { content: "\f510"; } +.bi-reception-1::before { content: "\f511"; } +.bi-reception-2::before { content: "\f512"; } +.bi-reception-3::before { content: "\f513"; } +.bi-reception-4::before { content: "\f514"; } +.bi-record-btn-fill::before { content: "\f515"; } +.bi-record-btn::before { content: "\f516"; } +.bi-record-circle-fill::before { content: "\f517"; } +.bi-record-circle::before { content: "\f518"; } +.bi-record-fill::before { content: "\f519"; } +.bi-record::before { content: "\f51a"; } +.bi-record2-fill::before { content: "\f51b"; } +.bi-record2::before { content: "\f51c"; } +.bi-reply-all-fill::before { content: "\f51d"; } +.bi-reply-all::before { content: "\f51e"; } +.bi-reply-fill::before { content: "\f51f"; } +.bi-reply::before { content: "\f520"; } +.bi-rss-fill::before { content: "\f521"; } +.bi-rss::before { content: "\f522"; } +.bi-rulers::before { content: "\f523"; } +.bi-save-fill::before { content: "\f524"; } +.bi-save::before { content: "\f525"; } +.bi-save2-fill::before { content: "\f526"; } +.bi-save2::before { content: "\f527"; } +.bi-scissors::before { content: "\f528"; } +.bi-screwdriver::before { content: "\f529"; } +.bi-search::before { content: "\f52a"; } +.bi-segmented-nav::before { content: "\f52b"; } +.bi-server::before { content: "\f52c"; } +.bi-share-fill::before { content: "\f52d"; } +.bi-share::before { content: "\f52e"; } +.bi-shield-check::before { content: "\f52f"; } +.bi-shield-exclamation::before { content: "\f530"; } +.bi-shield-fill-check::before { content: "\f531"; } +.bi-shield-fill-exclamation::before { content: "\f532"; } +.bi-shield-fill-minus::before { content: "\f533"; } +.bi-shield-fill-plus::before { content: "\f534"; } +.bi-shield-fill-x::before { content: "\f535"; } +.bi-shield-fill::before { content: "\f536"; } +.bi-shield-lock-fill::before { content: "\f537"; } +.bi-shield-lock::before { content: "\f538"; } +.bi-shield-minus::before { content: "\f539"; } +.bi-shield-plus::before { content: "\f53a"; } +.bi-shield-shaded::before { content: "\f53b"; } +.bi-shield-slash-fill::before { content: "\f53c"; } +.bi-shield-slash::before { content: "\f53d"; } +.bi-shield-x::before { content: "\f53e"; } +.bi-shield::before { content: "\f53f"; } +.bi-shift-fill::before { content: "\f540"; } +.bi-shift::before { content: "\f541"; } +.bi-shop-window::before { content: "\f542"; } +.bi-shop::before { content: "\f543"; } +.bi-shuffle::before { content: "\f544"; } +.bi-signpost-2-fill::before { content: "\f545"; } +.bi-signpost-2::before { content: "\f546"; } +.bi-signpost-fill::before { content: "\f547"; } +.bi-signpost-split-fill::before { content: "\f548"; } +.bi-signpost-split::before { content: "\f549"; } +.bi-signpost::before { content: "\f54a"; } +.bi-sim-fill::before { content: "\f54b"; } +.bi-sim::before { content: "\f54c"; } +.bi-skip-backward-btn-fill::before { content: "\f54d"; } +.bi-skip-backward-btn::before { content: "\f54e"; } +.bi-skip-backward-circle-fill::before { content: "\f54f"; } +.bi-skip-backward-circle::before { content: "\f550"; } +.bi-skip-backward-fill::before { content: "\f551"; } +.bi-skip-backward::before { content: "\f552"; } +.bi-skip-end-btn-fill::before { content: "\f553"; } +.bi-skip-end-btn::before { content: "\f554"; } +.bi-skip-end-circle-fill::before { content: "\f555"; } +.bi-skip-end-circle::before { content: "\f556"; } +.bi-skip-end-fill::before { content: "\f557"; } +.bi-skip-end::before { content: "\f558"; } +.bi-skip-forward-btn-fill::before { content: "\f559"; } +.bi-skip-forward-btn::before { content: "\f55a"; } +.bi-skip-forward-circle-fill::before { content: "\f55b"; } +.bi-skip-forward-circle::before { content: "\f55c"; } +.bi-skip-forward-fill::before { content: "\f55d"; } +.bi-skip-forward::before { content: "\f55e"; } +.bi-skip-start-btn-fill::before { content: "\f55f"; } +.bi-skip-start-btn::before { content: "\f560"; } +.bi-skip-start-circle-fill::before { content: "\f561"; } +.bi-skip-start-circle::before { content: "\f562"; } +.bi-skip-start-fill::before { content: "\f563"; } +.bi-skip-start::before { content: "\f564"; } +.bi-slack::before { content: "\f565"; } +.bi-slash-circle-fill::before { content: "\f566"; } +.bi-slash-circle::before { content: "\f567"; } +.bi-slash-square-fill::before { content: "\f568"; } +.bi-slash-square::before { content: "\f569"; } +.bi-slash::before { content: "\f56a"; } +.bi-sliders::before { content: "\f56b"; } +.bi-smartwatch::before { content: "\f56c"; } +.bi-snow::before { content: "\f56d"; } +.bi-snow2::before { content: "\f56e"; } +.bi-snow3::before { content: "\f56f"; } +.bi-sort-alpha-down-alt::before { content: "\f570"; } +.bi-sort-alpha-down::before { content: "\f571"; } +.bi-sort-alpha-up-alt::before { content: "\f572"; } +.bi-sort-alpha-up::before { content: "\f573"; } +.bi-sort-down-alt::before { content: "\f574"; } +.bi-sort-down::before { content: "\f575"; } +.bi-sort-numeric-down-alt::before { content: "\f576"; } +.bi-sort-numeric-down::before { content: "\f577"; } +.bi-sort-numeric-up-alt::before { content: "\f578"; } +.bi-sort-numeric-up::before { content: "\f579"; } +.bi-sort-up-alt::before { content: "\f57a"; } +.bi-sort-up::before { content: "\f57b"; } +.bi-soundwave::before { content: "\f57c"; } +.bi-speaker-fill::before { content: "\f57d"; } +.bi-speaker::before { content: "\f57e"; } +.bi-speedometer::before { content: "\f57f"; } +.bi-speedometer2::before { content: "\f580"; } +.bi-spellcheck::before { content: "\f581"; } +.bi-square-fill::before { content: "\f582"; } +.bi-square-half::before { content: "\f583"; } +.bi-square::before { content: "\f584"; } +.bi-stack::before { content: "\f585"; } +.bi-star-fill::before { content: "\f586"; } +.bi-star-half::before { content: "\f587"; } +.bi-star::before { content: "\f588"; } +.bi-stars::before { content: "\f589"; } +.bi-stickies-fill::before { content: "\f58a"; } +.bi-stickies::before { content: "\f58b"; } +.bi-sticky-fill::before { content: "\f58c"; } +.bi-sticky::before { content: "\f58d"; } +.bi-stop-btn-fill::before { content: "\f58e"; } +.bi-stop-btn::before { content: "\f58f"; } +.bi-stop-circle-fill::before { content: "\f590"; } +.bi-stop-circle::before { content: "\f591"; } +.bi-stop-fill::before { content: "\f592"; } +.bi-stop::before { content: "\f593"; } +.bi-stoplights-fill::before { content: "\f594"; } +.bi-stoplights::before { content: "\f595"; } +.bi-stopwatch-fill::before { content: "\f596"; } +.bi-stopwatch::before { content: "\f597"; } +.bi-subtract::before { content: "\f598"; } +.bi-suit-club-fill::before { content: "\f599"; } +.bi-suit-club::before { content: "\f59a"; } +.bi-suit-diamond-fill::before { content: "\f59b"; } +.bi-suit-diamond::before { content: "\f59c"; } +.bi-suit-heart-fill::before { content: "\f59d"; } +.bi-suit-heart::before { content: "\f59e"; } +.bi-suit-spade-fill::before { content: "\f59f"; } +.bi-suit-spade::before { content: "\f5a0"; } +.bi-sun-fill::before { content: "\f5a1"; } +.bi-sun::before { content: "\f5a2"; } +.bi-sunglasses::before { content: "\f5a3"; } +.bi-sunrise-fill::before { content: "\f5a4"; } +.bi-sunrise::before { content: "\f5a5"; } +.bi-sunset-fill::before { content: "\f5a6"; } +.bi-sunset::before { content: "\f5a7"; } +.bi-symmetry-horizontal::before { content: "\f5a8"; } +.bi-symmetry-vertical::before { content: "\f5a9"; } +.bi-table::before { content: "\f5aa"; } +.bi-tablet-fill::before { content: "\f5ab"; } +.bi-tablet-landscape-fill::before { content: "\f5ac"; } +.bi-tablet-landscape::before { content: "\f5ad"; } +.bi-tablet::before { content: "\f5ae"; } +.bi-tag-fill::before { content: "\f5af"; } +.bi-tag::before { content: "\f5b0"; } +.bi-tags-fill::before { content: "\f5b1"; } +.bi-tags::before { content: "\f5b2"; } +.bi-telegram::before { content: "\f5b3"; } +.bi-telephone-fill::before { content: "\f5b4"; } +.bi-telephone-forward-fill::before { content: "\f5b5"; } +.bi-telephone-forward::before { content: "\f5b6"; } +.bi-telephone-inbound-fill::before { content: "\f5b7"; } +.bi-telephone-inbound::before { content: "\f5b8"; } +.bi-telephone-minus-fill::before { content: "\f5b9"; } +.bi-telephone-minus::before { content: "\f5ba"; } +.bi-telephone-outbound-fill::before { content: "\f5bb"; } +.bi-telephone-outbound::before { content: "\f5bc"; } +.bi-telephone-plus-fill::before { content: "\f5bd"; } +.bi-telephone-plus::before { content: "\f5be"; } +.bi-telephone-x-fill::before { content: "\f5bf"; } +.bi-telephone-x::before { content: "\f5c0"; } +.bi-telephone::before { content: "\f5c1"; } +.bi-terminal-fill::before { content: "\f5c2"; } +.bi-terminal::before { content: "\f5c3"; } +.bi-text-center::before { content: "\f5c4"; } +.bi-text-indent-left::before { content: "\f5c5"; } +.bi-text-indent-right::before { content: "\f5c6"; } +.bi-text-left::before { content: "\f5c7"; } +.bi-text-paragraph::before { content: "\f5c8"; } +.bi-text-right::before { content: "\f5c9"; } +.bi-textarea-resize::before { content: "\f5ca"; } +.bi-textarea-t::before { content: "\f5cb"; } +.bi-textarea::before { content: "\f5cc"; } +.bi-thermometer-half::before { content: "\f5cd"; } +.bi-thermometer-high::before { content: "\f5ce"; } +.bi-thermometer-low::before { content: "\f5cf"; } +.bi-thermometer-snow::before { content: "\f5d0"; } +.bi-thermometer-sun::before { content: "\f5d1"; } +.bi-thermometer::before { content: "\f5d2"; } +.bi-three-dots-vertical::before { content: "\f5d3"; } +.bi-three-dots::before { content: "\f5d4"; } +.bi-toggle-off::before { content: "\f5d5"; } +.bi-toggle-on::before { content: "\f5d6"; } +.bi-toggle2-off::before { content: "\f5d7"; } +.bi-toggle2-on::before { content: "\f5d8"; } +.bi-toggles::before { content: "\f5d9"; } +.bi-toggles2::before { content: "\f5da"; } +.bi-tools::before { content: "\f5db"; } +.bi-tornado::before { content: "\f5dc"; } +.bi-trash-fill::before { content: "\f5dd"; } +.bi-trash::before { content: "\f5de"; } +.bi-trash2-fill::before { content: "\f5df"; } +.bi-trash2::before { content: "\f5e0"; } +.bi-tree-fill::before { content: "\f5e1"; } +.bi-tree::before { content: "\f5e2"; } +.bi-triangle-fill::before { content: "\f5e3"; } +.bi-triangle-half::before { content: "\f5e4"; } +.bi-triangle::before { content: "\f5e5"; } +.bi-trophy-fill::before { content: "\f5e6"; } +.bi-trophy::before { content: "\f5e7"; } +.bi-tropical-storm::before { content: "\f5e8"; } +.bi-truck-flatbed::before { content: "\f5e9"; } +.bi-truck::before { content: "\f5ea"; } +.bi-tsunami::before { content: "\f5eb"; } +.bi-tv-fill::before { content: "\f5ec"; } +.bi-tv::before { content: "\f5ed"; } +.bi-twitch::before { content: "\f5ee"; } +.bi-twitter::before { content: "\f5ef"; } +.bi-type-bold::before { content: "\f5f0"; } +.bi-type-h1::before { content: "\f5f1"; } +.bi-type-h2::before { content: "\f5f2"; } +.bi-type-h3::before { content: "\f5f3"; } +.bi-type-italic::before { content: "\f5f4"; } +.bi-type-strikethrough::before { content: "\f5f5"; } +.bi-type-underline::before { content: "\f5f6"; } +.bi-type::before { content: "\f5f7"; } +.bi-ui-checks-grid::before { content: "\f5f8"; } +.bi-ui-checks::before { content: "\f5f9"; } +.bi-ui-radios-grid::before { content: "\f5fa"; } +.bi-ui-radios::before { content: "\f5fb"; } +.bi-umbrella-fill::before { content: "\f5fc"; } +.bi-umbrella::before { content: "\f5fd"; } +.bi-union::before { content: "\f5fe"; } +.bi-unlock-fill::before { content: "\f5ff"; } +.bi-unlock::before { content: "\f600"; } +.bi-upc-scan::before { content: "\f601"; } +.bi-upc::before { content: "\f602"; } +.bi-upload::before { content: "\f603"; } +.bi-vector-pen::before { content: "\f604"; } +.bi-view-list::before { content: "\f605"; } +.bi-view-stacked::before { content: "\f606"; } +.bi-vinyl-fill::before { content: "\f607"; } +.bi-vinyl::before { content: "\f608"; } +.bi-voicemail::before { content: "\f609"; } +.bi-volume-down-fill::before { content: "\f60a"; } +.bi-volume-down::before { content: "\f60b"; } +.bi-volume-mute-fill::before { content: "\f60c"; } +.bi-volume-mute::before { content: "\f60d"; } +.bi-volume-off-fill::before { content: "\f60e"; } +.bi-volume-off::before { content: "\f60f"; } +.bi-volume-up-fill::before { content: "\f610"; } +.bi-volume-up::before { content: "\f611"; } +.bi-vr::before { content: "\f612"; } +.bi-wallet-fill::before { content: "\f613"; } +.bi-wallet::before { content: "\f614"; } +.bi-wallet2::before { content: "\f615"; } +.bi-watch::before { content: "\f616"; } +.bi-water::before { content: "\f617"; } +.bi-whatsapp::before { content: "\f618"; } +.bi-wifi-1::before { content: "\f619"; } +.bi-wifi-2::before { content: "\f61a"; } +.bi-wifi-off::before { content: "\f61b"; } +.bi-wifi::before { content: "\f61c"; } +.bi-wind::before { content: "\f61d"; } +.bi-window-dock::before { content: "\f61e"; } +.bi-window-sidebar::before { content: "\f61f"; } +.bi-window::before { content: "\f620"; } +.bi-wrench::before { content: "\f621"; } +.bi-x-circle-fill::before { content: "\f622"; } +.bi-x-circle::before { content: "\f623"; } +.bi-x-diamond-fill::before { content: "\f624"; } +.bi-x-diamond::before { content: "\f625"; } +.bi-x-octagon-fill::before { content: "\f626"; } +.bi-x-octagon::before { content: "\f627"; } +.bi-x-square-fill::before { content: "\f628"; } +.bi-x-square::before { content: "\f629"; } +.bi-x::before { content: "\f62a"; } +.bi-youtube::before { content: "\f62b"; } +.bi-zoom-in::before { content: "\f62c"; } +.bi-zoom-out::before { content: "\f62d"; } +.bi-bank::before { content: "\f62e"; } +.bi-bank2::before { content: "\f62f"; } +.bi-bell-slash-fill::before { content: "\f630"; } +.bi-bell-slash::before { content: "\f631"; } +.bi-cash-coin::before { content: "\f632"; } +.bi-check-lg::before { content: "\f633"; } +.bi-coin::before { content: "\f634"; } +.bi-currency-bitcoin::before { content: "\f635"; } +.bi-currency-dollar::before { content: "\f636"; } +.bi-currency-euro::before { content: "\f637"; } +.bi-currency-exchange::before { content: "\f638"; } +.bi-currency-pound::before { content: "\f639"; } +.bi-currency-yen::before { content: "\f63a"; } +.bi-dash-lg::before { content: "\f63b"; } +.bi-exclamation-lg::before { content: "\f63c"; } +.bi-file-earmark-pdf-fill::before { content: "\f63d"; } +.bi-file-earmark-pdf::before { content: "\f63e"; } +.bi-file-pdf-fill::before { content: "\f63f"; } +.bi-file-pdf::before { content: "\f640"; } +.bi-gender-ambiguous::before { content: "\f641"; } +.bi-gender-female::before { content: "\f642"; } +.bi-gender-male::before { content: "\f643"; } +.bi-gender-trans::before { content: "\f644"; } +.bi-headset-vr::before { content: "\f645"; } +.bi-info-lg::before { content: "\f646"; } +.bi-mastodon::before { content: "\f647"; } +.bi-messenger::before { content: "\f648"; } +.bi-piggy-bank-fill::before { content: "\f649"; } +.bi-piggy-bank::before { content: "\f64a"; } +.bi-pin-map-fill::before { content: "\f64b"; } +.bi-pin-map::before { content: "\f64c"; } +.bi-plus-lg::before { content: "\f64d"; } +.bi-question-lg::before { content: "\f64e"; } +.bi-recycle::before { content: "\f64f"; } +.bi-reddit::before { content: "\f650"; } +.bi-safe-fill::before { content: "\f651"; } +.bi-safe2-fill::before { content: "\f652"; } +.bi-safe2::before { content: "\f653"; } +.bi-sd-card-fill::before { content: "\f654"; } +.bi-sd-card::before { content: "\f655"; } +.bi-skype::before { content: "\f656"; } +.bi-slash-lg::before { content: "\f657"; } +.bi-translate::before { content: "\f658"; } +.bi-x-lg::before { content: "\f659"; } +.bi-safe::before { content: "\f65a"; } +.bi-apple::before { content: "\f65b"; } +.bi-microsoft::before { content: "\f65d"; } +.bi-windows::before { content: "\f65e"; } +.bi-behance::before { content: "\f65c"; } +.bi-dribbble::before { content: "\f65f"; } +.bi-line::before { content: "\f660"; } +.bi-medium::before { content: "\f661"; } +.bi-paypal::before { content: "\f662"; } +.bi-pinterest::before { content: "\f663"; } +.bi-signal::before { content: "\f664"; } +.bi-snapchat::before { content: "\f665"; } +.bi-spotify::before { content: "\f666"; } +.bi-stack-overflow::before { content: "\f667"; } +.bi-strava::before { content: "\f668"; } +.bi-wordpress::before { content: "\f669"; } +.bi-vimeo::before { content: "\f66a"; } +.bi-activity::before { content: "\f66b"; } +.bi-easel2-fill::before { content: "\f66c"; } +.bi-easel2::before { content: "\f66d"; } +.bi-easel3-fill::before { content: "\f66e"; } +.bi-easel3::before { content: "\f66f"; } +.bi-fan::before { content: "\f670"; } +.bi-fingerprint::before { content: "\f671"; } +.bi-graph-down-arrow::before { content: "\f672"; } +.bi-graph-up-arrow::before { content: "\f673"; } +.bi-hypnotize::before { content: "\f674"; } +.bi-magic::before { content: "\f675"; } +.bi-person-rolodex::before { content: "\f676"; } +.bi-person-video::before { content: "\f677"; } +.bi-person-video2::before { content: "\f678"; } +.bi-person-video3::before { content: "\f679"; } +.bi-person-workspace::before { content: "\f67a"; } +.bi-radioactive::before { content: "\f67b"; } +.bi-webcam-fill::before { content: "\f67c"; } +.bi-webcam::before { content: "\f67d"; } +.bi-yin-yang::before { content: "\f67e"; } +.bi-bandaid-fill::before { content: "\f680"; } +.bi-bandaid::before { content: "\f681"; } +.bi-bluetooth::before { content: "\f682"; } +.bi-body-text::before { content: "\f683"; } +.bi-boombox::before { content: "\f684"; } +.bi-boxes::before { content: "\f685"; } +.bi-dpad-fill::before { content: "\f686"; } +.bi-dpad::before { content: "\f687"; } +.bi-ear-fill::before { content: "\f688"; } +.bi-ear::before { content: "\f689"; } +.bi-envelope-check-fill::before { content: "\f68b"; } +.bi-envelope-check::before { content: "\f68c"; } +.bi-envelope-dash-fill::before { content: "\f68e"; } +.bi-envelope-dash::before { content: "\f68f"; } +.bi-envelope-exclamation-fill::before { content: "\f691"; } +.bi-envelope-exclamation::before { content: "\f692"; } +.bi-envelope-plus-fill::before { content: "\f693"; } +.bi-envelope-plus::before { content: "\f694"; } +.bi-envelope-slash-fill::before { content: "\f696"; } +.bi-envelope-slash::before { content: "\f697"; } +.bi-envelope-x-fill::before { content: "\f699"; } +.bi-envelope-x::before { content: "\f69a"; } +.bi-explicit-fill::before { content: "\f69b"; } +.bi-explicit::before { content: "\f69c"; } +.bi-git::before { content: "\f69d"; } +.bi-infinity::before { content: "\f69e"; } +.bi-list-columns-reverse::before { content: "\f69f"; } +.bi-list-columns::before { content: "\f6a0"; } +.bi-meta::before { content: "\f6a1"; } +.bi-nintendo-switch::before { content: "\f6a4"; } +.bi-pc-display-horizontal::before { content: "\f6a5"; } +.bi-pc-display::before { content: "\f6a6"; } +.bi-pc-horizontal::before { content: "\f6a7"; } +.bi-pc::before { content: "\f6a8"; } +.bi-playstation::before { content: "\f6a9"; } +.bi-plus-slash-minus::before { content: "\f6aa"; } +.bi-projector-fill::before { content: "\f6ab"; } +.bi-projector::before { content: "\f6ac"; } +.bi-qr-code-scan::before { content: "\f6ad"; } +.bi-qr-code::before { content: "\f6ae"; } +.bi-quora::before { content: "\f6af"; } +.bi-quote::before { content: "\f6b0"; } +.bi-robot::before { content: "\f6b1"; } +.bi-send-check-fill::before { content: "\f6b2"; } +.bi-send-check::before { content: "\f6b3"; } +.bi-send-dash-fill::before { content: "\f6b4"; } +.bi-send-dash::before { content: "\f6b5"; } +.bi-send-exclamation-fill::before { content: "\f6b7"; } +.bi-send-exclamation::before { content: "\f6b8"; } +.bi-send-fill::before { content: "\f6b9"; } +.bi-send-plus-fill::before { content: "\f6ba"; } +.bi-send-plus::before { content: "\f6bb"; } +.bi-send-slash-fill::before { content: "\f6bc"; } +.bi-send-slash::before { content: "\f6bd"; } +.bi-send-x-fill::before { content: "\f6be"; } +.bi-send-x::before { content: "\f6bf"; } +.bi-send::before { content: "\f6c0"; } +.bi-steam::before { content: "\f6c1"; } +.bi-terminal-dash::before { content: "\f6c3"; } +.bi-terminal-plus::before { content: "\f6c4"; } +.bi-terminal-split::before { content: "\f6c5"; } +.bi-ticket-detailed-fill::before { content: "\f6c6"; } +.bi-ticket-detailed::before { content: "\f6c7"; } +.bi-ticket-fill::before { content: "\f6c8"; } +.bi-ticket-perforated-fill::before { content: "\f6c9"; } +.bi-ticket-perforated::before { content: "\f6ca"; } +.bi-ticket::before { content: "\f6cb"; } +.bi-tiktok::before { content: "\f6cc"; } +.bi-window-dash::before { content: "\f6cd"; } +.bi-window-desktop::before { content: "\f6ce"; } +.bi-window-fullscreen::before { content: "\f6cf"; } +.bi-window-plus::before { content: "\f6d0"; } +.bi-window-split::before { content: "\f6d1"; } +.bi-window-stack::before { content: "\f6d2"; } +.bi-window-x::before { content: "\f6d3"; } +.bi-xbox::before { content: "\f6d4"; } +.bi-ethernet::before { content: "\f6d5"; } +.bi-hdmi-fill::before { content: "\f6d6"; } +.bi-hdmi::before { content: "\f6d7"; } +.bi-usb-c-fill::before { content: "\f6d8"; } +.bi-usb-c::before { content: "\f6d9"; } +.bi-usb-fill::before { content: "\f6da"; } +.bi-usb-plug-fill::before { content: "\f6db"; } +.bi-usb-plug::before { content: "\f6dc"; } +.bi-usb-symbol::before { content: "\f6dd"; } +.bi-usb::before { content: "\f6de"; } +.bi-boombox-fill::before { content: "\f6df"; } +.bi-displayport::before { content: "\f6e1"; } +.bi-gpu-card::before { content: "\f6e2"; } +.bi-memory::before { content: "\f6e3"; } +.bi-modem-fill::before { content: "\f6e4"; } +.bi-modem::before { content: "\f6e5"; } +.bi-motherboard-fill::before { content: "\f6e6"; } +.bi-motherboard::before { content: "\f6e7"; } +.bi-optical-audio-fill::before { content: "\f6e8"; } +.bi-optical-audio::before { content: "\f6e9"; } +.bi-pci-card::before { content: "\f6ea"; } +.bi-router-fill::before { content: "\f6eb"; } +.bi-router::before { content: "\f6ec"; } +.bi-thunderbolt-fill::before { content: "\f6ef"; } +.bi-thunderbolt::before { content: "\f6f0"; } +.bi-usb-drive-fill::before { content: "\f6f1"; } +.bi-usb-drive::before { content: "\f6f2"; } +.bi-usb-micro-fill::before { content: "\f6f3"; } +.bi-usb-micro::before { content: "\f6f4"; } +.bi-usb-mini-fill::before { content: "\f6f5"; } +.bi-usb-mini::before { content: "\f6f6"; } +.bi-cloud-haze2::before { content: "\f6f7"; } +.bi-device-hdd-fill::before { content: "\f6f8"; } +.bi-device-hdd::before { content: "\f6f9"; } +.bi-device-ssd-fill::before { content: "\f6fa"; } +.bi-device-ssd::before { content: "\f6fb"; } +.bi-displayport-fill::before { content: "\f6fc"; } +.bi-mortarboard-fill::before { content: "\f6fd"; } +.bi-mortarboard::before { content: "\f6fe"; } +.bi-terminal-x::before { content: "\f6ff"; } +.bi-arrow-through-heart-fill::before { content: "\f700"; } +.bi-arrow-through-heart::before { content: "\f701"; } +.bi-badge-sd-fill::before { content: "\f702"; } +.bi-badge-sd::before { content: "\f703"; } +.bi-bag-heart-fill::before { content: "\f704"; } +.bi-bag-heart::before { content: "\f705"; } +.bi-balloon-fill::before { content: "\f706"; } +.bi-balloon-heart-fill::before { content: "\f707"; } +.bi-balloon-heart::before { content: "\f708"; } +.bi-balloon::before { content: "\f709"; } +.bi-box2-fill::before { content: "\f70a"; } +.bi-box2-heart-fill::before { content: "\f70b"; } +.bi-box2-heart::before { content: "\f70c"; } +.bi-box2::before { content: "\f70d"; } +.bi-braces-asterisk::before { content: "\f70e"; } +.bi-calendar-heart-fill::before { content: "\f70f"; } +.bi-calendar-heart::before { content: "\f710"; } +.bi-calendar2-heart-fill::before { content: "\f711"; } +.bi-calendar2-heart::before { content: "\f712"; } +.bi-chat-heart-fill::before { content: "\f713"; } +.bi-chat-heart::before { content: "\f714"; } +.bi-chat-left-heart-fill::before { content: "\f715"; } +.bi-chat-left-heart::before { content: "\f716"; } +.bi-chat-right-heart-fill::before { content: "\f717"; } +.bi-chat-right-heart::before { content: "\f718"; } +.bi-chat-square-heart-fill::before { content: "\f719"; } +.bi-chat-square-heart::before { content: "\f71a"; } +.bi-clipboard-check-fill::before { content: "\f71b"; } +.bi-clipboard-data-fill::before { content: "\f71c"; } +.bi-clipboard-fill::before { content: "\f71d"; } +.bi-clipboard-heart-fill::before { content: "\f71e"; } +.bi-clipboard-heart::before { content: "\f71f"; } +.bi-clipboard-minus-fill::before { content: "\f720"; } +.bi-clipboard-plus-fill::before { content: "\f721"; } +.bi-clipboard-pulse::before { content: "\f722"; } +.bi-clipboard-x-fill::before { content: "\f723"; } +.bi-clipboard2-check-fill::before { content: "\f724"; } +.bi-clipboard2-check::before { content: "\f725"; } +.bi-clipboard2-data-fill::before { content: "\f726"; } +.bi-clipboard2-data::before { content: "\f727"; } +.bi-clipboard2-fill::before { content: "\f728"; } +.bi-clipboard2-heart-fill::before { content: "\f729"; } +.bi-clipboard2-heart::before { content: "\f72a"; } +.bi-clipboard2-minus-fill::before { content: "\f72b"; } +.bi-clipboard2-minus::before { content: "\f72c"; } +.bi-clipboard2-plus-fill::before { content: "\f72d"; } +.bi-clipboard2-plus::before { content: "\f72e"; } +.bi-clipboard2-pulse-fill::before { content: "\f72f"; } +.bi-clipboard2-pulse::before { content: "\f730"; } +.bi-clipboard2-x-fill::before { content: "\f731"; } +.bi-clipboard2-x::before { content: "\f732"; } +.bi-clipboard2::before { content: "\f733"; } +.bi-emoji-kiss-fill::before { content: "\f734"; } +.bi-emoji-kiss::before { content: "\f735"; } +.bi-envelope-heart-fill::before { content: "\f736"; } +.bi-envelope-heart::before { content: "\f737"; } +.bi-envelope-open-heart-fill::before { content: "\f738"; } +.bi-envelope-open-heart::before { content: "\f739"; } +.bi-envelope-paper-fill::before { content: "\f73a"; } +.bi-envelope-paper-heart-fill::before { content: "\f73b"; } +.bi-envelope-paper-heart::before { content: "\f73c"; } +.bi-envelope-paper::before { content: "\f73d"; } +.bi-filetype-aac::before { content: "\f73e"; } +.bi-filetype-ai::before { content: "\f73f"; } +.bi-filetype-bmp::before { content: "\f740"; } +.bi-filetype-cs::before { content: "\f741"; } +.bi-filetype-css::before { content: "\f742"; } +.bi-filetype-csv::before { content: "\f743"; } +.bi-filetype-doc::before { content: "\f744"; } +.bi-filetype-docx::before { content: "\f745"; } +.bi-filetype-exe::before { content: "\f746"; } +.bi-filetype-gif::before { content: "\f747"; } +.bi-filetype-heic::before { content: "\f748"; } +.bi-filetype-html::before { content: "\f749"; } +.bi-filetype-java::before { content: "\f74a"; } +.bi-filetype-jpg::before { content: "\f74b"; } +.bi-filetype-js::before { content: "\f74c"; } +.bi-filetype-jsx::before { content: "\f74d"; } +.bi-filetype-key::before { content: "\f74e"; } +.bi-filetype-m4p::before { content: "\f74f"; } +.bi-filetype-md::before { content: "\f750"; } +.bi-filetype-mdx::before { content: "\f751"; } +.bi-filetype-mov::before { content: "\f752"; } +.bi-filetype-mp3::before { content: "\f753"; } +.bi-filetype-mp4::before { content: "\f754"; } +.bi-filetype-otf::before { content: "\f755"; } +.bi-filetype-pdf::before { content: "\f756"; } +.bi-filetype-php::before { content: "\f757"; } +.bi-filetype-png::before { content: "\f758"; } +.bi-filetype-ppt::before { content: "\f75a"; } +.bi-filetype-psd::before { content: "\f75b"; } +.bi-filetype-py::before { content: "\f75c"; } +.bi-filetype-raw::before { content: "\f75d"; } +.bi-filetype-rb::before { content: "\f75e"; } +.bi-filetype-sass::before { content: "\f75f"; } +.bi-filetype-scss::before { content: "\f760"; } +.bi-filetype-sh::before { content: "\f761"; } +.bi-filetype-svg::before { content: "\f762"; } +.bi-filetype-tiff::before { content: "\f763"; } +.bi-filetype-tsx::before { content: "\f764"; } +.bi-filetype-ttf::before { content: "\f765"; } +.bi-filetype-txt::before { content: "\f766"; } +.bi-filetype-wav::before { content: "\f767"; } +.bi-filetype-woff::before { content: "\f768"; } +.bi-filetype-xls::before { content: "\f76a"; } +.bi-filetype-xml::before { content: "\f76b"; } +.bi-filetype-yml::before { content: "\f76c"; } +.bi-heart-arrow::before { content: "\f76d"; } +.bi-heart-pulse-fill::before { content: "\f76e"; } +.bi-heart-pulse::before { content: "\f76f"; } +.bi-heartbreak-fill::before { content: "\f770"; } +.bi-heartbreak::before { content: "\f771"; } +.bi-hearts::before { content: "\f772"; } +.bi-hospital-fill::before { content: "\f773"; } +.bi-hospital::before { content: "\f774"; } +.bi-house-heart-fill::before { content: "\f775"; } +.bi-house-heart::before { content: "\f776"; } +.bi-incognito::before { content: "\f777"; } +.bi-magnet-fill::before { content: "\f778"; } +.bi-magnet::before { content: "\f779"; } +.bi-person-heart::before { content: "\f77a"; } +.bi-person-hearts::before { content: "\f77b"; } +.bi-phone-flip::before { content: "\f77c"; } +.bi-plugin::before { content: "\f77d"; } +.bi-postage-fill::before { content: "\f77e"; } +.bi-postage-heart-fill::before { content: "\f77f"; } +.bi-postage-heart::before { content: "\f780"; } +.bi-postage::before { content: "\f781"; } +.bi-postcard-fill::before { content: "\f782"; } +.bi-postcard-heart-fill::before { content: "\f783"; } +.bi-postcard-heart::before { content: "\f784"; } +.bi-postcard::before { content: "\f785"; } +.bi-search-heart-fill::before { content: "\f786"; } +.bi-search-heart::before { content: "\f787"; } +.bi-sliders2-vertical::before { content: "\f788"; } +.bi-sliders2::before { content: "\f789"; } +.bi-trash3-fill::before { content: "\f78a"; } +.bi-trash3::before { content: "\f78b"; } +.bi-valentine::before { content: "\f78c"; } +.bi-valentine2::before { content: "\f78d"; } +.bi-wrench-adjustable-circle-fill::before { content: "\f78e"; } +.bi-wrench-adjustable-circle::before { content: "\f78f"; } +.bi-wrench-adjustable::before { content: "\f790"; } +.bi-filetype-json::before { content: "\f791"; } +.bi-filetype-pptx::before { content: "\f792"; } +.bi-filetype-xlsx::before { content: "\f793"; } +.bi-1-circle-fill::before { content: "\f796"; } +.bi-1-circle::before { content: "\f797"; } +.bi-1-square-fill::before { content: "\f798"; } +.bi-1-square::before { content: "\f799"; } +.bi-2-circle-fill::before { content: "\f79c"; } +.bi-2-circle::before { content: "\f79d"; } +.bi-2-square-fill::before { content: "\f79e"; } +.bi-2-square::before { content: "\f79f"; } +.bi-3-circle-fill::before { content: "\f7a2"; } +.bi-3-circle::before { content: "\f7a3"; } +.bi-3-square-fill::before { content: "\f7a4"; } +.bi-3-square::before { content: "\f7a5"; } +.bi-4-circle-fill::before { content: "\f7a8"; } +.bi-4-circle::before { content: "\f7a9"; } +.bi-4-square-fill::before { content: "\f7aa"; } +.bi-4-square::before { content: "\f7ab"; } +.bi-5-circle-fill::before { content: "\f7ae"; } +.bi-5-circle::before { content: "\f7af"; } +.bi-5-square-fill::before { content: "\f7b0"; } +.bi-5-square::before { content: "\f7b1"; } +.bi-6-circle-fill::before { content: "\f7b4"; } +.bi-6-circle::before { content: "\f7b5"; } +.bi-6-square-fill::before { content: "\f7b6"; } +.bi-6-square::before { content: "\f7b7"; } +.bi-7-circle-fill::before { content: "\f7ba"; } +.bi-7-circle::before { content: "\f7bb"; } +.bi-7-square-fill::before { content: "\f7bc"; } +.bi-7-square::before { content: "\f7bd"; } +.bi-8-circle-fill::before { content: "\f7c0"; } +.bi-8-circle::before { content: "\f7c1"; } +.bi-8-square-fill::before { content: "\f7c2"; } +.bi-8-square::before { content: "\f7c3"; } +.bi-9-circle-fill::before { content: "\f7c6"; } +.bi-9-circle::before { content: "\f7c7"; } +.bi-9-square-fill::before { content: "\f7c8"; } +.bi-9-square::before { content: "\f7c9"; } +.bi-airplane-engines-fill::before { content: "\f7ca"; } +.bi-airplane-engines::before { content: "\f7cb"; } +.bi-airplane-fill::before { content: "\f7cc"; } +.bi-airplane::before { content: "\f7cd"; } +.bi-alexa::before { content: "\f7ce"; } +.bi-alipay::before { content: "\f7cf"; } +.bi-android::before { content: "\f7d0"; } +.bi-android2::before { content: "\f7d1"; } +.bi-box-fill::before { content: "\f7d2"; } +.bi-box-seam-fill::before { content: "\f7d3"; } +.bi-browser-chrome::before { content: "\f7d4"; } +.bi-browser-edge::before { content: "\f7d5"; } +.bi-browser-firefox::before { content: "\f7d6"; } +.bi-browser-safari::before { content: "\f7d7"; } +.bi-c-circle-fill::before { content: "\f7da"; } +.bi-c-circle::before { content: "\f7db"; } +.bi-c-square-fill::before { content: "\f7dc"; } +.bi-c-square::before { content: "\f7dd"; } +.bi-capsule-pill::before { content: "\f7de"; } +.bi-capsule::before { content: "\f7df"; } +.bi-car-front-fill::before { content: "\f7e0"; } +.bi-car-front::before { content: "\f7e1"; } +.bi-cassette-fill::before { content: "\f7e2"; } +.bi-cassette::before { content: "\f7e3"; } +.bi-cc-circle-fill::before { content: "\f7e6"; } +.bi-cc-circle::before { content: "\f7e7"; } +.bi-cc-square-fill::before { content: "\f7e8"; } +.bi-cc-square::before { content: "\f7e9"; } +.bi-cup-hot-fill::before { content: "\f7ea"; } +.bi-cup-hot::before { content: "\f7eb"; } +.bi-currency-rupee::before { content: "\f7ec"; } +.bi-dropbox::before { content: "\f7ed"; } +.bi-escape::before { content: "\f7ee"; } +.bi-fast-forward-btn-fill::before { content: "\f7ef"; } +.bi-fast-forward-btn::before { content: "\f7f0"; } +.bi-fast-forward-circle-fill::before { content: "\f7f1"; } +.bi-fast-forward-circle::before { content: "\f7f2"; } +.bi-fast-forward-fill::before { content: "\f7f3"; } +.bi-fast-forward::before { content: "\f7f4"; } +.bi-filetype-sql::before { content: "\f7f5"; } +.bi-fire::before { content: "\f7f6"; } +.bi-google-play::before { content: "\f7f7"; } +.bi-h-circle-fill::before { content: "\f7fa"; } +.bi-h-circle::before { content: "\f7fb"; } +.bi-h-square-fill::before { content: "\f7fc"; } +.bi-h-square::before { content: "\f7fd"; } +.bi-indent::before { content: "\f7fe"; } +.bi-lungs-fill::before { content: "\f7ff"; } +.bi-lungs::before { content: "\f800"; } +.bi-microsoft-teams::before { content: "\f801"; } +.bi-p-circle-fill::before { content: "\f804"; } +.bi-p-circle::before { content: "\f805"; } +.bi-p-square-fill::before { content: "\f806"; } +.bi-p-square::before { content: "\f807"; } +.bi-pass-fill::before { content: "\f808"; } +.bi-pass::before { content: "\f809"; } +.bi-prescription::before { content: "\f80a"; } +.bi-prescription2::before { content: "\f80b"; } +.bi-r-circle-fill::before { content: "\f80e"; } +.bi-r-circle::before { content: "\f80f"; } +.bi-r-square-fill::before { content: "\f810"; } +.bi-r-square::before { content: "\f811"; } +.bi-repeat-1::before { content: "\f812"; } +.bi-repeat::before { content: "\f813"; } +.bi-rewind-btn-fill::before { content: "\f814"; } +.bi-rewind-btn::before { content: "\f815"; } +.bi-rewind-circle-fill::before { content: "\f816"; } +.bi-rewind-circle::before { content: "\f817"; } +.bi-rewind-fill::before { content: "\f818"; } +.bi-rewind::before { content: "\f819"; } +.bi-train-freight-front-fill::before { content: "\f81a"; } +.bi-train-freight-front::before { content: "\f81b"; } +.bi-train-front-fill::before { content: "\f81c"; } +.bi-train-front::before { content: "\f81d"; } +.bi-train-lightrail-front-fill::before { content: "\f81e"; } +.bi-train-lightrail-front::before { content: "\f81f"; } +.bi-truck-front-fill::before { content: "\f820"; } +.bi-truck-front::before { content: "\f821"; } +.bi-ubuntu::before { content: "\f822"; } +.bi-unindent::before { content: "\f823"; } +.bi-unity::before { content: "\f824"; } +.bi-universal-access-circle::before { content: "\f825"; } +.bi-universal-access::before { content: "\f826"; } +.bi-virus::before { content: "\f827"; } +.bi-virus2::before { content: "\f828"; } +.bi-wechat::before { content: "\f829"; } +.bi-yelp::before { content: "\f82a"; } +.bi-sign-stop-fill::before { content: "\f82b"; } +.bi-sign-stop-lights-fill::before { content: "\f82c"; } +.bi-sign-stop-lights::before { content: "\f82d"; } +.bi-sign-stop::before { content: "\f82e"; } +.bi-sign-turn-left-fill::before { content: "\f82f"; } +.bi-sign-turn-left::before { content: "\f830"; } +.bi-sign-turn-right-fill::before { content: "\f831"; } +.bi-sign-turn-right::before { content: "\f832"; } +.bi-sign-turn-slight-left-fill::before { content: "\f833"; } +.bi-sign-turn-slight-left::before { content: "\f834"; } +.bi-sign-turn-slight-right-fill::before { content: "\f835"; } +.bi-sign-turn-slight-right::before { content: "\f836"; } +.bi-sign-yield-fill::before { content: "\f837"; } +.bi-sign-yield::before { content: "\f838"; } +.bi-ev-station-fill::before { content: "\f839"; } +.bi-ev-station::before { content: "\f83a"; } +.bi-fuel-pump-diesel-fill::before { content: "\f83b"; } +.bi-fuel-pump-diesel::before { content: "\f83c"; } +.bi-fuel-pump-fill::before { content: "\f83d"; } +.bi-fuel-pump::before { content: "\f83e"; } +.bi-0-circle-fill::before { content: "\f83f"; } +.bi-0-circle::before { content: "\f840"; } +.bi-0-square-fill::before { content: "\f841"; } +.bi-0-square::before { content: "\f842"; } +.bi-rocket-fill::before { content: "\f843"; } +.bi-rocket-takeoff-fill::before { content: "\f844"; } +.bi-rocket-takeoff::before { content: "\f845"; } +.bi-rocket::before { content: "\f846"; } +.bi-stripe::before { content: "\f847"; } +.bi-subscript::before { content: "\f848"; } +.bi-superscript::before { content: "\f849"; } +.bi-trello::before { content: "\f84a"; } +.bi-envelope-at-fill::before { content: "\f84b"; } +.bi-envelope-at::before { content: "\f84c"; } +.bi-regex::before { content: "\f84d"; } +.bi-text-wrap::before { content: "\f84e"; } +.bi-sign-dead-end-fill::before { content: "\f84f"; } +.bi-sign-dead-end::before { content: "\f850"; } +.bi-sign-do-not-enter-fill::before { content: "\f851"; } +.bi-sign-do-not-enter::before { content: "\f852"; } +.bi-sign-intersection-fill::before { content: "\f853"; } +.bi-sign-intersection-side-fill::before { content: "\f854"; } +.bi-sign-intersection-side::before { content: "\f855"; } +.bi-sign-intersection-t-fill::before { content: "\f856"; } +.bi-sign-intersection-t::before { content: "\f857"; } +.bi-sign-intersection-y-fill::before { content: "\f858"; } +.bi-sign-intersection-y::before { content: "\f859"; } +.bi-sign-intersection::before { content: "\f85a"; } +.bi-sign-merge-left-fill::before { content: "\f85b"; } +.bi-sign-merge-left::before { content: "\f85c"; } +.bi-sign-merge-right-fill::before { content: "\f85d"; } +.bi-sign-merge-right::before { content: "\f85e"; } +.bi-sign-no-left-turn-fill::before { content: "\f85f"; } +.bi-sign-no-left-turn::before { content: "\f860"; } +.bi-sign-no-parking-fill::before { content: "\f861"; } +.bi-sign-no-parking::before { content: "\f862"; } +.bi-sign-no-right-turn-fill::before { content: "\f863"; } +.bi-sign-no-right-turn::before { content: "\f864"; } +.bi-sign-railroad-fill::before { content: "\f865"; } +.bi-sign-railroad::before { content: "\f866"; } +.bi-building-add::before { content: "\f867"; } +.bi-building-check::before { content: "\f868"; } +.bi-building-dash::before { content: "\f869"; } +.bi-building-down::before { content: "\f86a"; } +.bi-building-exclamation::before { content: "\f86b"; } +.bi-building-fill-add::before { content: "\f86c"; } +.bi-building-fill-check::before { content: "\f86d"; } +.bi-building-fill-dash::before { content: "\f86e"; } +.bi-building-fill-down::before { content: "\f86f"; } +.bi-building-fill-exclamation::before { content: "\f870"; } +.bi-building-fill-gear::before { content: "\f871"; } +.bi-building-fill-lock::before { content: "\f872"; } +.bi-building-fill-slash::before { content: "\f873"; } +.bi-building-fill-up::before { content: "\f874"; } +.bi-building-fill-x::before { content: "\f875"; } +.bi-building-fill::before { content: "\f876"; } +.bi-building-gear::before { content: "\f877"; } +.bi-building-lock::before { content: "\f878"; } +.bi-building-slash::before { content: "\f879"; } +.bi-building-up::before { content: "\f87a"; } +.bi-building-x::before { content: "\f87b"; } +.bi-buildings-fill::before { content: "\f87c"; } +.bi-buildings::before { content: "\f87d"; } +.bi-bus-front-fill::before { content: "\f87e"; } +.bi-bus-front::before { content: "\f87f"; } +.bi-ev-front-fill::before { content: "\f880"; } +.bi-ev-front::before { content: "\f881"; } +.bi-globe-americas::before { content: "\f882"; } +.bi-globe-asia-australia::before { content: "\f883"; } +.bi-globe-central-south-asia::before { content: "\f884"; } +.bi-globe-europe-africa::before { content: "\f885"; } +.bi-house-add-fill::before { content: "\f886"; } +.bi-house-add::before { content: "\f887"; } +.bi-house-check-fill::before { content: "\f888"; } +.bi-house-check::before { content: "\f889"; } +.bi-house-dash-fill::before { content: "\f88a"; } +.bi-house-dash::before { content: "\f88b"; } +.bi-house-down-fill::before { content: "\f88c"; } +.bi-house-down::before { content: "\f88d"; } +.bi-house-exclamation-fill::before { content: "\f88e"; } +.bi-house-exclamation::before { content: "\f88f"; } +.bi-house-gear-fill::before { content: "\f890"; } +.bi-house-gear::before { content: "\f891"; } +.bi-house-lock-fill::before { content: "\f892"; } +.bi-house-lock::before { content: "\f893"; } +.bi-house-slash-fill::before { content: "\f894"; } +.bi-house-slash::before { content: "\f895"; } +.bi-house-up-fill::before { content: "\f896"; } +.bi-house-up::before { content: "\f897"; } +.bi-house-x-fill::before { content: "\f898"; } +.bi-house-x::before { content: "\f899"; } +.bi-person-add::before { content: "\f89a"; } +.bi-person-down::before { content: "\f89b"; } +.bi-person-exclamation::before { content: "\f89c"; } +.bi-person-fill-add::before { content: "\f89d"; } +.bi-person-fill-check::before { content: "\f89e"; } +.bi-person-fill-dash::before { content: "\f89f"; } +.bi-person-fill-down::before { content: "\f8a0"; } +.bi-person-fill-exclamation::before { content: "\f8a1"; } +.bi-person-fill-gear::before { content: "\f8a2"; } +.bi-person-fill-lock::before { content: "\f8a3"; } +.bi-person-fill-slash::before { content: "\f8a4"; } +.bi-person-fill-up::before { content: "\f8a5"; } +.bi-person-fill-x::before { content: "\f8a6"; } +.bi-person-gear::before { content: "\f8a7"; } +.bi-person-lock::before { content: "\f8a8"; } +.bi-person-slash::before { content: "\f8a9"; } +.bi-person-up::before { content: "\f8aa"; } +.bi-scooter::before { content: "\f8ab"; } +.bi-taxi-front-fill::before { content: "\f8ac"; } +.bi-taxi-front::before { content: "\f8ad"; } +.bi-amd::before { content: "\f8ae"; } +.bi-database-add::before { content: "\f8af"; } +.bi-database-check::before { content: "\f8b0"; } +.bi-database-dash::before { content: "\f8b1"; } +.bi-database-down::before { content: "\f8b2"; } +.bi-database-exclamation::before { content: "\f8b3"; } +.bi-database-fill-add::before { content: "\f8b4"; } +.bi-database-fill-check::before { content: "\f8b5"; } +.bi-database-fill-dash::before { content: "\f8b6"; } +.bi-database-fill-down::before { content: "\f8b7"; } +.bi-database-fill-exclamation::before { content: "\f8b8"; } +.bi-database-fill-gear::before { content: "\f8b9"; } +.bi-database-fill-lock::before { content: "\f8ba"; } +.bi-database-fill-slash::before { content: "\f8bb"; } +.bi-database-fill-up::before { content: "\f8bc"; } +.bi-database-fill-x::before { content: "\f8bd"; } +.bi-database-fill::before { content: "\f8be"; } +.bi-database-gear::before { content: "\f8bf"; } +.bi-database-lock::before { content: "\f8c0"; } +.bi-database-slash::before { content: "\f8c1"; } +.bi-database-up::before { content: "\f8c2"; } +.bi-database-x::before { content: "\f8c3"; } +.bi-database::before { content: "\f8c4"; } +.bi-houses-fill::before { content: "\f8c5"; } +.bi-houses::before { content: "\f8c6"; } +.bi-nvidia::before { content: "\f8c7"; } +.bi-person-vcard-fill::before { content: "\f8c8"; } +.bi-person-vcard::before { content: "\f8c9"; } +.bi-sina-weibo::before { content: "\f8ca"; } +.bi-tencent-qq::before { content: "\f8cb"; } +.bi-wikipedia::before { content: "\f8cc"; } +.bi-alphabet-uppercase::before { content: "\f2a5"; } +.bi-alphabet::before { content: "\f68a"; } +.bi-amazon::before { content: "\f68d"; } +.bi-arrows-collapse-vertical::before { content: "\f690"; } +.bi-arrows-expand-vertical::before { content: "\f695"; } +.bi-arrows-vertical::before { content: "\f698"; } +.bi-arrows::before { content: "\f6a2"; } +.bi-ban-fill::before { content: "\f6a3"; } +.bi-ban::before { content: "\f6b6"; } +.bi-bing::before { content: "\f6c2"; } +.bi-cake::before { content: "\f6e0"; } +.bi-cake2::before { content: "\f6ed"; } +.bi-cookie::before { content: "\f6ee"; } +.bi-copy::before { content: "\f759"; } +.bi-crosshair::before { content: "\f769"; } +.bi-crosshair2::before { content: "\f794"; } +.bi-emoji-astonished-fill::before { content: "\f795"; } +.bi-emoji-astonished::before { content: "\f79a"; } +.bi-emoji-grimace-fill::before { content: "\f79b"; } +.bi-emoji-grimace::before { content: "\f7a0"; } +.bi-emoji-grin-fill::before { content: "\f7a1"; } +.bi-emoji-grin::before { content: "\f7a6"; } +.bi-emoji-surprise-fill::before { content: "\f7a7"; } +.bi-emoji-surprise::before { content: "\f7ac"; } +.bi-emoji-tear-fill::before { content: "\f7ad"; } +.bi-emoji-tear::before { content: "\f7b2"; } +.bi-envelope-arrow-down-fill::before { content: "\f7b3"; } +.bi-envelope-arrow-down::before { content: "\f7b8"; } +.bi-envelope-arrow-up-fill::before { content: "\f7b9"; } +.bi-envelope-arrow-up::before { content: "\f7be"; } +.bi-feather::before { content: "\f7bf"; } +.bi-feather2::before { content: "\f7c4"; } +.bi-floppy-fill::before { content: "\f7c5"; } +.bi-floppy::before { content: "\f7d8"; } +.bi-floppy2-fill::before { content: "\f7d9"; } +.bi-floppy2::before { content: "\f7e4"; } +.bi-gitlab::before { content: "\f7e5"; } +.bi-highlighter::before { content: "\f7f8"; } +.bi-marker-tip::before { content: "\f802"; } +.bi-nvme-fill::before { content: "\f803"; } +.bi-nvme::before { content: "\f80c"; } +.bi-opencollective::before { content: "\f80d"; } +.bi-pci-card-network::before { content: "\f8cd"; } +.bi-pci-card-sound::before { content: "\f8ce"; } +.bi-radar::before { content: "\f8cf"; } +.bi-send-arrow-down-fill::before { content: "\f8d0"; } +.bi-send-arrow-down::before { content: "\f8d1"; } +.bi-send-arrow-up-fill::before { content: "\f8d2"; } +.bi-send-arrow-up::before { content: "\f8d3"; } +.bi-sim-slash-fill::before { content: "\f8d4"; } +.bi-sim-slash::before { content: "\f8d5"; } +.bi-sourceforge::before { content: "\f8d6"; } +.bi-substack::before { content: "\f8d7"; } +.bi-threads-fill::before { content: "\f8d8"; } +.bi-threads::before { content: "\f8d9"; } +.bi-transparency::before { content: "\f8da"; } +.bi-twitter-x::before { content: "\f8db"; } +.bi-type-h4::before { content: "\f8dc"; } +.bi-type-h5::before { content: "\f8dd"; } +.bi-type-h6::before { content: "\f8de"; } +.bi-backpack-fill::before { content: "\f8df"; } +.bi-backpack::before { content: "\f8e0"; } +.bi-backpack2-fill::before { content: "\f8e1"; } +.bi-backpack2::before { content: "\f8e2"; } +.bi-backpack3-fill::before { content: "\f8e3"; } +.bi-backpack3::before { content: "\f8e4"; } +.bi-backpack4-fill::before { content: "\f8e5"; } +.bi-backpack4::before { content: "\f8e6"; } +.bi-brilliance::before { content: "\f8e7"; } +.bi-cake-fill::before { content: "\f8e8"; } +.bi-cake2-fill::before { content: "\f8e9"; } +.bi-duffle-fill::before { content: "\f8ea"; } +.bi-duffle::before { content: "\f8eb"; } +.bi-exposure::before { content: "\f8ec"; } +.bi-gender-neuter::before { content: "\f8ed"; } +.bi-highlights::before { content: "\f8ee"; } +.bi-luggage-fill::before { content: "\f8ef"; } +.bi-luggage::before { content: "\f8f0"; } +.bi-mailbox-flag::before { content: "\f8f1"; } +.bi-mailbox2-flag::before { content: "\f8f2"; } +.bi-noise-reduction::before { content: "\f8f3"; } +.bi-passport-fill::before { content: "\f8f4"; } +.bi-passport::before { content: "\f8f5"; } +.bi-person-arms-up::before { content: "\f8f6"; } +.bi-person-raised-hand::before { content: "\f8f7"; } +.bi-person-standing-dress::before { content: "\f8f8"; } +.bi-person-standing::before { content: "\f8f9"; } +.bi-person-walking::before { content: "\f8fa"; } +.bi-person-wheelchair::before { content: "\f8fb"; } +.bi-shadows::before { content: "\f8fc"; } +.bi-suitcase-fill::before { content: "\f8fd"; } +.bi-suitcase-lg-fill::before { content: "\f8fe"; } +.bi-suitcase-lg::before { content: "\f8ff"; } +.bi-suitcase::before { content: "\f900"; } +.bi-suitcase2-fill::before { content: "\f901"; } +.bi-suitcase2::before { content: "\f902"; } +.bi-vignette::before { content: "\f903"; } diff --git a/site_libs/bootstrap/bootstrap-icons.woff b/site_libs/bootstrap/bootstrap-icons.woff new file mode 100644 index 0000000000000000000000000000000000000000..dbeeb055674125ad78fda0f3d166b36e5cc92336 GIT binary patch literal 176200 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

2+UrCZlNAp`)&G@jg{m-!Dn; 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πR(XEyYV3az{Ot$Y*f93mYq^Lnu{qbYp!X!TA9&! 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 F?~0aZ)an2L literal 0 HcmV?d00001 diff --git a/site_libs/bootstrap/bootstrap.min.css b/site_libs/bootstrap/bootstrap.min.css new file mode 100644 index 0000000..ac53fd3 --- /dev/null +++ b/site_libs/bootstrap/bootstrap.min.css @@ -0,0 +1,12 @@ +/*! + * Bootstrap v5.3.1 (https://getbootstrap.com/) + * Copyright 2011-2023 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */@import"https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400;700&display=swap";:root,[data-bs-theme=light]{--bs-blue: #2780e3;--bs-indigo: #6610f2;--bs-purple: #613d7c;--bs-pink: #e83e8c;--bs-red: #ff0039;--bs-orange: #f0ad4e;--bs-yellow: #ff7518;--bs-green: #3fb618;--bs-teal: #20c997;--bs-cyan: #9954bb;--bs-black: #000;--bs-white: #fff;--bs-gray: #6c757d;--bs-gray-dark: #343a40;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #343a40;--bs-gray-900: #212529;--bs-default: #343a40;--bs-primary: #2780e3;--bs-secondary: #343a40;--bs-success: #3fb618;--bs-info: #9954bb;--bs-warning: #ff7518;--bs-danger: #ff0039;--bs-light: #f8f9fa;--bs-dark: #343a40;--bs-default-rgb: 52, 58, 64;--bs-primary-rgb: 39, 128, 227;--bs-secondary-rgb: 52, 58, 64;--bs-success-rgb: 63, 182, 24;--bs-info-rgb: 153, 84, 187;--bs-warning-rgb: 255, 117, 24;--bs-danger-rgb: 255, 0, 57;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 52, 58, 64;--bs-primary-text-emphasis: #10335b;--bs-secondary-text-emphasis: #15171a;--bs-success-text-emphasis: #19490a;--bs-info-text-emphasis: #3d224b;--bs-warning-text-emphasis: #662f0a;--bs-danger-text-emphasis: #660017;--bs-light-text-emphasis: #495057;--bs-dark-text-emphasis: #495057;--bs-primary-bg-subtle: #d4e6f9;--bs-secondary-bg-subtle: #d6d8d9;--bs-success-bg-subtle: #d9f0d1;--bs-info-bg-subtle: #ebddf1;--bs-warning-bg-subtle: #ffe3d1;--bs-danger-bg-subtle: #ffccd7;--bs-light-bg-subtle: #fcfcfd;--bs-dark-bg-subtle: #ced4da;--bs-primary-border-subtle: #a9ccf4;--bs-secondary-border-subtle: #aeb0b3;--bs-success-border-subtle: #b2e2a3;--bs-info-border-subtle: #d6bbe4;--bs-warning-border-subtle: #ffc8a3;--bs-danger-border-subtle: #ff99b0;--bs-light-border-subtle: #e9ecef;--bs-dark-border-subtle: #adb5bd;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-font-sans-serif: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-root-font-size: 17px;--bs-body-font-family: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--bs-body-font-size:1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #343a40;--bs-body-color-rgb: 52, 58, 64;--bs-body-bg: #fff;--bs-body-bg-rgb: 255, 255, 255;--bs-emphasis-color: #000;--bs-emphasis-color-rgb: 0, 0, 0;--bs-secondary-color: rgba(52, 58, 64, 0.75);--bs-secondary-color-rgb: 52, 58, 64;--bs-secondary-bg: #e9ecef;--bs-secondary-bg-rgb: 233, 236, 239;--bs-tertiary-color: rgba(52, 58, 64, 0.5);--bs-tertiary-color-rgb: 52, 58, 64;--bs-tertiary-bg: #f8f9fa;--bs-tertiary-bg-rgb: 248, 249, 250;--bs-heading-color: inherit;--bs-link-color: #2761e3;--bs-link-color-rgb: 39, 97, 227;--bs-link-decoration: underline;--bs-link-hover-color: #1f4eb6;--bs-link-hover-color-rgb: 31, 78, 182;--bs-code-color: #7d12ba;--bs-highlight-bg: #ffe3d1;--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, 0.175);--bs-border-radius: 0.25rem;--bs-border-radius-sm: 0.2em;--bs-border-radius-lg: 0.5rem;--bs-border-radius-xl: 1rem;--bs-border-radius-xxl: 2rem;--bs-border-radius-2xl: var(--bs-border-radius-xxl);--bs-border-radius-pill: 50rem;--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width: 0.25rem;--bs-focus-ring-opacity: 0.25;--bs-focus-ring-color: rgba(39, 128, 227, 0.25);--bs-form-valid-color: #3fb618;--bs-form-valid-border-color: #3fb618;--bs-form-invalid-color: #ff0039;--bs-form-invalid-border-color: #ff0039}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color: #dee2e6;--bs-body-color-rgb: 222, 226, 230;--bs-body-bg: #212529;--bs-body-bg-rgb: 33, 37, 41;--bs-emphasis-color: #fff;--bs-emphasis-color-rgb: 255, 255, 255;--bs-secondary-color: rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb: 222, 226, 230;--bs-secondary-bg: #343a40;--bs-secondary-bg-rgb: 52, 58, 64;--bs-tertiary-color: rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb: 222, 226, 230;--bs-tertiary-bg: #2b3035;--bs-tertiary-bg-rgb: 43, 48, 53;--bs-primary-text-emphasis: #7db3ee;--bs-secondary-text-emphasis: #85898c;--bs-success-text-emphasis: #8cd374;--bs-info-text-emphasis: #c298d6;--bs-warning-text-emphasis: #ffac74;--bs-danger-text-emphasis: #ff6688;--bs-light-text-emphasis: #f8f9fa;--bs-dark-text-emphasis: #dee2e6;--bs-primary-bg-subtle: #081a2d;--bs-secondary-bg-subtle: #0a0c0d;--bs-success-bg-subtle: #0d2405;--bs-info-bg-subtle: #1f1125;--bs-warning-bg-subtle: #331705;--bs-danger-bg-subtle: #33000b;--bs-light-bg-subtle: #343a40;--bs-dark-bg-subtle: #1a1d20;--bs-primary-border-subtle: #174d88;--bs-secondary-border-subtle: #1f2326;--bs-success-border-subtle: #266d0e;--bs-info-border-subtle: #5c3270;--bs-warning-border-subtle: #99460e;--bs-danger-border-subtle: #990022;--bs-light-border-subtle: #495057;--bs-dark-border-subtle: #343a40;--bs-heading-color: inherit;--bs-link-color: #7db3ee;--bs-link-hover-color: #97c2f1;--bs-link-color-rgb: 125, 179, 238;--bs-link-hover-color-rgb: 151, 194, 241;--bs-code-color: white;--bs-border-color: #495057;--bs-border-color-translucent: rgba(255, 255, 255, 0.15);--bs-form-valid-color: #8cd374;--bs-form-valid-border-color: #8cd374;--bs-form-invalid-color: #ff6688;--bs-form-invalid-border-color: #ff6688}*,*::before,*::after{box-sizing:border-box}:root{font-size:var(--bs-root-font-size)}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr{margin:1rem 0;color:inherit;border:0;border-top:1px solid;opacity:.25}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:400;line-height:1.2;color:var(--bs-heading-color)}h1,.h1{font-size:calc(1.325rem + 0.9vw)}@media(min-width: 1200px){h1,.h1{font-size:2rem}}h2,.h2{font-size:calc(1.29rem + 0.48vw)}@media(min-width: 1200px){h2,.h2{font-size:1.65rem}}h3,.h3{font-size:calc(1.27rem + 0.24vw)}@media(min-width: 1200px){h3,.h3{font-size:1.45rem}}h4,.h4{font-size:1.25rem}h5,.h5{font-size:1.1rem}h6,.h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{text-decoration:underline dotted;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;-ms-text-decoration:underline dotted;-o-text-decoration:underline dotted;cursor:help;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem;padding:.625rem 1.25rem;border-left:.25rem solid #e9ecef}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}b,strong{font-weight:bolder}small,.small{font-size:0.875em}mark,.mark{padding:.1875em;background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}a:hover{--bs-link-color-rgb: var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875em;color:#000;background-color:#f8f9fa;padding:.5rem;border:1px solid var(--bs-border-color, #dee2e6)}pre code{background-color:rgba(0,0,0,0);font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:var(--bs-code-color);background-color:#f8f9fa;padding:.125rem .25rem;word-wrap:break-word}a>code{color:inherit}kbd{padding:.4rem .4rem;font-size:0.875em;color:#fff;background-color:#343a40}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:rgba(52,58,64,.75);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none !important}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none !important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:0.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:0.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:rgba(52,58,64,.75)}.container,.container-fluid,.container-xxl,.container-xl,.container-lg,.container-md,.container-sm{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;width:100%;padding-right:calc(var(--bs-gutter-x)*.5);padding-left:calc(var(--bs-gutter-x)*.5);margin-right:auto;margin-left:auto}@media(min-width: 576px){.container-sm,.container{max-width:540px}}@media(min-width: 768px){.container-md,.container-sm,.container{max-width:720px}}@media(min-width: 992px){.container-lg,.container-md,.container-sm,.container{max-width:960px}}@media(min-width: 1200px){.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1140px}}@media(min-width: 1400px){.container-xxl,.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1320px}}:root{--bs-breakpoint-xs: 0;--bs-breakpoint-sm: 576px;--bs-breakpoint-md: 768px;--bs-breakpoint-lg: 992px;--bs-breakpoint-xl: 1200px;--bs-breakpoint-xxl: 1400px}.grid{display:grid;grid-template-rows:repeat(var(--bs-rows, 1), 1fr);grid-template-columns:repeat(var(--bs-columns, 12), 1fr);gap:var(--bs-gap, 1.5rem)}.grid .g-col-1{grid-column:auto/span 1}.grid .g-col-2{grid-column:auto/span 2}.grid .g-col-3{grid-column:auto/span 3}.grid .g-col-4{grid-column:auto/span 4}.grid .g-col-5{grid-column:auto/span 5}.grid .g-col-6{grid-column:auto/span 6}.grid .g-col-7{grid-column:auto/span 7}.grid .g-col-8{grid-column:auto/span 8}.grid .g-col-9{grid-column:auto/span 9}.grid .g-col-10{grid-column:auto/span 10}.grid .g-col-11{grid-column:auto/span 11}.grid .g-col-12{grid-column:auto/span 12}.grid .g-start-1{grid-column-start:1}.grid .g-start-2{grid-column-start:2}.grid .g-start-3{grid-column-start:3}.grid .g-start-4{grid-column-start:4}.grid .g-start-5{grid-column-start:5}.grid .g-start-6{grid-column-start:6}.grid .g-start-7{grid-column-start:7}.grid .g-start-8{grid-column-start:8}.grid .g-start-9{grid-column-start:9}.grid .g-start-10{grid-column-start:10}.grid .g-start-11{grid-column-start:11}@media(min-width: 576px){.grid .g-col-sm-1{grid-column:auto/span 1}.grid .g-col-sm-2{grid-column:auto/span 2}.grid .g-col-sm-3{grid-column:auto/span 3}.grid .g-col-sm-4{grid-column:auto/span 4}.grid .g-col-sm-5{grid-column:auto/span 5}.grid .g-col-sm-6{grid-column:auto/span 6}.grid .g-col-sm-7{grid-column:auto/span 7}.grid .g-col-sm-8{grid-column:auto/span 8}.grid .g-col-sm-9{grid-column:auto/span 9}.grid .g-col-sm-10{grid-column:auto/span 10}.grid .g-col-sm-11{grid-column:auto/span 11}.grid .g-col-sm-12{grid-column:auto/span 12}.grid .g-start-sm-1{grid-column-start:1}.grid .g-start-sm-2{grid-column-start:2}.grid .g-start-sm-3{grid-column-start:3}.grid .g-start-sm-4{grid-column-start:4}.grid .g-start-sm-5{grid-column-start:5}.grid .g-start-sm-6{grid-column-start:6}.grid .g-start-sm-7{grid-column-start:7}.grid .g-start-sm-8{grid-column-start:8}.grid .g-start-sm-9{grid-column-start:9}.grid .g-start-sm-10{grid-column-start:10}.grid .g-start-sm-11{grid-column-start:11}}@media(min-width: 768px){.grid .g-col-md-1{grid-column:auto/span 1}.grid .g-col-md-2{grid-column:auto/span 2}.grid .g-col-md-3{grid-column:auto/span 3}.grid .g-col-md-4{grid-column:auto/span 4}.grid .g-col-md-5{grid-column:auto/span 5}.grid .g-col-md-6{grid-column:auto/span 6}.grid .g-col-md-7{grid-column:auto/span 7}.grid .g-col-md-8{grid-column:auto/span 8}.grid .g-col-md-9{grid-column:auto/span 9}.grid .g-col-md-10{grid-column:auto/span 10}.grid .g-col-md-11{grid-column:auto/span 11}.grid .g-col-md-12{grid-column:auto/span 12}.grid .g-start-md-1{grid-column-start:1}.grid .g-start-md-2{grid-column-start:2}.grid .g-start-md-3{grid-column-start:3}.grid .g-start-md-4{grid-column-start:4}.grid .g-start-md-5{grid-column-start:5}.grid .g-start-md-6{grid-column-start:6}.grid .g-start-md-7{grid-column-start:7}.grid .g-start-md-8{grid-column-start:8}.grid .g-start-md-9{grid-column-start:9}.grid .g-start-md-10{grid-column-start:10}.grid .g-start-md-11{grid-column-start:11}}@media(min-width: 992px){.grid .g-col-lg-1{grid-column:auto/span 1}.grid .g-col-lg-2{grid-column:auto/span 2}.grid .g-col-lg-3{grid-column:auto/span 3}.grid .g-col-lg-4{grid-column:auto/span 4}.grid .g-col-lg-5{grid-column:auto/span 5}.grid .g-col-lg-6{grid-column:auto/span 6}.grid .g-col-lg-7{grid-column:auto/span 7}.grid .g-col-lg-8{grid-column:auto/span 8}.grid .g-col-lg-9{grid-column:auto/span 9}.grid .g-col-lg-10{grid-column:auto/span 10}.grid .g-col-lg-11{grid-column:auto/span 11}.grid .g-col-lg-12{grid-column:auto/span 12}.grid .g-start-lg-1{grid-column-start:1}.grid .g-start-lg-2{grid-column-start:2}.grid .g-start-lg-3{grid-column-start:3}.grid .g-start-lg-4{grid-column-start:4}.grid .g-start-lg-5{grid-column-start:5}.grid .g-start-lg-6{grid-column-start:6}.grid .g-start-lg-7{grid-column-start:7}.grid .g-start-lg-8{grid-column-start:8}.grid .g-start-lg-9{grid-column-start:9}.grid .g-start-lg-10{grid-column-start:10}.grid .g-start-lg-11{grid-column-start:11}}@media(min-width: 1200px){.grid .g-col-xl-1{grid-column:auto/span 1}.grid .g-col-xl-2{grid-column:auto/span 2}.grid .g-col-xl-3{grid-column:auto/span 3}.grid .g-col-xl-4{grid-column:auto/span 4}.grid .g-col-xl-5{grid-column:auto/span 5}.grid .g-col-xl-6{grid-column:auto/span 6}.grid .g-col-xl-7{grid-column:auto/span 7}.grid .g-col-xl-8{grid-column:auto/span 8}.grid .g-col-xl-9{grid-column:auto/span 9}.grid .g-col-xl-10{grid-column:auto/span 10}.grid .g-col-xl-11{grid-column:auto/span 11}.grid .g-col-xl-12{grid-column:auto/span 12}.grid .g-start-xl-1{grid-column-start:1}.grid .g-start-xl-2{grid-column-start:2}.grid .g-start-xl-3{grid-column-start:3}.grid .g-start-xl-4{grid-column-start:4}.grid .g-start-xl-5{grid-column-start:5}.grid .g-start-xl-6{grid-column-start:6}.grid .g-start-xl-7{grid-column-start:7}.grid .g-start-xl-8{grid-column-start:8}.grid .g-start-xl-9{grid-column-start:9}.grid .g-start-xl-10{grid-column-start:10}.grid .g-start-xl-11{grid-column-start:11}}@media(min-width: 1400px){.grid .g-col-xxl-1{grid-column:auto/span 1}.grid .g-col-xxl-2{grid-column:auto/span 2}.grid .g-col-xxl-3{grid-column:auto/span 3}.grid .g-col-xxl-4{grid-column:auto/span 4}.grid .g-col-xxl-5{grid-column:auto/span 5}.grid .g-col-xxl-6{grid-column:auto/span 6}.grid .g-col-xxl-7{grid-column:auto/span 7}.grid .g-col-xxl-8{grid-column:auto/span 8}.grid .g-col-xxl-9{grid-column:auto/span 9}.grid .g-col-xxl-10{grid-column:auto/span 10}.grid .g-col-xxl-11{grid-column:auto/span 11}.grid .g-col-xxl-12{grid-column:auto/span 12}.grid .g-start-xxl-1{grid-column-start:1}.grid .g-start-xxl-2{grid-column-start:2}.grid .g-start-xxl-3{grid-column-start:3}.grid .g-start-xxl-4{grid-column-start:4}.grid .g-start-xxl-5{grid-column-start:5}.grid .g-start-xxl-6{grid-column-start:6}.grid .g-start-xxl-7{grid-column-start:7}.grid .g-start-xxl-8{grid-column-start:8}.grid .g-start-xxl-9{grid-column-start:9}.grid .g-start-xxl-10{grid-column-start:10}.grid .g-start-xxl-11{grid-column-start:11}}.table{--bs-table-color-type: initial;--bs-table-bg-type: initial;--bs-table-color-state: initial;--bs-table-bg-state: initial;--bs-table-color: #343a40;--bs-table-bg: #fff;--bs-table-border-color: #dee2e6;--bs-table-accent-bg: transparent;--bs-table-striped-color: #343a40;--bs-table-striped-bg: rgba(0, 0, 0, 0.05);--bs-table-active-color: #343a40;--bs-table-active-bg: rgba(0, 0, 0, 0.1);--bs-table-hover-color: #343a40;--bs-table-hover-bg: rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(1px*2) solid #b2bac1}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(even){--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-active{--bs-table-color-state: var(--bs-table-active-color);--bs-table-bg-state: var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state: var(--bs-table-hover-color);--bs-table-bg-state: var(--bs-table-hover-bg)}.table-primary{--bs-table-color: #000;--bs-table-bg: #d4e6f9;--bs-table-border-color: #bfcfe0;--bs-table-striped-bg: #c9dbed;--bs-table-striped-color: #000;--bs-table-active-bg: #bfcfe0;--bs-table-active-color: #000;--bs-table-hover-bg: #c4d5e6;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color: #000;--bs-table-bg: #d6d8d9;--bs-table-border-color: #c1c2c3;--bs-table-striped-bg: #cbcdce;--bs-table-striped-color: #000;--bs-table-active-bg: #c1c2c3;--bs-table-active-color: #000;--bs-table-hover-bg: #c6c8c9;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color: #000;--bs-table-bg: #d9f0d1;--bs-table-border-color: #c3d8bc;--bs-table-striped-bg: #cee4c7;--bs-table-striped-color: #000;--bs-table-active-bg: #c3d8bc;--bs-table-active-color: #000;--bs-table-hover-bg: #c9dec1;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color: #000;--bs-table-bg: #ebddf1;--bs-table-border-color: #d4c7d9;--bs-table-striped-bg: #dfd2e5;--bs-table-striped-color: #000;--bs-table-active-bg: #d4c7d9;--bs-table-active-color: #000;--bs-table-hover-bg: #d9ccdf;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color: #000;--bs-table-bg: #ffe3d1;--bs-table-border-color: #e6ccbc;--bs-table-striped-bg: #f2d8c7;--bs-table-striped-color: #000;--bs-table-active-bg: #e6ccbc;--bs-table-active-color: #000;--bs-table-hover-bg: #ecd2c1;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color: #000;--bs-table-bg: #ffccd7;--bs-table-border-color: #e6b8c2;--bs-table-striped-bg: #f2c2cc;--bs-table-striped-color: #000;--bs-table-active-bg: #e6b8c2;--bs-table-active-color: #000;--bs-table-hover-bg: #ecbdc7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color: #000;--bs-table-bg: #f8f9fa;--bs-table-border-color: #dfe0e1;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color: #fff;--bs-table-bg: #343a40;--bs-table-border-color: #484e53;--bs-table-striped-bg: #3e444a;--bs-table-striped-color: #fff;--bs-table-active-bg: #484e53;--bs-table-active-color: #fff;--bs-table-hover-bg: #43494e;--bs-table-hover-color: #fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label,.shiny-input-container .control-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(0.375rem + 1px);padding-bottom:calc(0.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(0.5rem + 1px);padding-bottom:calc(0.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(0.25rem + 1px);padding-bottom:calc(0.25rem + 1px);font-size:0.875rem}.form-text{margin-top:.25rem;font-size:0.875em;color:rgba(52,58,64,.75)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#343a40;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#fff;background-clip:padding-box;border:1px solid #dee2e6;border-radius:0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#343a40;background-color:#fff;border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:rgba(52,58,64,.75);opacity:1}.form-control:disabled{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#343a40;background-color:#f8f9fa;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#e9ecef}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#343a40;background-color:rgba(0,0,0,0);border:solid rgba(0,0,0,0);border-width:1px 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(1px * 2));padding:.25rem .5rem;font-size:0.875rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(1px * 2));padding:.5rem 1rem;font-size:1.25rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + 0.75rem + calc(1px * 2))}textarea.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(1px * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(1px * 2))}.form-control-color{width:3rem;height:calc(1.5em + 0.75rem + calc(1px * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0 !important}.form-control-color::-webkit-color-swatch{border:0 !important}.form-control-color.form-control-sm{height:calc(1.5em + 0.5rem + calc(1px * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(1px * 2))}.form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#343a40;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#fff;background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #dee2e6;border-radius:0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:rgba(0,0,0,0);text-shadow:0 0 0 #343a40}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check,.shiny-input-container .checkbox,.shiny-input-container .radio{display:block;min-height:1.5rem;padding-left:0;margin-bottom:.125rem}.form-check .form-check-input,.form-check .shiny-input-container .checkbox input,.form-check .shiny-input-container .radio input,.shiny-input-container .checkbox .form-check-input,.shiny-input-container .checkbox .shiny-input-container .checkbox input,.shiny-input-container .checkbox .shiny-input-container .radio input,.shiny-input-container .radio .form-check-input,.shiny-input-container .radio .shiny-input-container .checkbox input,.shiny-input-container .radio .shiny-input-container .radio input{float:left;margin-left:0}.form-check-reverse{padding-right:0;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:0;margin-left:0}.form-check-input,.shiny-input-container .checkbox input,.shiny-input-container .checkbox-inline input,.shiny-input-container .radio input,.shiny-input-container .radio-inline input{--bs-form-check-bg: #fff;width:1em;height:1em;margin-top:.25em;vertical-align:top;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid #dee2e6;print-color-adjust:exact}.form-check-input[type=radio],.shiny-input-container .checkbox input[type=radio],.shiny-input-container .checkbox-inline input[type=radio],.shiny-input-container .radio input[type=radio],.shiny-input-container .radio-inline input[type=radio]{border-radius:50%}.form-check-input:active,.shiny-input-container .checkbox input:active,.shiny-input-container .checkbox-inline input:active,.shiny-input-container .radio input:active,.shiny-input-container .radio-inline input:active{filter:brightness(90%)}.form-check-input:focus,.shiny-input-container .checkbox input:focus,.shiny-input-container .checkbox-inline input:focus,.shiny-input-container .radio input:focus,.shiny-input-container .radio-inline input:focus{border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-check-input:checked,.shiny-input-container .checkbox input:checked,.shiny-input-container .checkbox-inline input:checked,.shiny-input-container .radio input:checked,.shiny-input-container .radio-inline input:checked{background-color:#2780e3;border-color:#2780e3}.form-check-input:checked[type=checkbox],.shiny-input-container .checkbox input:checked[type=checkbox],.shiny-input-container .checkbox-inline input:checked[type=checkbox],.shiny-input-container .radio input:checked[type=checkbox],.shiny-input-container .radio-inline input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio],.shiny-input-container .checkbox input:checked[type=radio],.shiny-input-container .checkbox-inline input:checked[type=radio],.shiny-input-container .radio input:checked[type=radio],.shiny-input-container .radio-inline input:checked[type=radio]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate,.shiny-input-container .checkbox input[type=checkbox]:indeterminate,.shiny-input-container .checkbox-inline input[type=checkbox]:indeterminate,.shiny-input-container .radio input[type=checkbox]:indeterminate,.shiny-input-container .radio-inline input[type=checkbox]:indeterminate{background-color:#2780e3;border-color:#2780e3;--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled,.shiny-input-container .checkbox input:disabled,.shiny-input-container .checkbox-inline input:disabled,.shiny-input-container .radio input:disabled,.shiny-input-container .radio-inline input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input[disabled]~span,.form-check-input:disabled~.form-check-label,.form-check-input:disabled~span,.shiny-input-container .checkbox input[disabled]~.form-check-label,.shiny-input-container .checkbox input[disabled]~span,.shiny-input-container .checkbox input:disabled~.form-check-label,.shiny-input-container .checkbox input:disabled~span,.shiny-input-container .checkbox-inline input[disabled]~.form-check-label,.shiny-input-container .checkbox-inline input[disabled]~span,.shiny-input-container .checkbox-inline input:disabled~.form-check-label,.shiny-input-container .checkbox-inline input:disabled~span,.shiny-input-container .radio input[disabled]~.form-check-label,.shiny-input-container .radio input[disabled]~span,.shiny-input-container .radio input:disabled~.form-check-label,.shiny-input-container .radio input:disabled~span,.shiny-input-container .radio-inline input[disabled]~.form-check-label,.shiny-input-container .radio-inline input[disabled]~span,.shiny-input-container .radio-inline input:disabled~.form-check-label,.shiny-input-container .radio-inline input:disabled~span{cursor:default;opacity:.5}.form-check-label,.shiny-input-container .checkbox label,.shiny-input-container .checkbox-inline label,.shiny-input-container .radio label,.shiny-input-container .radio-inline label{cursor:pointer}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;transition:background-position .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2393c0f1'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:rgba(0,0,0,0)}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(39,128,227,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(39,128,227,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#2780e3;border:0;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#bed9f7}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#f8f9fa;border-color:rgba(0,0,0,0)}.form-range::-moz-range-thumb{width:1rem;height:1rem;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#2780e3;border:0;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#bed9f7}.form-range::-moz-range-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#f8f9fa;border-color:rgba(0,0,0,0)}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:rgba(52,58,64,.75)}.form-range:disabled::-moz-range-thumb{background-color:rgba(52,58,64,.75)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(1px * 2));min-height:calc(3.5rem + calc(1px * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:1px solid rgba(0,0,0,0);transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media(prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown),.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill,.form-floating>.form-control-plaintext:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-control-plaintext~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem .375rem;z-index:-1;height:1.5em;content:"";background-color:#fff}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control-plaintext~label{border-width:1px 0}.form-floating>:disabled~label,.form-floating>.form-control:disabled~label{color:#6c757d}.form-floating>:disabled~label::after,.form-floating>.form-control:disabled~label::after{background-color:#e9ecef}.input-group{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:stretch;-webkit-align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select,.input-group>.form-floating{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus,.input-group>.form-floating:focus-within{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#343a40;text-align:center;white-space:nowrap;background-color:#f8f9fa;border:1px solid #dee2e6}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(1px*-1)}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#3fb618}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:#3fb618}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#3fb618;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%233fb618' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#3fb618;box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:#3fb618}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%233fb618' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:#3fb618;box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:#3fb618}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:#3fb618}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#3fb618}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):valid,.input-group>.form-control:not(:focus).is-valid,.was-validated .input-group>.form-select:not(:focus):valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.input-group>.form-floating:not(:focus-within).is-valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#ff0039}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:#ff0039}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#ff0039;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff0039'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff0039' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#ff0039;box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:#ff0039}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff0039'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff0039' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:#ff0039;box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:#ff0039}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:#ff0039}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#ff0039}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):invalid,.input-group>.form-control:not(:focus).is-invalid,.was-validated .input-group>.form-select:not(:focus):invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.input-group>.form-floating:not(:focus-within).is-invalid{z-index:4}.btn{--bs-btn-padding-x: 0.75rem;--bs-btn-padding-y: 0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.5;--bs-btn-color: #343a40;--bs-btn-bg: transparent;--bs-btn-border-width: 1px;--bs-btn-border-color: transparent;--bs-btn-border-radius: 0.25rem;--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity: 0.65;--bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;vertical-align:middle;cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-default{--bs-btn-color: #fff;--bs-btn-bg: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #2c3136;--bs-btn-hover-border-color: #2a2e33;--bs-btn-focus-shadow-rgb: 82, 88, 93;--bs-btn-active-color: #fff;--bs-btn-active-bg: #2a2e33;--bs-btn-active-border-color: #272c30;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #343a40;--bs-btn-disabled-border-color: #343a40}.btn-primary{--bs-btn-color: #fff;--bs-btn-bg: #2780e3;--bs-btn-border-color: #2780e3;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #216dc1;--bs-btn-hover-border-color: #1f66b6;--bs-btn-focus-shadow-rgb: 71, 147, 231;--bs-btn-active-color: #fff;--bs-btn-active-bg: #1f66b6;--bs-btn-active-border-color: #1d60aa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #2780e3;--bs-btn-disabled-border-color: #2780e3}.btn-secondary{--bs-btn-color: #fff;--bs-btn-bg: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #2c3136;--bs-btn-hover-border-color: #2a2e33;--bs-btn-focus-shadow-rgb: 82, 88, 93;--bs-btn-active-color: #fff;--bs-btn-active-bg: #2a2e33;--bs-btn-active-border-color: #272c30;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #343a40;--bs-btn-disabled-border-color: #343a40}.btn-success{--bs-btn-color: #fff;--bs-btn-bg: #3fb618;--bs-btn-border-color: #3fb618;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #369b14;--bs-btn-hover-border-color: #329213;--bs-btn-focus-shadow-rgb: 92, 193, 59;--bs-btn-active-color: #fff;--bs-btn-active-bg: #329213;--bs-btn-active-border-color: #2f8912;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #3fb618;--bs-btn-disabled-border-color: #3fb618}.btn-info{--bs-btn-color: #fff;--bs-btn-bg: #9954bb;--bs-btn-border-color: #9954bb;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #82479f;--bs-btn-hover-border-color: #7a4396;--bs-btn-focus-shadow-rgb: 168, 110, 197;--bs-btn-active-color: #fff;--bs-btn-active-bg: #7a4396;--bs-btn-active-border-color: #733f8c;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #9954bb;--bs-btn-disabled-border-color: #9954bb}.btn-warning{--bs-btn-color: #fff;--bs-btn-bg: #ff7518;--bs-btn-border-color: #ff7518;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #d96314;--bs-btn-hover-border-color: #cc5e13;--bs-btn-focus-shadow-rgb: 255, 138, 59;--bs-btn-active-color: #fff;--bs-btn-active-bg: #cc5e13;--bs-btn-active-border-color: #bf5812;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #ff7518;--bs-btn-disabled-border-color: #ff7518}.btn-danger{--bs-btn-color: #fff;--bs-btn-bg: #ff0039;--bs-btn-border-color: #ff0039;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #d90030;--bs-btn-hover-border-color: #cc002e;--bs-btn-focus-shadow-rgb: 255, 38, 87;--bs-btn-active-color: #fff;--bs-btn-active-bg: #cc002e;--bs-btn-active-border-color: #bf002b;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #ff0039;--bs-btn-disabled-border-color: #ff0039}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #d3d4d5;--bs-btn-hover-border-color: #c6c7c8;--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: #c6c7c8;--bs-btn-active-border-color: #babbbc;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-dark{--bs-btn-color: #fff;--bs-btn-bg: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #52585d;--bs-btn-hover-border-color: #484e53;--bs-btn-focus-shadow-rgb: 82, 88, 93;--bs-btn-active-color: #fff;--bs-btn-active-bg: #5d6166;--bs-btn-active-border-color: #484e53;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #343a40;--bs-btn-disabled-border-color: #343a40}.btn-outline-default{--bs-btn-color: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #343a40;--bs-btn-hover-border-color: #343a40;--bs-btn-focus-shadow-rgb: 52, 58, 64;--bs-btn-active-color: #fff;--bs-btn-active-bg: #343a40;--bs-btn-active-border-color: #343a40;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #343a40;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #343a40;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-primary{--bs-btn-color: #2780e3;--bs-btn-border-color: #2780e3;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #2780e3;--bs-btn-hover-border-color: #2780e3;--bs-btn-focus-shadow-rgb: 39, 128, 227;--bs-btn-active-color: #fff;--bs-btn-active-bg: #2780e3;--bs-btn-active-border-color: #2780e3;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #2780e3;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #2780e3;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-secondary{--bs-btn-color: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #343a40;--bs-btn-hover-border-color: #343a40;--bs-btn-focus-shadow-rgb: 52, 58, 64;--bs-btn-active-color: #fff;--bs-btn-active-bg: #343a40;--bs-btn-active-border-color: #343a40;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #343a40;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #343a40;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-success{--bs-btn-color: #3fb618;--bs-btn-border-color: #3fb618;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #3fb618;--bs-btn-hover-border-color: #3fb618;--bs-btn-focus-shadow-rgb: 63, 182, 24;--bs-btn-active-color: #fff;--bs-btn-active-bg: #3fb618;--bs-btn-active-border-color: #3fb618;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #3fb618;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #3fb618;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-info{--bs-btn-color: #9954bb;--bs-btn-border-color: #9954bb;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #9954bb;--bs-btn-hover-border-color: #9954bb;--bs-btn-focus-shadow-rgb: 153, 84, 187;--bs-btn-active-color: #fff;--bs-btn-active-bg: #9954bb;--bs-btn-active-border-color: #9954bb;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #9954bb;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #9954bb;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-warning{--bs-btn-color: #ff7518;--bs-btn-border-color: #ff7518;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #ff7518;--bs-btn-hover-border-color: #ff7518;--bs-btn-focus-shadow-rgb: 255, 117, 24;--bs-btn-active-color: #fff;--bs-btn-active-bg: #ff7518;--bs-btn-active-border-color: #ff7518;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ff7518;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ff7518;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-danger{--bs-btn-color: #ff0039;--bs-btn-border-color: #ff0039;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #ff0039;--bs-btn-hover-border-color: #ff0039;--bs-btn-focus-shadow-rgb: 255, 0, 57;--bs-btn-active-color: #fff;--bs-btn-active-bg: #ff0039;--bs-btn-active-border-color: #ff0039;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ff0039;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ff0039;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-light{--bs-btn-color: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #f8f9fa;--bs-btn-hover-border-color: #f8f9fa;--bs-btn-focus-shadow-rgb: 248, 249, 250;--bs-btn-active-color: #000;--bs-btn-active-bg: #f8f9fa;--bs-btn-active-border-color: #f8f9fa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #f8f9fa;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #f8f9fa;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-dark{--bs-btn-color: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #343a40;--bs-btn-hover-border-color: #343a40;--bs-btn-focus-shadow-rgb: 52, 58, 64;--bs-btn-active-color: #fff;--bs-btn-active-bg: #343a40;--bs-btn-active-border-color: #343a40;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #343a40;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #343a40;--bs-btn-bg: transparent;--bs-gradient: none}.btn-link{--bs-btn-font-weight: 400;--bs-btn-color: #2761e3;--bs-btn-bg: transparent;--bs-btn-border-color: transparent;--bs-btn-hover-color: #1f4eb6;--bs-btn-hover-border-color: transparent;--bs-btn-active-color: #1f4eb6;--bs-btn-active-border-color: transparent;--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-border-color: transparent;--bs-btn-box-shadow: 0 0 0 #000;--bs-btn-focus-shadow-rgb: 71, 121, 231;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--bs-btn-padding-y: 0.5rem;--bs-btn-padding-x: 1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius: 0.5rem}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: 0.25rem;--bs-btn-padding-x: 0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius: 0.2em}.fade{transition:opacity .15s linear}@media(prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .2s ease}@media(prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media(prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid rgba(0,0,0,0);border-bottom:0;border-left:.3em solid rgba(0,0,0,0)}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex: 1000;--bs-dropdown-min-width: 10rem;--bs-dropdown-padding-x: 0;--bs-dropdown-padding-y: 0.5rem;--bs-dropdown-spacer: 0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color: #343a40;--bs-dropdown-bg: #fff;--bs-dropdown-border-color: rgba(0, 0, 0, 0.175);--bs-dropdown-border-radius: 0.25rem;--bs-dropdown-border-width: 1px;--bs-dropdown-inner-border-radius: calc(0.25rem - 1px);--bs-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--bs-dropdown-divider-margin-y: 0.5rem;--bs-dropdown-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-dropdown-link-color: #343a40;--bs-dropdown-link-hover-color: #343a40;--bs-dropdown-link-hover-bg: #f8f9fa;--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #2780e3;--bs-dropdown-link-disabled-color: rgba(52, 58, 64, 0.5);--bs-dropdown-item-padding-x: 1rem;--bs-dropdown-item-padding-y: 0.25rem;--bs-dropdown-header-color: #6c757d;--bs-dropdown-header-padding-x: 1rem;--bs-dropdown-header-padding-y: 0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid rgba(0,0,0,0);border-bottom:.3em solid;border-left:.3em solid rgba(0,0,0,0)}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:0;border-bottom:.3em solid rgba(0,0,0,0);border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:.3em solid;border-bottom:.3em solid rgba(0,0,0,0)}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap;background-color:rgba(0,0,0,0);border:0}.dropdown-item:hover,.dropdown-item:focus{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:rgba(0,0,0,0)}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:0.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color: #dee2e6;--bs-dropdown-bg: #343a40;--bs-dropdown-border-color: rgba(0, 0, 0, 0.175);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color: #dee2e6;--bs-dropdown-link-hover-color: #fff;--bs-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #2780e3;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-header-color: #adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;justify-content:flex-start;-webkit-justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:calc(1px*-1)}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;-webkit-flex-direction:column;align-items:flex-start;-webkit-align-items:flex-start;justify-content:center;-webkit-justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:calc(1px*-1)}.nav{--bs-nav-link-padding-x: 1rem;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: #2761e3;--bs-nav-link-hover-color: #1f4eb6;--bs-nav-link-disabled-color: rgba(52, 58, 64, 0.75);display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background:none;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media(prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width: 1px;--bs-nav-tabs-border-color: #dee2e6;--bs-nav-tabs-border-radius: 0.25rem;--bs-nav-tabs-link-hover-border-color: #e9ecef #e9ecef #dee2e6;--bs-nav-tabs-link-active-color: #000;--bs-nav-tabs-link-active-bg: #fff;--bs-nav-tabs-link-active-border-color: #dee2e6 #dee2e6 #fff;border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1*var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid rgba(0,0,0,0)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1*var(--bs-nav-tabs-border-width))}.nav-pills{--bs-nav-pills-border-radius: 0.25rem;--bs-nav-pills-link-active-color: #fff;--bs-nav-pills-link-active-bg: #2780e3}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap: 1rem;--bs-nav-underline-border-width: 0.125rem;--bs-nav-underline-link-active-color: #000;gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid rgba(0,0,0,0)}.nav-underline .nav-link:hover,.nav-underline .nav-link:focus{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;-webkit-flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;-webkit-flex-basis:0;flex-grow:1;-webkit-flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x: 0;--bs-navbar-padding-y: 0.5rem;--bs-navbar-color: #fdfeff;--bs-navbar-hover-color: rgba(253, 253, 255, 0.8);--bs-navbar-disabled-color: rgba(253, 254, 255, 0.75);--bs-navbar-active-color: #fdfdff;--bs-navbar-brand-padding-y: 0.3125rem;--bs-navbar-brand-margin-end: 1rem;--bs-navbar-brand-font-size: 1.25rem;--bs-navbar-brand-color: #fdfeff;--bs-navbar-brand-hover-color: #fdfdff;--bs-navbar-nav-link-padding-x: 0.5rem;--bs-navbar-toggler-padding-y: 0.25;--bs-navbar-toggler-padding-x: 0;--bs-navbar-toggler-font-size: 1.25rem;--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfeff' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color: rgba(253, 254, 255, 0);--bs-navbar-toggler-border-radius: 0.25rem;--bs-navbar-toggler-focus-width: 0.25rem;--bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out;position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;display:-webkit-flex;flex-wrap:inherit;-webkit-flex-wrap:inherit;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x: 0;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-navbar-color);--bs-nav-link-hover-color: var(--bs-navbar-hover-color);--bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;-webkit-flex-basis:100%;flex-grow:1;-webkit-flex-grow:1;align-items:center;-webkit-align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:rgba(0,0,0,0);border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);transition:var(--bs-navbar-toggler-transition)}@media(prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color: #fdfeff;--bs-navbar-hover-color: rgba(253, 253, 255, 0.8);--bs-navbar-disabled-color: rgba(253, 254, 255, 0.75);--bs-navbar-active-color: #fdfdff;--bs-navbar-brand-color: #fdfeff;--bs-navbar-brand-hover-color: #fdfdff;--bs-navbar-toggler-border-color: rgba(253, 254, 255, 0);--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfeff' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfeff' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: 0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: 1px;--bs-card-border-color: rgba(0, 0, 0, 0.175);--bs-card-border-radius: 0.25rem;--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc(0.25rem - 1px);--bs-card-cap-padding-y: 0.5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(52, 58, 64, 0.25);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: #fff;--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: 0.75rem;position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0}.card>.list-group:last-child{border-bottom-width:0}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;-webkit-flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-0.5*var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header-tabs{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-bottom:calc(-1*var(--bs-card-cap-padding-y));margin-left:calc(-0.5*var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-left:calc(-0.5*var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media(min-width: 576px){.card-group{display:flex;display:-webkit-flex;flex-flow:row wrap;-webkit-flex-flow:row wrap}.card-group>.card{flex:1 0 0%;-webkit-flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}}.accordion{--bs-accordion-color: #343a40;--bs-accordion-bg: #fff;--bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;--bs-accordion-border-color: #dee2e6;--bs-accordion-border-width: 1px;--bs-accordion-border-radius: 0.25rem;--bs-accordion-inner-border-radius: calc(0.25rem - 1px);--bs-accordion-btn-padding-x: 1.25rem;--bs-accordion-btn-padding-y: 1rem;--bs-accordion-btn-color: #343a40;--bs-accordion-btn-bg: #fff;--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23343a40'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width: 1.25rem;--bs-accordion-btn-icon-transform: rotate(-180deg);--bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2310335b'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-focus-border-color: #93c0f1;--bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(39, 128, 227, 0.25);--bs-accordion-body-padding-x: 1.25rem;--bs-accordion-body-padding-y: 1rem;--bs-accordion-active-color: #10335b;--bs-accordion-active-bg: #d4e6f9}.accordion-button{position:relative;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media(prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1*var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;-webkit-flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media(prefers-reduced-motion: reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:var(--bs-accordion-btn-focus-border-color);outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:not(:first-of-type){border-top:0}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%237db3ee'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%237db3ee'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x: 0;--bs-breadcrumb-padding-y: 0;--bs-breadcrumb-margin-bottom: 1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color: rgba(52, 58, 64, 0.75);--bs-breadcrumb-item-padding-x: 0.5rem;--bs-breadcrumb-item-active-color: rgba(52, 58, 64, 0.75);display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, ">") /* rtl: var(--bs-breadcrumb-divider, ">") */}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x: 0.75rem;--bs-pagination-padding-y: 0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color: #2761e3;--bs-pagination-bg: #fff;--bs-pagination-border-width: 1px;--bs-pagination-border-color: #dee2e6;--bs-pagination-border-radius: 0.25rem;--bs-pagination-hover-color: #1f4eb6;--bs-pagination-hover-bg: #f8f9fa;--bs-pagination-hover-border-color: #dee2e6;--bs-pagination-focus-color: #1f4eb6;--bs-pagination-focus-bg: #e9ecef;--bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(39, 128, 227, 0.25);--bs-pagination-active-color: #fff;--bs-pagination-active-bg: #2780e3;--bs-pagination-active-border-color: #2780e3;--bs-pagination-disabled-color: rgba(52, 58, 64, 0.75);--bs-pagination-disabled-bg: #e9ecef;--bs-pagination-disabled-border-color: #dee2e6;display:flex;display:-webkit-flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(1px*-1)}.pagination-lg{--bs-pagination-padding-x: 1.5rem;--bs-pagination-padding-y: 0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius: 0.5rem}.pagination-sm{--bs-pagination-padding-x: 0.5rem;--bs-pagination-padding-y: 0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius: 0.2em}.badge{--bs-badge-padding-x: 0.65em;--bs-badge-padding-y: 0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight: 700;--bs-badge-color: #fff;--bs-badge-border-radius: 0.25rem;display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg: transparent;--bs-alert-padding-x: 1rem;--bs-alert-padding-y: 1rem;--bs-alert-margin-bottom: 1rem;--bs-alert-color: inherit;--bs-alert-border-color: transparent;--bs-alert-border: 0 solid var(--bs-alert-border-color);--bs-alert-border-radius: 0.25rem;--bs-alert-link-color: inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-default{--bs-alert-color: var(--bs-default-text-emphasis);--bs-alert-bg: var(--bs-default-bg-subtle);--bs-alert-border-color: var(--bs-default-border-subtle);--bs-alert-link-color: var(--bs-default-text-emphasis)}.alert-primary{--bs-alert-color: var(--bs-primary-text-emphasis);--bs-alert-bg: var(--bs-primary-bg-subtle);--bs-alert-border-color: var(--bs-primary-border-subtle);--bs-alert-link-color: var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color: var(--bs-secondary-text-emphasis);--bs-alert-bg: var(--bs-secondary-bg-subtle);--bs-alert-border-color: var(--bs-secondary-border-subtle);--bs-alert-link-color: var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color: var(--bs-success-text-emphasis);--bs-alert-bg: var(--bs-success-bg-subtle);--bs-alert-border-color: var(--bs-success-border-subtle);--bs-alert-link-color: var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color: var(--bs-info-text-emphasis);--bs-alert-bg: var(--bs-info-bg-subtle);--bs-alert-border-color: var(--bs-info-border-subtle);--bs-alert-link-color: var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color: var(--bs-warning-text-emphasis);--bs-alert-bg: var(--bs-warning-bg-subtle);--bs-alert-border-color: var(--bs-warning-border-subtle);--bs-alert-link-color: var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color: var(--bs-danger-text-emphasis);--bs-alert-bg: var(--bs-danger-bg-subtle);--bs-alert-border-color: var(--bs-danger-border-subtle);--bs-alert-link-color: var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color: var(--bs-light-text-emphasis);--bs-alert-bg: var(--bs-light-bg-subtle);--bs-alert-border-color: var(--bs-light-border-subtle);--bs-alert-link-color: var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color: var(--bs-dark-text-emphasis);--bs-alert-bg: var(--bs-dark-bg-subtle);--bs-alert-border-color: var(--bs-dark-border-subtle);--bs-alert-link-color: var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:.5rem}}.progress,.progress-stacked{--bs-progress-height: 0.5rem;--bs-progress-font-size:0.75rem;--bs-progress-bg: #e9ecef;--bs-progress-border-radius: 0.25rem;--bs-progress-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-progress-bar-color: #fff;--bs-progress-bar-bg: #2780e3;--bs-progress-bar-transition: width 0.6s ease;display:flex;display:-webkit-flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg)}.progress-bar{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;justify-content:center;-webkit-justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media(prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color: #343a40;--bs-list-group-bg: #fff;--bs-list-group-border-color: #dee2e6;--bs-list-group-border-width: 1px;--bs-list-group-border-radius: 0.25rem;--bs-list-group-item-padding-x: 1rem;--bs-list-group-item-padding-y: 0.5rem;--bs-list-group-action-color: rgba(52, 58, 64, 0.75);--bs-list-group-action-hover-color: #000;--bs-list-group-action-hover-bg: #f8f9fa;--bs-list-group-action-active-color: #343a40;--bs-list-group-action-active-bg: #e9ecef;--bs-list-group-disabled-color: rgba(52, 58, 64, 0.75);--bs-list-group-disabled-bg: #fff;--bs-list-group-active-color: #fff;--bs-list-group-active-bg: #2780e3;--bs-list-group-active-border-color: #2780e3;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1*var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-default{--bs-list-group-color: var(--bs-default-text-emphasis);--bs-list-group-bg: var(--bs-default-bg-subtle);--bs-list-group-border-color: var(--bs-default-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-default-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-default-border-subtle);--bs-list-group-active-color: var(--bs-default-bg-subtle);--bs-list-group-active-bg: var(--bs-default-text-emphasis);--bs-list-group-active-border-color: var(--bs-default-text-emphasis)}.list-group-item-primary{--bs-list-group-color: var(--bs-primary-text-emphasis);--bs-list-group-bg: var(--bs-primary-bg-subtle);--bs-list-group-border-color: var(--bs-primary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-primary-border-subtle);--bs-list-group-active-color: var(--bs-primary-bg-subtle);--bs-list-group-active-bg: var(--bs-primary-text-emphasis);--bs-list-group-active-border-color: var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color: var(--bs-secondary-text-emphasis);--bs-list-group-bg: var(--bs-secondary-bg-subtle);--bs-list-group-border-color: var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);--bs-list-group-active-color: var(--bs-secondary-bg-subtle);--bs-list-group-active-bg: var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color: var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color: var(--bs-success-text-emphasis);--bs-list-group-bg: var(--bs-success-bg-subtle);--bs-list-group-border-color: var(--bs-success-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-success-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-success-border-subtle);--bs-list-group-active-color: var(--bs-success-bg-subtle);--bs-list-group-active-bg: var(--bs-success-text-emphasis);--bs-list-group-active-border-color: var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color: var(--bs-info-text-emphasis);--bs-list-group-bg: var(--bs-info-bg-subtle);--bs-list-group-border-color: var(--bs-info-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-info-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-info-border-subtle);--bs-list-group-active-color: var(--bs-info-bg-subtle);--bs-list-group-active-bg: var(--bs-info-text-emphasis);--bs-list-group-active-border-color: var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color: var(--bs-warning-text-emphasis);--bs-list-group-bg: var(--bs-warning-bg-subtle);--bs-list-group-border-color: var(--bs-warning-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-warning-border-subtle);--bs-list-group-active-color: var(--bs-warning-bg-subtle);--bs-list-group-active-bg: var(--bs-warning-text-emphasis);--bs-list-group-active-border-color: var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color: var(--bs-danger-text-emphasis);--bs-list-group-bg: var(--bs-danger-bg-subtle);--bs-list-group-border-color: var(--bs-danger-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-danger-border-subtle);--bs-list-group-active-color: var(--bs-danger-bg-subtle);--bs-list-group-active-bg: var(--bs-danger-text-emphasis);--bs-list-group-active-border-color: var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color: var(--bs-light-text-emphasis);--bs-list-group-bg: var(--bs-light-bg-subtle);--bs-list-group-border-color: var(--bs-light-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-light-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-light-border-subtle);--bs-list-group-active-color: var(--bs-light-bg-subtle);--bs-list-group-active-bg: var(--bs-light-text-emphasis);--bs-list-group-active-border-color: var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color: var(--bs-dark-text-emphasis);--bs-list-group-bg: var(--bs-dark-bg-subtle);--bs-list-group-border-color: var(--bs-dark-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-dark-border-subtle);--bs-list-group-active-color: var(--bs-dark-bg-subtle);--bs-list-group-active-bg: var(--bs-dark-text-emphasis);--bs-list-group-active-border-color: var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color: #000;--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity: 0.5;--bs-btn-close-hover-opacity: 0.75;--bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(39, 128, 227, 0.25);--bs-btn-close-focus-opacity: 1;--bs-btn-close-disabled-opacity: 0.25;--bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:rgba(0,0,0,0) var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex: 1090;--bs-toast-padding-x: 0.75rem;--bs-toast-padding-y: 0.5rem;--bs-toast-spacing: 1.5rem;--bs-toast-max-width: 350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg: rgba(255, 255, 255, 0.85);--bs-toast-border-width: 1px;--bs-toast-border-color: rgba(0, 0, 0, 0.175);--bs-toast-border-radius: 0.25rem;--bs-toast-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-toast-header-color: rgba(52, 58, 64, 0.75);--bs-toast-header-bg: rgba(255, 255, 255, 0.85);--bs-toast-header-border-color: rgba(0, 0, 0, 0.175);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex: 1090;position:absolute;z-index:var(--bs-toast-zindex);width:max-content;width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:-o-max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color)}.toast-header .btn-close{margin-right:calc(-0.5*var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex: 1055;--bs-modal-width: 500px;--bs-modal-padding: 1rem;--bs-modal-margin: 0.5rem;--bs-modal-color: ;--bs-modal-bg: #fff;--bs-modal-border-color: rgba(0, 0, 0, 0.175);--bs-modal-border-width: 1px;--bs-modal-border-radius: 0.5rem;--bs-modal-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-modal-inner-border-radius: calc(0.5rem - 1px);--bs-modal-header-padding-x: 1rem;--bs-modal-header-padding-y: 1rem;--bs-modal-header-padding: 1rem 1rem;--bs-modal-header-border-color: #dee2e6;--bs-modal-header-border-width: 1px;--bs-modal-title-line-height: 1.5;--bs-modal-footer-gap: 0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color: #dee2e6;--bs-modal-footer-border-width: 1px;position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -50px)}@media(prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin)*2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;min-height:calc(100% - var(--bs-modal-margin)*2)}.modal-content{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);outline:0}.modal-backdrop{--bs-backdrop-zindex: 1050;--bs-backdrop-bg: #000;--bs-backdrop-opacity: 0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y)*.5) calc(var(--bs-modal-header-padding-x)*.5);margin:calc(-0.5*var(--bs-modal-header-padding-y)) calc(-0.5*var(--bs-modal-header-padding-x)) calc(-0.5*var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:flex-end;-webkit-justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap)*.5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap)*.5)}@media(min-width: 576px){.modal{--bs-modal-margin: 1.75rem;--bs-modal-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width: 300px}}@media(min-width: 992px){.modal-lg,.modal-xl{--bs-modal-width: 800px}}@media(min-width: 1200px){.modal-xl{--bs-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0}.modal-fullscreen .modal-body{overflow-y:auto}@media(max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media(max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media(max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media(max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media(max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex: 1080;--bs-tooltip-max-width: 200px;--bs-tooltip-padding-x: 0.5rem;--bs-tooltip-padding-y: 0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color: #fff;--bs-tooltip-bg: #000;--bs-tooltip-border-radius: 0.25rem;--bs-tooltip-opacity: 0.9;--bs-tooltip-arrow-width: 0.8rem;--bs-tooltip-arrow-height: 0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:"Source Sans Pro",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-bottom .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) 0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg)}.popover{--bs-popover-zindex: 1070;--bs-popover-max-width: 276px;--bs-popover-font-size:0.875rem;--bs-popover-bg: #fff;--bs-popover-border-width: 1px;--bs-popover-border-color: rgba(0, 0, 0, 0.175);--bs-popover-border-radius: 0.5rem;--bs-popover-inner-border-radius: calc(0.5rem - 1px);--bs-popover-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-popover-header-padding-x: 1rem;--bs-popover-header-padding-y: 0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color: inherit;--bs-popover-header-bg: #e9ecef;--bs-popover-body-padding-x: 1rem;--bs-popover-body-padding-y: 1rem;--bs-popover-body-color: #343a40;--bs-popover-arrow-width: 1rem;--bs-popover-arrow-height: 0.5rem;--bs-popover-arrow-border: var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:"Source Sans Pro",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:rgba(0,0,0,0);border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{border-width:0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-0.5*var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) 0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y;-webkit-touch-action:pan-y;-moz-touch-action:pan-y;-ms-touch-action:pan-y;-o-touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:center;-webkit-justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;display:-webkit-flex;justify-content:center;-webkit-justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;-webkit-flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid rgba(0,0,0,0);border-bottom:10px solid rgba(0,0,0,0);opacity:.5;transition:opacity .6s ease}@media(prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-grow,.spinner-border{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-border-width: 0.25em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:rgba(0,0,0,0)}.spinner-border-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem;--bs-spinner-border-width: 0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--bs-offcanvas-zindex: 1045;--bs-offcanvas-width: 400px;--bs-offcanvas-height: 30vh;--bs-offcanvas-padding-x: 1rem;--bs-offcanvas-padding-y: 1rem;--bs-offcanvas-color: #343a40;--bs-offcanvas-bg: #fff;--bs-offcanvas-border-width: 1px;--bs-offcanvas-border-color: rgba(0, 0, 0, 0.175);--bs-offcanvas-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-offcanvas-transition: transform 0.3s ease-in-out;--bs-offcanvas-title-line-height: 1.5}@media(max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 575.98px)and (prefers-reduced-motion: reduce){.offcanvas-sm{transition:none}}@media(max-width: 575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.showing,.offcanvas-sm.show:not(.hiding){transform:none}.offcanvas-sm.showing,.offcanvas-sm.hiding,.offcanvas-sm.show{visibility:visible}}@media(min-width: 576px){.offcanvas-sm{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 767.98px)and (prefers-reduced-motion: reduce){.offcanvas-md{transition:none}}@media(max-width: 767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.showing,.offcanvas-md.show:not(.hiding){transform:none}.offcanvas-md.showing,.offcanvas-md.hiding,.offcanvas-md.show{visibility:visible}}@media(min-width: 768px){.offcanvas-md{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 991.98px)and (prefers-reduced-motion: reduce){.offcanvas-lg{transition:none}}@media(max-width: 991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.showing,.offcanvas-lg.show:not(.hiding){transform:none}.offcanvas-lg.showing,.offcanvas-lg.hiding,.offcanvas-lg.show{visibility:visible}}@media(min-width: 992px){.offcanvas-lg{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1199.98px)and (prefers-reduced-motion: reduce){.offcanvas-xl{transition:none}}@media(max-width: 1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.showing,.offcanvas-xl.show:not(.hiding){transform:none}.offcanvas-xl.showing,.offcanvas-xl.hiding,.offcanvas-xl.show{visibility:visible}}@media(min-width: 1200px){.offcanvas-xl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1399.98px)and (prefers-reduced-motion: reduce){.offcanvas-xxl{transition:none}}@media(max-width: 1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.showing,.offcanvas-xxl.show:not(.hiding){transform:none}.offcanvas-xxl.showing,.offcanvas-xxl.hiding,.offcanvas-xxl.show{visibility:visible}}@media(min-width: 1400px){.offcanvas-xxl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media(prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y)*.5) calc(var(--bs-offcanvas-padding-x)*.5);margin-top:calc(-0.5*var(--bs-offcanvas-padding-y));margin-right:calc(-0.5*var(--bs-offcanvas-padding-x));margin-bottom:calc(-0.5*var(--bs-offcanvas-padding-y))}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;-webkit-flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);-webkit-mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);mask-size:200% 100%;-webkit-mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{mask-position:-200% 0%;-webkit-mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-default{color:#fff !important;background-color:RGBA(var(--bs-default-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-primary{color:#fff !important;background-color:RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-secondary{color:#fff !important;background-color:RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-success{color:#fff !important;background-color:RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-info{color:#fff !important;background-color:RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-warning{color:#fff !important;background-color:RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-danger{color:#fff !important;background-color:RGBA(var(--bs-danger-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-light{color:#000 !important;background-color:RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-dark{color:#fff !important;background-color:RGBA(var(--bs-dark-rgb), var(--bs-bg-opacity, 1)) !important}.link-default{color:RGBA(var(--bs-default-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-default-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-default:hover,.link-default:focus{color:RGBA(42, 46, 51, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(42, 46, 51, var(--bs-link-underline-opacity, 1)) !important}.link-primary{color:RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-primary:hover,.link-primary:focus{color:RGBA(31, 102, 182, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(31, 102, 182, var(--bs-link-underline-opacity, 1)) !important}.link-secondary{color:RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-secondary:hover,.link-secondary:focus{color:RGBA(42, 46, 51, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(42, 46, 51, var(--bs-link-underline-opacity, 1)) !important}.link-success{color:RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-success:hover,.link-success:focus{color:RGBA(50, 146, 19, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(50, 146, 19, var(--bs-link-underline-opacity, 1)) !important}.link-info{color:RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-info:hover,.link-info:focus{color:RGBA(122, 67, 150, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(122, 67, 150, var(--bs-link-underline-opacity, 1)) !important}.link-warning{color:RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-warning:hover,.link-warning:focus{color:RGBA(204, 94, 19, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(204, 94, 19, var(--bs-link-underline-opacity, 1)) !important}.link-danger{color:RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-danger:hover,.link-danger:focus{color:RGBA(204, 0, 46, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(204, 0, 46, var(--bs-link-underline-opacity, 1)) !important}.link-light{color:RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-light:hover,.link-light:focus{color:RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important}.link-dark{color:RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-dark:hover,.link-dark:focus{color:RGBA(42, 46, 51, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(42, 46, 51, var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis:hover,.link-body-emphasis:focus{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 0.75)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-align-items:center;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));text-underline-offset:.25em;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;-webkit-flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media(prefers-reduced-motion: reduce){.icon-link>.bi{transition:none}}.icon-link-hover:hover>.bi,.icon-link-hover:focus-visible>.bi{transform:var(--bs-icon-link-transform, translate3d(0.25em, 0, 0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}.sticky-bottom{position:sticky;bottom:0;z-index:1020}@media(min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;display:-webkit-flex;flex-direction:row;-webkit-flex-direction:row;align-items:center;-webkit-align-items:center;align-self:stretch;-webkit-align-self:stretch}.vstack{display:flex;display:-webkit-flex;flex:1 1 auto;-webkit-flex:1 1 auto;flex-direction:column;-webkit-flex-direction:column;align-self:stretch;-webkit-align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}.visually-hidden:not(caption),.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption){position:absolute !important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;-webkit-align-self:stretch;width:1px;min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.object-fit-contain{object-fit:contain !important}.object-fit-cover{object-fit:cover !important}.object-fit-fill{object-fit:fill !important}.object-fit-scale{object-fit:scale-down !important}.object-fit-none{object-fit:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.overflow-x-auto{overflow-x:auto !important}.overflow-x-hidden{overflow-x:hidden !important}.overflow-x-visible{overflow-x:visible !important}.overflow-x-scroll{overflow-x:scroll !important}.overflow-y-auto{overflow-y:auto !important}.overflow-y-hidden{overflow-y:hidden !important}.overflow-y-visible{overflow-y:visible !important}.overflow-y-scroll{overflow-y:scroll !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-grid{display:grid !important}.d-inline-grid{display:inline-grid !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:flex !important}.d-inline-flex{display:inline-flex !important}.d-none{display:none !important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15) !important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075) !important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175) !important}.shadow-none{box-shadow:none !important}.focus-ring-default{--bs-focus-ring-color: rgba(var(--bs-default-rgb), var(--bs-focus-ring-opacity))}.focus-ring-primary{--bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.top-0{top:0 !important}.top-50{top:50% !important}.top-100{top:100% !important}.bottom-0{bottom:0 !important}.bottom-50{bottom:50% !important}.bottom-100{bottom:100% !important}.start-0{left:0 !important}.start-50{left:50% !important}.start-100{left:100% !important}.end-0{right:0 !important}.end-50{right:50% !important}.end-100{right:100% !important}.translate-middle{transform:translate(-50%, -50%) !important}.translate-middle-x{transform:translateX(-50%) !important}.translate-middle-y{transform:translateY(-50%) !important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-0{border:0 !important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-top-0{border-top:0 !important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-start-0{border-left:0 !important}.border-default{--bs-border-opacity: 1;border-color:rgba(var(--bs-default-rgb), var(--bs-border-opacity)) !important}.border-primary{--bs-border-opacity: 1;border-color:rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important}.border-secondary{--bs-border-opacity: 1;border-color:rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important}.border-success{--bs-border-opacity: 1;border-color:rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important}.border-info{--bs-border-opacity: 1;border-color:rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important}.border-warning{--bs-border-opacity: 1;border-color:rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important}.border-danger{--bs-border-opacity: 1;border-color:rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important}.border-light{--bs-border-opacity: 1;border-color:rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important}.border-dark{--bs-border-opacity: 1;border-color:rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important}.border-black{--bs-border-opacity: 1;border-color:rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important}.border-white{--bs-border-opacity: 1;border-color:rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle) !important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle) !important}.border-success-subtle{border-color:var(--bs-success-border-subtle) !important}.border-info-subtle{border-color:var(--bs-info-border-subtle) !important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle) !important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle) !important}.border-light-subtle{border-color:var(--bs-light-border-subtle) !important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle) !important}.border-1{border-width:1px !important}.border-2{border-width:2px !important}.border-3{border-width:3px !important}.border-4{border-width:4px !important}.border-5{border-width:5px !important}.border-opacity-10{--bs-border-opacity: 0.1}.border-opacity-25{--bs-border-opacity: 0.25}.border-opacity-50{--bs-border-opacity: 0.5}.border-opacity-75{--bs-border-opacity: 0.75}.border-opacity-100{--bs-border-opacity: 1}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.mw-100{max-width:100% !important}.vw-100{width:100vw !important}.min-vw-100{min-width:100vw !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mh-100{max-height:100% !important}.vh-100{height:100vh !important}.min-vh-100{min-height:100vh !important}.flex-fill{flex:1 1 auto !important}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.flex-shrink-0{flex-shrink:0 !important}.flex-shrink-1{flex-shrink:1 !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.justify-content-evenly{justify-content:space-evenly !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}.order-first{order:-1 !important}.order-0{order:0 !important}.order-1{order:1 !important}.order-2{order:2 !important}.order-3{order:3 !important}.order-4{order:4 !important}.order-5{order:5 !important}.order-last{order:6 !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.m-auto{margin:auto !important}.mx-0{margin-right:0 !important;margin-left:0 !important}.mx-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-3{margin-right:1rem !important;margin-left:1rem !important}.mx-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-5{margin-right:3rem !important;margin-left:3rem !important}.mx-auto{margin-right:auto !important;margin-left:auto !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mt-auto{margin-top:auto !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.me-auto{margin-right:auto !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.mb-auto{margin-bottom:auto !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.ms-auto{margin-left:auto !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.px-0{padding-right:0 !important;padding-left:0 !important}.px-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-3{padding-right:1rem !important;padding-left:1rem !important}.px-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-5{padding-right:3rem !important;padding-left:3rem !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.row-gap-0{row-gap:0 !important}.row-gap-1{row-gap:.25rem !important}.row-gap-2{row-gap:.5rem !important}.row-gap-3{row-gap:1rem !important}.row-gap-4{row-gap:1.5rem !important}.row-gap-5{row-gap:3rem !important}.column-gap-0{column-gap:0 !important}.column-gap-1{column-gap:.25rem !important}.column-gap-2{column-gap:.5rem !important}.column-gap-3{column-gap:1rem !important}.column-gap-4{column-gap:1.5rem !important}.column-gap-5{column-gap:3rem !important}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.325rem + 0.9vw) !important}.fs-2{font-size:calc(1.29rem + 0.48vw) !important}.fs-3{font-size:calc(1.27rem + 0.24vw) !important}.fs-4{font-size:1.25rem !important}.fs-5{font-size:1.1rem !important}.fs-6{font-size:1rem !important}.fst-italic{font-style:italic !important}.fst-normal{font-style:normal !important}.fw-lighter{font-weight:lighter !important}.fw-light{font-weight:300 !important}.fw-normal{font-weight:400 !important}.fw-medium{font-weight:500 !important}.fw-semibold{font-weight:600 !important}.fw-bold{font-weight:700 !important}.fw-bolder{font-weight:bolder !important}.lh-1{line-height:1 !important}.lh-sm{line-height:1.25 !important}.lh-base{line-height:1.5 !important}.lh-lg{line-height:2 !important}.text-start{text-align:left !important}.text-end{text-align:right !important}.text-center{text-align:center !important}.text-decoration-none{text-decoration:none !important}.text-decoration-underline{text-decoration:underline !important}.text-decoration-line-through{text-decoration:line-through !important}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-wrap{white-space:normal !important}.text-nowrap{white-space:nowrap !important}.text-break{word-wrap:break-word !important;word-break:break-word !important}.text-default{--bs-text-opacity: 1;color:rgba(var(--bs-default-rgb), var(--bs-text-opacity)) !important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-black-50{--bs-text-opacity: 1;color:rgba(0,0,0,.5) !important}.text-white-50{--bs-text-opacity: 1;color:rgba(255,255,255,.5) !important}.text-body-secondary{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-body-tertiary{--bs-text-opacity: 1;color:var(--bs-tertiary-color) !important}.text-body-emphasis{--bs-text-opacity: 1;color:var(--bs-emphasis-color) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis) !important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis) !important}.text-success-emphasis{color:var(--bs-success-text-emphasis) !important}.text-info-emphasis{color:var(--bs-info-text-emphasis) !important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis) !important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis) !important}.text-light-emphasis{color:var(--bs-light-text-emphasis) !important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis) !important}.link-opacity-10{--bs-link-opacity: 0.1}.link-opacity-10-hover:hover{--bs-link-opacity: 0.1}.link-opacity-25{--bs-link-opacity: 0.25}.link-opacity-25-hover:hover{--bs-link-opacity: 0.25}.link-opacity-50{--bs-link-opacity: 0.5}.link-opacity-50-hover:hover{--bs-link-opacity: 0.5}.link-opacity-75{--bs-link-opacity: 0.75}.link-opacity-75-hover:hover{--bs-link-opacity: 0.75}.link-opacity-100{--bs-link-opacity: 1}.link-opacity-100-hover:hover{--bs-link-opacity: 1}.link-offset-1{text-underline-offset:.125em !important}.link-offset-1-hover:hover{text-underline-offset:.125em !important}.link-offset-2{text-underline-offset:.25em !important}.link-offset-2-hover:hover{text-underline-offset:.25em !important}.link-offset-3{text-underline-offset:.375em !important}.link-offset-3-hover:hover{text-underline-offset:.375em !important}.link-underline-default{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-default-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-primary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-secondary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-success{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-info{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-warning{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-danger{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-light{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-dark{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important}.link-underline{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-underline-opacity-0{--bs-link-underline-opacity: 0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity: 0}.link-underline-opacity-10{--bs-link-underline-opacity: 0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity: 0.1}.link-underline-opacity-25{--bs-link-underline-opacity: 0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity: 0.25}.link-underline-opacity-50{--bs-link-underline-opacity: 0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity: 0.5}.link-underline-opacity-75{--bs-link-underline-opacity: 0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity: 0.75}.link-underline-opacity-100{--bs-link-underline-opacity: 1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity: 1}.bg-default{--bs-bg-opacity: 1;background-color:rgba(var(--bs-default-rgb), var(--bs-bg-opacity)) !important}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:rgba(0,0,0,0) !important}.bg-body-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-body-tertiary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-tertiary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle) !important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle) !important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle) !important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle) !important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle) !important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle) !important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle) !important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle) !important}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{user-select:all !important}.user-select-auto{user-select:auto !important}.user-select-none{user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:var(--bs-border-radius) !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:var(--bs-border-radius-sm) !important}.rounded-2{border-radius:var(--bs-border-radius) !important}.rounded-3{border-radius:var(--bs-border-radius-lg) !important}.rounded-4{border-radius:var(--bs-border-radius-xl) !important}.rounded-5{border-radius:var(--bs-border-radius-xxl) !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:var(--bs-border-radius-pill) !important}.rounded-top{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-0{border-top-left-radius:0 !important;border-top-right-radius:0 !important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm) !important;border-top-right-radius:var(--bs-border-radius-sm) !important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg) !important;border-top-right-radius:var(--bs-border-radius-lg) !important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl) !important;border-top-right-radius:var(--bs-border-radius-xl) !important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl) !important;border-top-right-radius:var(--bs-border-radius-xxl) !important}.rounded-top-circle{border-top-left-radius:50% !important;border-top-right-radius:50% !important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill) !important;border-top-right-radius:var(--bs-border-radius-pill) !important}.rounded-end{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-0{border-top-right-radius:0 !important;border-bottom-right-radius:0 !important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm) !important;border-bottom-right-radius:var(--bs-border-radius-sm) !important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg) !important;border-bottom-right-radius:var(--bs-border-radius-lg) !important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl) !important;border-bottom-right-radius:var(--bs-border-radius-xl) !important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-right-radius:var(--bs-border-radius-xxl) !important}.rounded-end-circle{border-top-right-radius:50% !important;border-bottom-right-radius:50% !important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill) !important;border-bottom-right-radius:var(--bs-border-radius-pill) !important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-0{border-bottom-right-radius:0 !important;border-bottom-left-radius:0 !important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm) !important;border-bottom-left-radius:var(--bs-border-radius-sm) !important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg) !important;border-bottom-left-radius:var(--bs-border-radius-lg) !important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl) !important;border-bottom-left-radius:var(--bs-border-radius-xl) !important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-left-radius:var(--bs-border-radius-xxl) !important}.rounded-bottom-circle{border-bottom-right-radius:50% !important;border-bottom-left-radius:50% !important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill) !important;border-bottom-left-radius:var(--bs-border-radius-pill) !important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-0{border-bottom-left-radius:0 !important;border-top-left-radius:0 !important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm) !important;border-top-left-radius:var(--bs-border-radius-sm) !important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg) !important;border-top-left-radius:var(--bs-border-radius-lg) !important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl) !important;border-top-left-radius:var(--bs-border-radius-xl) !important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl) !important;border-top-left-radius:var(--bs-border-radius-xxl) !important}.rounded-start-circle{border-bottom-left-radius:50% !important;border-top-left-radius:50% !important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill) !important;border-top-left-radius:var(--bs-border-radius-pill) !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}.z-n1{z-index:-1 !important}.z-0{z-index:0 !important}.z-1{z-index:1 !important}.z-2{z-index:2 !important}.z-3{z-index:3 !important}@media(min-width: 576px){.float-sm-start{float:left !important}.float-sm-end{float:right !important}.float-sm-none{float:none !important}.object-fit-sm-contain{object-fit:contain !important}.object-fit-sm-cover{object-fit:cover !important}.object-fit-sm-fill{object-fit:fill !important}.object-fit-sm-scale{object-fit:scale-down !important}.object-fit-sm-none{object-fit:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-grid{display:grid !important}.d-sm-inline-grid{display:inline-grid !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:flex !important}.d-sm-inline-flex{display:inline-flex !important}.d-sm-none{display:none !important}.flex-sm-fill{flex:1 1 auto !important}.flex-sm-row{flex-direction:row !important}.flex-sm-column{flex-direction:column !important}.flex-sm-row-reverse{flex-direction:row-reverse !important}.flex-sm-column-reverse{flex-direction:column-reverse !important}.flex-sm-grow-0{flex-grow:0 !important}.flex-sm-grow-1{flex-grow:1 !important}.flex-sm-shrink-0{flex-shrink:0 !important}.flex-sm-shrink-1{flex-shrink:1 !important}.flex-sm-wrap{flex-wrap:wrap !important}.flex-sm-nowrap{flex-wrap:nowrap !important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-sm-start{justify-content:flex-start !important}.justify-content-sm-end{justify-content:flex-end !important}.justify-content-sm-center{justify-content:center !important}.justify-content-sm-between{justify-content:space-between !important}.justify-content-sm-around{justify-content:space-around !important}.justify-content-sm-evenly{justify-content:space-evenly !important}.align-items-sm-start{align-items:flex-start !important}.align-items-sm-end{align-items:flex-end !important}.align-items-sm-center{align-items:center !important}.align-items-sm-baseline{align-items:baseline !important}.align-items-sm-stretch{align-items:stretch !important}.align-content-sm-start{align-content:flex-start !important}.align-content-sm-end{align-content:flex-end !important}.align-content-sm-center{align-content:center !important}.align-content-sm-between{align-content:space-between !important}.align-content-sm-around{align-content:space-around !important}.align-content-sm-stretch{align-content:stretch !important}.align-self-sm-auto{align-self:auto !important}.align-self-sm-start{align-self:flex-start !important}.align-self-sm-end{align-self:flex-end !important}.align-self-sm-center{align-self:center !important}.align-self-sm-baseline{align-self:baseline !important}.align-self-sm-stretch{align-self:stretch !important}.order-sm-first{order:-1 !important}.order-sm-0{order:0 !important}.order-sm-1{order:1 !important}.order-sm-2{order:2 !important}.order-sm-3{order:3 !important}.order-sm-4{order:4 !important}.order-sm-5{order:5 !important}.order-sm-last{order:6 !important}.m-sm-0{margin:0 !important}.m-sm-1{margin:.25rem !important}.m-sm-2{margin:.5rem !important}.m-sm-3{margin:1rem !important}.m-sm-4{margin:1.5rem !important}.m-sm-5{margin:3rem !important}.m-sm-auto{margin:auto !important}.mx-sm-0{margin-right:0 !important;margin-left:0 !important}.mx-sm-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-sm-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-sm-3{margin-right:1rem !important;margin-left:1rem !important}.mx-sm-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-sm-5{margin-right:3rem !important;margin-left:3rem !important}.mx-sm-auto{margin-right:auto !important;margin-left:auto !important}.my-sm-0{margin-top:0 !important;margin-bottom:0 !important}.my-sm-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-sm-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-sm-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-sm-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-sm-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-sm-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-sm-0{margin-top:0 !important}.mt-sm-1{margin-top:.25rem !important}.mt-sm-2{margin-top:.5rem !important}.mt-sm-3{margin-top:1rem !important}.mt-sm-4{margin-top:1.5rem !important}.mt-sm-5{margin-top:3rem !important}.mt-sm-auto{margin-top:auto !important}.me-sm-0{margin-right:0 !important}.me-sm-1{margin-right:.25rem !important}.me-sm-2{margin-right:.5rem !important}.me-sm-3{margin-right:1rem !important}.me-sm-4{margin-right:1.5rem !important}.me-sm-5{margin-right:3rem !important}.me-sm-auto{margin-right:auto !important}.mb-sm-0{margin-bottom:0 !important}.mb-sm-1{margin-bottom:.25rem !important}.mb-sm-2{margin-bottom:.5rem !important}.mb-sm-3{margin-bottom:1rem !important}.mb-sm-4{margin-bottom:1.5rem !important}.mb-sm-5{margin-bottom:3rem !important}.mb-sm-auto{margin-bottom:auto !important}.ms-sm-0{margin-left:0 !important}.ms-sm-1{margin-left:.25rem !important}.ms-sm-2{margin-left:.5rem !important}.ms-sm-3{margin-left:1rem !important}.ms-sm-4{margin-left:1.5rem !important}.ms-sm-5{margin-left:3rem !important}.ms-sm-auto{margin-left:auto !important}.p-sm-0{padding:0 !important}.p-sm-1{padding:.25rem !important}.p-sm-2{padding:.5rem !important}.p-sm-3{padding:1rem !important}.p-sm-4{padding:1.5rem !important}.p-sm-5{padding:3rem !important}.px-sm-0{padding-right:0 !important;padding-left:0 !important}.px-sm-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-sm-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-sm-3{padding-right:1rem !important;padding-left:1rem !important}.px-sm-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-sm-5{padding-right:3rem !important;padding-left:3rem !important}.py-sm-0{padding-top:0 !important;padding-bottom:0 !important}.py-sm-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-sm-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-sm-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-sm-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-sm-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-sm-0{padding-top:0 !important}.pt-sm-1{padding-top:.25rem !important}.pt-sm-2{padding-top:.5rem !important}.pt-sm-3{padding-top:1rem !important}.pt-sm-4{padding-top:1.5rem !important}.pt-sm-5{padding-top:3rem !important}.pe-sm-0{padding-right:0 !important}.pe-sm-1{padding-right:.25rem !important}.pe-sm-2{padding-right:.5rem !important}.pe-sm-3{padding-right:1rem !important}.pe-sm-4{padding-right:1.5rem !important}.pe-sm-5{padding-right:3rem !important}.pb-sm-0{padding-bottom:0 !important}.pb-sm-1{padding-bottom:.25rem !important}.pb-sm-2{padding-bottom:.5rem !important}.pb-sm-3{padding-bottom:1rem !important}.pb-sm-4{padding-bottom:1.5rem !important}.pb-sm-5{padding-bottom:3rem !important}.ps-sm-0{padding-left:0 !important}.ps-sm-1{padding-left:.25rem !important}.ps-sm-2{padding-left:.5rem !important}.ps-sm-3{padding-left:1rem !important}.ps-sm-4{padding-left:1.5rem !important}.ps-sm-5{padding-left:3rem !important}.gap-sm-0{gap:0 !important}.gap-sm-1{gap:.25rem !important}.gap-sm-2{gap:.5rem !important}.gap-sm-3{gap:1rem !important}.gap-sm-4{gap:1.5rem !important}.gap-sm-5{gap:3rem !important}.row-gap-sm-0{row-gap:0 !important}.row-gap-sm-1{row-gap:.25rem !important}.row-gap-sm-2{row-gap:.5rem !important}.row-gap-sm-3{row-gap:1rem !important}.row-gap-sm-4{row-gap:1.5rem !important}.row-gap-sm-5{row-gap:3rem !important}.column-gap-sm-0{column-gap:0 !important}.column-gap-sm-1{column-gap:.25rem !important}.column-gap-sm-2{column-gap:.5rem !important}.column-gap-sm-3{column-gap:1rem !important}.column-gap-sm-4{column-gap:1.5rem !important}.column-gap-sm-5{column-gap:3rem !important}.text-sm-start{text-align:left !important}.text-sm-end{text-align:right !important}.text-sm-center{text-align:center !important}}@media(min-width: 768px){.float-md-start{float:left !important}.float-md-end{float:right !important}.float-md-none{float:none !important}.object-fit-md-contain{object-fit:contain !important}.object-fit-md-cover{object-fit:cover !important}.object-fit-md-fill{object-fit:fill !important}.object-fit-md-scale{object-fit:scale-down !important}.object-fit-md-none{object-fit:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-grid{display:grid !important}.d-md-inline-grid{display:inline-grid !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:flex !important}.d-md-inline-flex{display:inline-flex !important}.d-md-none{display:none !important}.flex-md-fill{flex:1 1 auto !important}.flex-md-row{flex-direction:row !important}.flex-md-column{flex-direction:column !important}.flex-md-row-reverse{flex-direction:row-reverse !important}.flex-md-column-reverse{flex-direction:column-reverse !important}.flex-md-grow-0{flex-grow:0 !important}.flex-md-grow-1{flex-grow:1 !important}.flex-md-shrink-0{flex-shrink:0 !important}.flex-md-shrink-1{flex-shrink:1 !important}.flex-md-wrap{flex-wrap:wrap !important}.flex-md-nowrap{flex-wrap:nowrap !important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-md-start{justify-content:flex-start !important}.justify-content-md-end{justify-content:flex-end !important}.justify-content-md-center{justify-content:center !important}.justify-content-md-between{justify-content:space-between !important}.justify-content-md-around{justify-content:space-around !important}.justify-content-md-evenly{justify-content:space-evenly !important}.align-items-md-start{align-items:flex-start !important}.align-items-md-end{align-items:flex-end !important}.align-items-md-center{align-items:center !important}.align-items-md-baseline{align-items:baseline !important}.align-items-md-stretch{align-items:stretch !important}.align-content-md-start{align-content:flex-start !important}.align-content-md-end{align-content:flex-end !important}.align-content-md-center{align-content:center !important}.align-content-md-between{align-content:space-between !important}.align-content-md-around{align-content:space-around !important}.align-content-md-stretch{align-content:stretch !important}.align-self-md-auto{align-self:auto !important}.align-self-md-start{align-self:flex-start !important}.align-self-md-end{align-self:flex-end !important}.align-self-md-center{align-self:center !important}.align-self-md-baseline{align-self:baseline !important}.align-self-md-stretch{align-self:stretch !important}.order-md-first{order:-1 !important}.order-md-0{order:0 !important}.order-md-1{order:1 !important}.order-md-2{order:2 !important}.order-md-3{order:3 !important}.order-md-4{order:4 !important}.order-md-5{order:5 !important}.order-md-last{order:6 !important}.m-md-0{margin:0 !important}.m-md-1{margin:.25rem !important}.m-md-2{margin:.5rem !important}.m-md-3{margin:1rem !important}.m-md-4{margin:1.5rem !important}.m-md-5{margin:3rem !important}.m-md-auto{margin:auto !important}.mx-md-0{margin-right:0 !important;margin-left:0 !important}.mx-md-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-md-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-md-3{margin-right:1rem !important;margin-left:1rem !important}.mx-md-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-md-5{margin-right:3rem !important;margin-left:3rem !important}.mx-md-auto{margin-right:auto !important;margin-left:auto !important}.my-md-0{margin-top:0 !important;margin-bottom:0 !important}.my-md-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-md-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-md-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-md-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-md-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-md-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-md-0{margin-top:0 !important}.mt-md-1{margin-top:.25rem !important}.mt-md-2{margin-top:.5rem !important}.mt-md-3{margin-top:1rem !important}.mt-md-4{margin-top:1.5rem !important}.mt-md-5{margin-top:3rem !important}.mt-md-auto{margin-top:auto !important}.me-md-0{margin-right:0 !important}.me-md-1{margin-right:.25rem !important}.me-md-2{margin-right:.5rem !important}.me-md-3{margin-right:1rem !important}.me-md-4{margin-right:1.5rem !important}.me-md-5{margin-right:3rem !important}.me-md-auto{margin-right:auto !important}.mb-md-0{margin-bottom:0 !important}.mb-md-1{margin-bottom:.25rem !important}.mb-md-2{margin-bottom:.5rem !important}.mb-md-3{margin-bottom:1rem !important}.mb-md-4{margin-bottom:1.5rem !important}.mb-md-5{margin-bottom:3rem !important}.mb-md-auto{margin-bottom:auto !important}.ms-md-0{margin-left:0 !important}.ms-md-1{margin-left:.25rem !important}.ms-md-2{margin-left:.5rem !important}.ms-md-3{margin-left:1rem !important}.ms-md-4{margin-left:1.5rem !important}.ms-md-5{margin-left:3rem !important}.ms-md-auto{margin-left:auto !important}.p-md-0{padding:0 !important}.p-md-1{padding:.25rem !important}.p-md-2{padding:.5rem !important}.p-md-3{padding:1rem !important}.p-md-4{padding:1.5rem !important}.p-md-5{padding:3rem !important}.px-md-0{padding-right:0 !important;padding-left:0 !important}.px-md-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-md-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-md-3{padding-right:1rem !important;padding-left:1rem !important}.px-md-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-md-5{padding-right:3rem !important;padding-left:3rem !important}.py-md-0{padding-top:0 !important;padding-bottom:0 !important}.py-md-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-md-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-md-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-md-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-md-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-md-0{padding-top:0 !important}.pt-md-1{padding-top:.25rem !important}.pt-md-2{padding-top:.5rem !important}.pt-md-3{padding-top:1rem !important}.pt-md-4{padding-top:1.5rem !important}.pt-md-5{padding-top:3rem !important}.pe-md-0{padding-right:0 !important}.pe-md-1{padding-right:.25rem !important}.pe-md-2{padding-right:.5rem !important}.pe-md-3{padding-right:1rem !important}.pe-md-4{padding-right:1.5rem !important}.pe-md-5{padding-right:3rem !important}.pb-md-0{padding-bottom:0 !important}.pb-md-1{padding-bottom:.25rem !important}.pb-md-2{padding-bottom:.5rem !important}.pb-md-3{padding-bottom:1rem !important}.pb-md-4{padding-bottom:1.5rem !important}.pb-md-5{padding-bottom:3rem !important}.ps-md-0{padding-left:0 !important}.ps-md-1{padding-left:.25rem !important}.ps-md-2{padding-left:.5rem !important}.ps-md-3{padding-left:1rem !important}.ps-md-4{padding-left:1.5rem !important}.ps-md-5{padding-left:3rem !important}.gap-md-0{gap:0 !important}.gap-md-1{gap:.25rem !important}.gap-md-2{gap:.5rem !important}.gap-md-3{gap:1rem !important}.gap-md-4{gap:1.5rem !important}.gap-md-5{gap:3rem !important}.row-gap-md-0{row-gap:0 !important}.row-gap-md-1{row-gap:.25rem !important}.row-gap-md-2{row-gap:.5rem !important}.row-gap-md-3{row-gap:1rem !important}.row-gap-md-4{row-gap:1.5rem !important}.row-gap-md-5{row-gap:3rem !important}.column-gap-md-0{column-gap:0 !important}.column-gap-md-1{column-gap:.25rem !important}.column-gap-md-2{column-gap:.5rem !important}.column-gap-md-3{column-gap:1rem !important}.column-gap-md-4{column-gap:1.5rem !important}.column-gap-md-5{column-gap:3rem !important}.text-md-start{text-align:left !important}.text-md-end{text-align:right !important}.text-md-center{text-align:center !important}}@media(min-width: 992px){.float-lg-start{float:left !important}.float-lg-end{float:right !important}.float-lg-none{float:none !important}.object-fit-lg-contain{object-fit:contain !important}.object-fit-lg-cover{object-fit:cover !important}.object-fit-lg-fill{object-fit:fill !important}.object-fit-lg-scale{object-fit:scale-down !important}.object-fit-lg-none{object-fit:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-grid{display:grid !important}.d-lg-inline-grid{display:inline-grid !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:flex !important}.d-lg-inline-flex{display:inline-flex !important}.d-lg-none{display:none !important}.flex-lg-fill{flex:1 1 auto !important}.flex-lg-row{flex-direction:row !important}.flex-lg-column{flex-direction:column !important}.flex-lg-row-reverse{flex-direction:row-reverse !important}.flex-lg-column-reverse{flex-direction:column-reverse !important}.flex-lg-grow-0{flex-grow:0 !important}.flex-lg-grow-1{flex-grow:1 !important}.flex-lg-shrink-0{flex-shrink:0 !important}.flex-lg-shrink-1{flex-shrink:1 !important}.flex-lg-wrap{flex-wrap:wrap !important}.flex-lg-nowrap{flex-wrap:nowrap !important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-lg-start{justify-content:flex-start !important}.justify-content-lg-end{justify-content:flex-end !important}.justify-content-lg-center{justify-content:center !important}.justify-content-lg-between{justify-content:space-between !important}.justify-content-lg-around{justify-content:space-around !important}.justify-content-lg-evenly{justify-content:space-evenly !important}.align-items-lg-start{align-items:flex-start !important}.align-items-lg-end{align-items:flex-end !important}.align-items-lg-center{align-items:center !important}.align-items-lg-baseline{align-items:baseline !important}.align-items-lg-stretch{align-items:stretch !important}.align-content-lg-start{align-content:flex-start !important}.align-content-lg-end{align-content:flex-end !important}.align-content-lg-center{align-content:center !important}.align-content-lg-between{align-content:space-between !important}.align-content-lg-around{align-content:space-around !important}.align-content-lg-stretch{align-content:stretch !important}.align-self-lg-auto{align-self:auto !important}.align-self-lg-start{align-self:flex-start !important}.align-self-lg-end{align-self:flex-end !important}.align-self-lg-center{align-self:center !important}.align-self-lg-baseline{align-self:baseline !important}.align-self-lg-stretch{align-self:stretch !important}.order-lg-first{order:-1 !important}.order-lg-0{order:0 !important}.order-lg-1{order:1 !important}.order-lg-2{order:2 !important}.order-lg-3{order:3 !important}.order-lg-4{order:4 !important}.order-lg-5{order:5 !important}.order-lg-last{order:6 !important}.m-lg-0{margin:0 !important}.m-lg-1{margin:.25rem !important}.m-lg-2{margin:.5rem !important}.m-lg-3{margin:1rem !important}.m-lg-4{margin:1.5rem !important}.m-lg-5{margin:3rem !important}.m-lg-auto{margin:auto !important}.mx-lg-0{margin-right:0 !important;margin-left:0 !important}.mx-lg-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-lg-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-lg-3{margin-right:1rem !important;margin-left:1rem !important}.mx-lg-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-lg-5{margin-right:3rem !important;margin-left:3rem !important}.mx-lg-auto{margin-right:auto !important;margin-left:auto !important}.my-lg-0{margin-top:0 !important;margin-bottom:0 !important}.my-lg-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-lg-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-lg-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-lg-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-lg-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-lg-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-lg-0{margin-top:0 !important}.mt-lg-1{margin-top:.25rem !important}.mt-lg-2{margin-top:.5rem !important}.mt-lg-3{margin-top:1rem !important}.mt-lg-4{margin-top:1.5rem !important}.mt-lg-5{margin-top:3rem !important}.mt-lg-auto{margin-top:auto !important}.me-lg-0{margin-right:0 !important}.me-lg-1{margin-right:.25rem !important}.me-lg-2{margin-right:.5rem !important}.me-lg-3{margin-right:1rem !important}.me-lg-4{margin-right:1.5rem !important}.me-lg-5{margin-right:3rem !important}.me-lg-auto{margin-right:auto !important}.mb-lg-0{margin-bottom:0 !important}.mb-lg-1{margin-bottom:.25rem !important}.mb-lg-2{margin-bottom:.5rem !important}.mb-lg-3{margin-bottom:1rem !important}.mb-lg-4{margin-bottom:1.5rem !important}.mb-lg-5{margin-bottom:3rem !important}.mb-lg-auto{margin-bottom:auto !important}.ms-lg-0{margin-left:0 !important}.ms-lg-1{margin-left:.25rem !important}.ms-lg-2{margin-left:.5rem !important}.ms-lg-3{margin-left:1rem !important}.ms-lg-4{margin-left:1.5rem !important}.ms-lg-5{margin-left:3rem !important}.ms-lg-auto{margin-left:auto !important}.p-lg-0{padding:0 !important}.p-lg-1{padding:.25rem !important}.p-lg-2{padding:.5rem !important}.p-lg-3{padding:1rem !important}.p-lg-4{padding:1.5rem !important}.p-lg-5{padding:3rem !important}.px-lg-0{padding-right:0 !important;padding-left:0 !important}.px-lg-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-lg-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-lg-3{padding-right:1rem !important;padding-left:1rem !important}.px-lg-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-lg-5{padding-right:3rem !important;padding-left:3rem !important}.py-lg-0{padding-top:0 !important;padding-bottom:0 !important}.py-lg-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-lg-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-lg-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-lg-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-lg-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-lg-0{padding-top:0 !important}.pt-lg-1{padding-top:.25rem !important}.pt-lg-2{padding-top:.5rem !important}.pt-lg-3{padding-top:1rem !important}.pt-lg-4{padding-top:1.5rem !important}.pt-lg-5{padding-top:3rem !important}.pe-lg-0{padding-right:0 !important}.pe-lg-1{padding-right:.25rem !important}.pe-lg-2{padding-right:.5rem !important}.pe-lg-3{padding-right:1rem !important}.pe-lg-4{padding-right:1.5rem !important}.pe-lg-5{padding-right:3rem !important}.pb-lg-0{padding-bottom:0 !important}.pb-lg-1{padding-bottom:.25rem !important}.pb-lg-2{padding-bottom:.5rem !important}.pb-lg-3{padding-bottom:1rem !important}.pb-lg-4{padding-bottom:1.5rem !important}.pb-lg-5{padding-bottom:3rem !important}.ps-lg-0{padding-left:0 !important}.ps-lg-1{padding-left:.25rem !important}.ps-lg-2{padding-left:.5rem !important}.ps-lg-3{padding-left:1rem !important}.ps-lg-4{padding-left:1.5rem !important}.ps-lg-5{padding-left:3rem !important}.gap-lg-0{gap:0 !important}.gap-lg-1{gap:.25rem !important}.gap-lg-2{gap:.5rem !important}.gap-lg-3{gap:1rem !important}.gap-lg-4{gap:1.5rem !important}.gap-lg-5{gap:3rem !important}.row-gap-lg-0{row-gap:0 !important}.row-gap-lg-1{row-gap:.25rem !important}.row-gap-lg-2{row-gap:.5rem !important}.row-gap-lg-3{row-gap:1rem !important}.row-gap-lg-4{row-gap:1.5rem !important}.row-gap-lg-5{row-gap:3rem !important}.column-gap-lg-0{column-gap:0 !important}.column-gap-lg-1{column-gap:.25rem !important}.column-gap-lg-2{column-gap:.5rem !important}.column-gap-lg-3{column-gap:1rem !important}.column-gap-lg-4{column-gap:1.5rem !important}.column-gap-lg-5{column-gap:3rem !important}.text-lg-start{text-align:left !important}.text-lg-end{text-align:right !important}.text-lg-center{text-align:center !important}}@media(min-width: 1200px){.float-xl-start{float:left !important}.float-xl-end{float:right !important}.float-xl-none{float:none !important}.object-fit-xl-contain{object-fit:contain !important}.object-fit-xl-cover{object-fit:cover !important}.object-fit-xl-fill{object-fit:fill !important}.object-fit-xl-scale{object-fit:scale-down !important}.object-fit-xl-none{object-fit:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-grid{display:grid !important}.d-xl-inline-grid{display:inline-grid !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:flex !important}.d-xl-inline-flex{display:inline-flex !important}.d-xl-none{display:none !important}.flex-xl-fill{flex:1 1 auto !important}.flex-xl-row{flex-direction:row !important}.flex-xl-column{flex-direction:column !important}.flex-xl-row-reverse{flex-direction:row-reverse !important}.flex-xl-column-reverse{flex-direction:column-reverse !important}.flex-xl-grow-0{flex-grow:0 !important}.flex-xl-grow-1{flex-grow:1 !important}.flex-xl-shrink-0{flex-shrink:0 !important}.flex-xl-shrink-1{flex-shrink:1 !important}.flex-xl-wrap{flex-wrap:wrap !important}.flex-xl-nowrap{flex-wrap:nowrap !important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-xl-start{justify-content:flex-start !important}.justify-content-xl-end{justify-content:flex-end !important}.justify-content-xl-center{justify-content:center !important}.justify-content-xl-between{justify-content:space-between !important}.justify-content-xl-around{justify-content:space-around !important}.justify-content-xl-evenly{justify-content:space-evenly !important}.align-items-xl-start{align-items:flex-start !important}.align-items-xl-end{align-items:flex-end !important}.align-items-xl-center{align-items:center !important}.align-items-xl-baseline{align-items:baseline !important}.align-items-xl-stretch{align-items:stretch !important}.align-content-xl-start{align-content:flex-start !important}.align-content-xl-end{align-content:flex-end !important}.align-content-xl-center{align-content:center !important}.align-content-xl-between{align-content:space-between !important}.align-content-xl-around{align-content:space-around !important}.align-content-xl-stretch{align-content:stretch !important}.align-self-xl-auto{align-self:auto !important}.align-self-xl-start{align-self:flex-start !important}.align-self-xl-end{align-self:flex-end !important}.align-self-xl-center{align-self:center !important}.align-self-xl-baseline{align-self:baseline !important}.align-self-xl-stretch{align-self:stretch !important}.order-xl-first{order:-1 !important}.order-xl-0{order:0 !important}.order-xl-1{order:1 !important}.order-xl-2{order:2 !important}.order-xl-3{order:3 !important}.order-xl-4{order:4 !important}.order-xl-5{order:5 !important}.order-xl-last{order:6 !important}.m-xl-0{margin:0 !important}.m-xl-1{margin:.25rem !important}.m-xl-2{margin:.5rem !important}.m-xl-3{margin:1rem !important}.m-xl-4{margin:1.5rem !important}.m-xl-5{margin:3rem !important}.m-xl-auto{margin:auto !important}.mx-xl-0{margin-right:0 !important;margin-left:0 !important}.mx-xl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xl-auto{margin-right:auto !important;margin-left:auto !important}.my-xl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xl-0{margin-top:0 !important}.mt-xl-1{margin-top:.25rem !important}.mt-xl-2{margin-top:.5rem !important}.mt-xl-3{margin-top:1rem !important}.mt-xl-4{margin-top:1.5rem !important}.mt-xl-5{margin-top:3rem !important}.mt-xl-auto{margin-top:auto !important}.me-xl-0{margin-right:0 !important}.me-xl-1{margin-right:.25rem !important}.me-xl-2{margin-right:.5rem !important}.me-xl-3{margin-right:1rem !important}.me-xl-4{margin-right:1.5rem !important}.me-xl-5{margin-right:3rem !important}.me-xl-auto{margin-right:auto !important}.mb-xl-0{margin-bottom:0 !important}.mb-xl-1{margin-bottom:.25rem !important}.mb-xl-2{margin-bottom:.5rem !important}.mb-xl-3{margin-bottom:1rem !important}.mb-xl-4{margin-bottom:1.5rem !important}.mb-xl-5{margin-bottom:3rem !important}.mb-xl-auto{margin-bottom:auto !important}.ms-xl-0{margin-left:0 !important}.ms-xl-1{margin-left:.25rem !important}.ms-xl-2{margin-left:.5rem !important}.ms-xl-3{margin-left:1rem !important}.ms-xl-4{margin-left:1.5rem !important}.ms-xl-5{margin-left:3rem !important}.ms-xl-auto{margin-left:auto !important}.p-xl-0{padding:0 !important}.p-xl-1{padding:.25rem !important}.p-xl-2{padding:.5rem !important}.p-xl-3{padding:1rem !important}.p-xl-4{padding:1.5rem !important}.p-xl-5{padding:3rem !important}.px-xl-0{padding-right:0 !important;padding-left:0 !important}.px-xl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xl-0{padding-top:0 !important}.pt-xl-1{padding-top:.25rem !important}.pt-xl-2{padding-top:.5rem !important}.pt-xl-3{padding-top:1rem !important}.pt-xl-4{padding-top:1.5rem !important}.pt-xl-5{padding-top:3rem !important}.pe-xl-0{padding-right:0 !important}.pe-xl-1{padding-right:.25rem !important}.pe-xl-2{padding-right:.5rem !important}.pe-xl-3{padding-right:1rem !important}.pe-xl-4{padding-right:1.5rem !important}.pe-xl-5{padding-right:3rem !important}.pb-xl-0{padding-bottom:0 !important}.pb-xl-1{padding-bottom:.25rem !important}.pb-xl-2{padding-bottom:.5rem !important}.pb-xl-3{padding-bottom:1rem !important}.pb-xl-4{padding-bottom:1.5rem !important}.pb-xl-5{padding-bottom:3rem !important}.ps-xl-0{padding-left:0 !important}.ps-xl-1{padding-left:.25rem !important}.ps-xl-2{padding-left:.5rem !important}.ps-xl-3{padding-left:1rem !important}.ps-xl-4{padding-left:1.5rem !important}.ps-xl-5{padding-left:3rem !important}.gap-xl-0{gap:0 !important}.gap-xl-1{gap:.25rem !important}.gap-xl-2{gap:.5rem !important}.gap-xl-3{gap:1rem !important}.gap-xl-4{gap:1.5rem !important}.gap-xl-5{gap:3rem !important}.row-gap-xl-0{row-gap:0 !important}.row-gap-xl-1{row-gap:.25rem !important}.row-gap-xl-2{row-gap:.5rem !important}.row-gap-xl-3{row-gap:1rem !important}.row-gap-xl-4{row-gap:1.5rem !important}.row-gap-xl-5{row-gap:3rem !important}.column-gap-xl-0{column-gap:0 !important}.column-gap-xl-1{column-gap:.25rem !important}.column-gap-xl-2{column-gap:.5rem !important}.column-gap-xl-3{column-gap:1rem !important}.column-gap-xl-4{column-gap:1.5rem !important}.column-gap-xl-5{column-gap:3rem !important}.text-xl-start{text-align:left !important}.text-xl-end{text-align:right !important}.text-xl-center{text-align:center !important}}@media(min-width: 1400px){.float-xxl-start{float:left !important}.float-xxl-end{float:right !important}.float-xxl-none{float:none !important}.object-fit-xxl-contain{object-fit:contain !important}.object-fit-xxl-cover{object-fit:cover !important}.object-fit-xxl-fill{object-fit:fill !important}.object-fit-xxl-scale{object-fit:scale-down !important}.object-fit-xxl-none{object-fit:none !important}.d-xxl-inline{display:inline !important}.d-xxl-inline-block{display:inline-block !important}.d-xxl-block{display:block !important}.d-xxl-grid{display:grid !important}.d-xxl-inline-grid{display:inline-grid !important}.d-xxl-table{display:table !important}.d-xxl-table-row{display:table-row !important}.d-xxl-table-cell{display:table-cell !important}.d-xxl-flex{display:flex !important}.d-xxl-inline-flex{display:inline-flex !important}.d-xxl-none{display:none !important}.flex-xxl-fill{flex:1 1 auto !important}.flex-xxl-row{flex-direction:row !important}.flex-xxl-column{flex-direction:column !important}.flex-xxl-row-reverse{flex-direction:row-reverse !important}.flex-xxl-column-reverse{flex-direction:column-reverse !important}.flex-xxl-grow-0{flex-grow:0 !important}.flex-xxl-grow-1{flex-grow:1 !important}.flex-xxl-shrink-0{flex-shrink:0 !important}.flex-xxl-shrink-1{flex-shrink:1 !important}.flex-xxl-wrap{flex-wrap:wrap !important}.flex-xxl-nowrap{flex-wrap:nowrap !important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-xxl-start{justify-content:flex-start !important}.justify-content-xxl-end{justify-content:flex-end !important}.justify-content-xxl-center{justify-content:center !important}.justify-content-xxl-between{justify-content:space-between !important}.justify-content-xxl-around{justify-content:space-around !important}.justify-content-xxl-evenly{justify-content:space-evenly !important}.align-items-xxl-start{align-items:flex-start !important}.align-items-xxl-end{align-items:flex-end !important}.align-items-xxl-center{align-items:center !important}.align-items-xxl-baseline{align-items:baseline !important}.align-items-xxl-stretch{align-items:stretch !important}.align-content-xxl-start{align-content:flex-start !important}.align-content-xxl-end{align-content:flex-end !important}.align-content-xxl-center{align-content:center !important}.align-content-xxl-between{align-content:space-between !important}.align-content-xxl-around{align-content:space-around !important}.align-content-xxl-stretch{align-content:stretch !important}.align-self-xxl-auto{align-self:auto !important}.align-self-xxl-start{align-self:flex-start !important}.align-self-xxl-end{align-self:flex-end !important}.align-self-xxl-center{align-self:center !important}.align-self-xxl-baseline{align-self:baseline !important}.align-self-xxl-stretch{align-self:stretch !important}.order-xxl-first{order:-1 !important}.order-xxl-0{order:0 !important}.order-xxl-1{order:1 !important}.order-xxl-2{order:2 !important}.order-xxl-3{order:3 !important}.order-xxl-4{order:4 !important}.order-xxl-5{order:5 !important}.order-xxl-last{order:6 !important}.m-xxl-0{margin:0 !important}.m-xxl-1{margin:.25rem !important}.m-xxl-2{margin:.5rem !important}.m-xxl-3{margin:1rem !important}.m-xxl-4{margin:1.5rem !important}.m-xxl-5{margin:3rem !important}.m-xxl-auto{margin:auto !important}.mx-xxl-0{margin-right:0 !important;margin-left:0 !important}.mx-xxl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xxl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xxl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xxl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xxl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xxl-auto{margin-right:auto !important;margin-left:auto !important}.my-xxl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xxl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xxl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xxl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xxl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xxl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xxl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xxl-0{margin-top:0 !important}.mt-xxl-1{margin-top:.25rem !important}.mt-xxl-2{margin-top:.5rem !important}.mt-xxl-3{margin-top:1rem !important}.mt-xxl-4{margin-top:1.5rem !important}.mt-xxl-5{margin-top:3rem !important}.mt-xxl-auto{margin-top:auto !important}.me-xxl-0{margin-right:0 !important}.me-xxl-1{margin-right:.25rem !important}.me-xxl-2{margin-right:.5rem !important}.me-xxl-3{margin-right:1rem !important}.me-xxl-4{margin-right:1.5rem !important}.me-xxl-5{margin-right:3rem !important}.me-xxl-auto{margin-right:auto !important}.mb-xxl-0{margin-bottom:0 !important}.mb-xxl-1{margin-bottom:.25rem !important}.mb-xxl-2{margin-bottom:.5rem !important}.mb-xxl-3{margin-bottom:1rem !important}.mb-xxl-4{margin-bottom:1.5rem !important}.mb-xxl-5{margin-bottom:3rem !important}.mb-xxl-auto{margin-bottom:auto !important}.ms-xxl-0{margin-left:0 !important}.ms-xxl-1{margin-left:.25rem !important}.ms-xxl-2{margin-left:.5rem !important}.ms-xxl-3{margin-left:1rem !important}.ms-xxl-4{margin-left:1.5rem !important}.ms-xxl-5{margin-left:3rem !important}.ms-xxl-auto{margin-left:auto !important}.p-xxl-0{padding:0 !important}.p-xxl-1{padding:.25rem !important}.p-xxl-2{padding:.5rem !important}.p-xxl-3{padding:1rem !important}.p-xxl-4{padding:1.5rem !important}.p-xxl-5{padding:3rem !important}.px-xxl-0{padding-right:0 !important;padding-left:0 !important}.px-xxl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xxl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xxl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xxl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xxl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xxl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xxl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xxl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xxl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xxl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xxl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xxl-0{padding-top:0 !important}.pt-xxl-1{padding-top:.25rem !important}.pt-xxl-2{padding-top:.5rem !important}.pt-xxl-3{padding-top:1rem !important}.pt-xxl-4{padding-top:1.5rem !important}.pt-xxl-5{padding-top:3rem !important}.pe-xxl-0{padding-right:0 !important}.pe-xxl-1{padding-right:.25rem !important}.pe-xxl-2{padding-right:.5rem !important}.pe-xxl-3{padding-right:1rem !important}.pe-xxl-4{padding-right:1.5rem !important}.pe-xxl-5{padding-right:3rem !important}.pb-xxl-0{padding-bottom:0 !important}.pb-xxl-1{padding-bottom:.25rem !important}.pb-xxl-2{padding-bottom:.5rem !important}.pb-xxl-3{padding-bottom:1rem !important}.pb-xxl-4{padding-bottom:1.5rem !important}.pb-xxl-5{padding-bottom:3rem !important}.ps-xxl-0{padding-left:0 !important}.ps-xxl-1{padding-left:.25rem !important}.ps-xxl-2{padding-left:.5rem !important}.ps-xxl-3{padding-left:1rem !important}.ps-xxl-4{padding-left:1.5rem !important}.ps-xxl-5{padding-left:3rem !important}.gap-xxl-0{gap:0 !important}.gap-xxl-1{gap:.25rem !important}.gap-xxl-2{gap:.5rem !important}.gap-xxl-3{gap:1rem !important}.gap-xxl-4{gap:1.5rem !important}.gap-xxl-5{gap:3rem !important}.row-gap-xxl-0{row-gap:0 !important}.row-gap-xxl-1{row-gap:.25rem !important}.row-gap-xxl-2{row-gap:.5rem !important}.row-gap-xxl-3{row-gap:1rem !important}.row-gap-xxl-4{row-gap:1.5rem !important}.row-gap-xxl-5{row-gap:3rem !important}.column-gap-xxl-0{column-gap:0 !important}.column-gap-xxl-1{column-gap:.25rem !important}.column-gap-xxl-2{column-gap:.5rem !important}.column-gap-xxl-3{column-gap:1rem !important}.column-gap-xxl-4{column-gap:1.5rem !important}.column-gap-xxl-5{column-gap:3rem !important}.text-xxl-start{text-align:left !important}.text-xxl-end{text-align:right !important}.text-xxl-center{text-align:center !important}}.bg-default{color:#fff}.bg-primary{color:#fff}.bg-secondary{color:#fff}.bg-success{color:#fff}.bg-info{color:#fff}.bg-warning{color:#fff}.bg-danger{color:#fff}.bg-light{color:#000}.bg-dark{color:#fff}@media(min-width: 1200px){.fs-1{font-size:2rem !important}.fs-2{font-size:1.65rem !important}.fs-3{font-size:1.45rem !important}}@media print{.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-grid{display:grid !important}.d-print-inline-grid{display:inline-grid !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:flex !important}.d-print-inline-flex{display:inline-flex !important}.d-print-none{display:none !important}}.bg-blue{--bslib-color-bg: #2780e3;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-blue{--bslib-color-fg: #2780e3;color:var(--bslib-color-fg)}.bg-indigo{--bslib-color-bg: #6610f2;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-indigo{--bslib-color-fg: #6610f2;color:var(--bslib-color-fg)}.bg-purple{--bslib-color-bg: #613d7c;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-purple{--bslib-color-fg: #613d7c;color:var(--bslib-color-fg)}.bg-pink{--bslib-color-bg: #e83e8c;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-pink{--bslib-color-fg: #e83e8c;color:var(--bslib-color-fg)}.bg-red{--bslib-color-bg: #ff0039;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-red{--bslib-color-fg: #ff0039;color:var(--bslib-color-fg)}.bg-orange{--bslib-color-bg: #f0ad4e;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-orange{--bslib-color-fg: #f0ad4e;color:var(--bslib-color-fg)}.bg-yellow{--bslib-color-bg: #ff7518;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-yellow{--bslib-color-fg: #ff7518;color:var(--bslib-color-fg)}.bg-green{--bslib-color-bg: #3fb618;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-green{--bslib-color-fg: #3fb618;color:var(--bslib-color-fg)}.bg-teal{--bslib-color-bg: #20c997;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-teal{--bslib-color-fg: #20c997;color:var(--bslib-color-fg)}.bg-cyan{--bslib-color-bg: #9954bb;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-cyan{--bslib-color-fg: #9954bb;color:var(--bslib-color-fg)}.text-default{--bslib-color-fg: #343a40}.bg-default{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.text-primary{--bslib-color-fg: #2780e3}.bg-primary{--bslib-color-bg: #2780e3;--bslib-color-fg: #fff}.text-secondary{--bslib-color-fg: #343a40}.bg-secondary{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.text-success{--bslib-color-fg: #3fb618}.bg-success{--bslib-color-bg: #3fb618;--bslib-color-fg: #fff}.text-info{--bslib-color-fg: #9954bb}.bg-info{--bslib-color-bg: #9954bb;--bslib-color-fg: #fff}.text-warning{--bslib-color-fg: #ff7518}.bg-warning{--bslib-color-bg: #ff7518;--bslib-color-fg: #fff}.text-danger{--bslib-color-fg: #ff0039}.bg-danger{--bslib-color-bg: #ff0039;--bslib-color-fg: #fff}.text-light{--bslib-color-fg: #f8f9fa}.bg-light{--bslib-color-bg: #f8f9fa;--bslib-color-fg: #000}.text-dark{--bslib-color-fg: #343a40}.bg-dark{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.bg-gradient-blue-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #4053e9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #4053e9;color:#fff}.bg-gradient-blue-purple{--bslib-color-fg: #fff;--bslib-color-bg: #3e65ba;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #3e65ba;color:#fff}.bg-gradient-blue-pink{--bslib-color-fg: #fff;--bslib-color-bg: #7466c0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #7466c0;color:#fff}.bg-gradient-blue-red{--bslib-color-fg: #fff;--bslib-color-bg: #7d4d9f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #7d4d9f;color:#fff}.bg-gradient-blue-orange{--bslib-color-fg: #fff;--bslib-color-bg: #7792a7;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #7792a7;color:#fff}.bg-gradient-blue-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #7d7c92;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #7d7c92;color:#fff}.bg-gradient-blue-green{--bslib-color-fg: #fff;--bslib-color-bg: #319692;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #319692;color:#fff}.bg-gradient-blue-teal{--bslib-color-fg: #fff;--bslib-color-bg: #249dc5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #249dc5;color:#fff}.bg-gradient-blue-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #556ed3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #556ed3;color:#fff}.bg-gradient-indigo-blue{--bslib-color-fg: #fff;--bslib-color-bg: #4d3dec;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #4d3dec;color:#fff}.bg-gradient-indigo-purple{--bslib-color-fg: #fff;--bslib-color-bg: #6422c3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #6422c3;color:#fff}.bg-gradient-indigo-pink{--bslib-color-fg: #fff;--bslib-color-bg: #9a22c9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #9a22c9;color:#fff}.bg-gradient-indigo-red{--bslib-color-fg: #fff;--bslib-color-bg: #a30aa8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #a30aa8;color:#fff}.bg-gradient-indigo-orange{--bslib-color-fg: #fff;--bslib-color-bg: #9d4fb0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #9d4fb0;color:#fff}.bg-gradient-indigo-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #a3389b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #a3389b;color:#fff}.bg-gradient-indigo-green{--bslib-color-fg: #fff;--bslib-color-bg: #56529b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #56529b;color:#fff}.bg-gradient-indigo-teal{--bslib-color-fg: #fff;--bslib-color-bg: #4a5ace;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4a5ace;color:#fff}.bg-gradient-indigo-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #7a2bdc;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #7a2bdc;color:#fff}.bg-gradient-purple-blue{--bslib-color-fg: #fff;--bslib-color-bg: #4a58a5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #4a58a5;color:#fff}.bg-gradient-purple-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #632bab;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #632bab;color:#fff}.bg-gradient-purple-pink{--bslib-color-fg: #fff;--bslib-color-bg: #973d82;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #973d82;color:#fff}.bg-gradient-purple-red{--bslib-color-fg: #fff;--bslib-color-bg: #a02561;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #a02561;color:#fff}.bg-gradient-purple-orange{--bslib-color-fg: #fff;--bslib-color-bg: #9a6a6a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #9a6a6a;color:#fff}.bg-gradient-purple-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #a05354;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #a05354;color:#fff}.bg-gradient-purple-green{--bslib-color-fg: #fff;--bslib-color-bg: #536d54;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #536d54;color:#fff}.bg-gradient-purple-teal{--bslib-color-fg: #fff;--bslib-color-bg: #477587;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #477587;color:#fff}.bg-gradient-purple-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #774695;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #774695;color:#fff}.bg-gradient-pink-blue{--bslib-color-fg: #fff;--bslib-color-bg: #9b58af;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #9b58af;color:#fff}.bg-gradient-pink-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #b42cb5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #b42cb5;color:#fff}.bg-gradient-pink-purple{--bslib-color-fg: #fff;--bslib-color-bg: #b23e86;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #b23e86;color:#fff}.bg-gradient-pink-red{--bslib-color-fg: #fff;--bslib-color-bg: #f1256b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #f1256b;color:#fff}.bg-gradient-pink-orange{--bslib-color-fg: #fff;--bslib-color-bg: #eb6a73;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #eb6a73;color:#fff}.bg-gradient-pink-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #f1545e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #f1545e;color:#fff}.bg-gradient-pink-green{--bslib-color-fg: #fff;--bslib-color-bg: #a46e5e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #a46e5e;color:#fff}.bg-gradient-pink-teal{--bslib-color-fg: #fff;--bslib-color-bg: #987690;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #987690;color:#fff}.bg-gradient-pink-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #c8479f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #c8479f;color:#fff}.bg-gradient-red-blue{--bslib-color-fg: #fff;--bslib-color-bg: #a9337d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #a9337d;color:#fff}.bg-gradient-red-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #c20683;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c20683;color:#fff}.bg-gradient-red-purple{--bslib-color-fg: #fff;--bslib-color-bg: #c01854;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #c01854;color:#fff}.bg-gradient-red-pink{--bslib-color-fg: #fff;--bslib-color-bg: #f6195a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #f6195a;color:#fff}.bg-gradient-red-orange{--bslib-color-fg: #fff;--bslib-color-bg: #f94541;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #f94541;color:#fff}.bg-gradient-red-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #ff2f2c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #ff2f2c;color:#fff}.bg-gradient-red-green{--bslib-color-fg: #fff;--bslib-color-bg: #b2492c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #b2492c;color:#fff}.bg-gradient-red-teal{--bslib-color-fg: #fff;--bslib-color-bg: #a6505f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a6505f;color:#fff}.bg-gradient-red-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #d6226d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #d6226d;color:#fff}.bg-gradient-orange-blue{--bslib-color-fg: #fff;--bslib-color-bg: #a09b8a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #a09b8a;color:#fff}.bg-gradient-orange-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #b96e90;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #b96e90;color:#fff}.bg-gradient-orange-purple{--bslib-color-fg: #fff;--bslib-color-bg: #b78060;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #b78060;color:#fff}.bg-gradient-orange-pink{--bslib-color-fg: #fff;--bslib-color-bg: #ed8167;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #ed8167;color:#fff}.bg-gradient-orange-red{--bslib-color-fg: #fff;--bslib-color-bg: #f66846;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #f66846;color:#fff}.bg-gradient-orange-yellow{--bslib-color-fg: #000;--bslib-color-bg: #f69738;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #f69738;color:#000}.bg-gradient-orange-green{--bslib-color-fg: #000;--bslib-color-bg: #a9b138;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #a9b138;color:#000}.bg-gradient-orange-teal{--bslib-color-fg: #000;--bslib-color-bg: #9db86b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #9db86b;color:#000}.bg-gradient-orange-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #cd897a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #cd897a;color:#fff}.bg-gradient-yellow-blue{--bslib-color-fg: #fff;--bslib-color-bg: #a97969;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #a97969;color:#fff}.bg-gradient-yellow-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #c24d6f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c24d6f;color:#fff}.bg-gradient-yellow-purple{--bslib-color-fg: #fff;--bslib-color-bg: #c05f40;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #c05f40;color:#fff}.bg-gradient-yellow-pink{--bslib-color-fg: #fff;--bslib-color-bg: #f65f46;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #f65f46;color:#fff}.bg-gradient-yellow-red{--bslib-color-fg: #fff;--bslib-color-bg: #ff4625;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #ff4625;color:#fff}.bg-gradient-yellow-orange{--bslib-color-fg: #000;--bslib-color-bg: #f98b2e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #f98b2e;color:#000}.bg-gradient-yellow-green{--bslib-color-fg: #fff;--bslib-color-bg: #b28f18;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #b28f18;color:#fff}.bg-gradient-yellow-teal{--bslib-color-fg: #fff;--bslib-color-bg: #a6974b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a6974b;color:#fff}.bg-gradient-yellow-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #d66859;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #d66859;color:#fff}.bg-gradient-green-blue{--bslib-color-fg: #fff;--bslib-color-bg: #35a069;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #35a069;color:#fff}.bg-gradient-green-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #4f746f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #4f746f;color:#fff}.bg-gradient-green-purple{--bslib-color-fg: #fff;--bslib-color-bg: #4d8640;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #4d8640;color:#fff}.bg-gradient-green-pink{--bslib-color-fg: #fff;--bslib-color-bg: #838646;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #838646;color:#fff}.bg-gradient-green-red{--bslib-color-fg: #fff;--bslib-color-bg: #8c6d25;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #8c6d25;color:#fff}.bg-gradient-green-orange{--bslib-color-fg: #000;--bslib-color-bg: #86b22e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #86b22e;color:#000}.bg-gradient-green-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #8c9c18;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #8c9c18;color:#fff}.bg-gradient-green-teal{--bslib-color-fg: #000;--bslib-color-bg: #33be4b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #33be4b;color:#000}.bg-gradient-green-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #638f59;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #638f59;color:#fff}.bg-gradient-teal-blue{--bslib-color-fg: #fff;--bslib-color-bg: #23acb5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #23acb5;color:#fff}.bg-gradient-teal-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #3c7fbb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3c7fbb;color:#fff}.bg-gradient-teal-purple{--bslib-color-fg: #fff;--bslib-color-bg: #3a918c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #3a918c;color:#fff}.bg-gradient-teal-pink{--bslib-color-fg: #fff;--bslib-color-bg: #709193;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #709193;color:#fff}.bg-gradient-teal-red{--bslib-color-fg: #fff;--bslib-color-bg: #797971;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #797971;color:#fff}.bg-gradient-teal-orange{--bslib-color-fg: #000;--bslib-color-bg: #73be7a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #73be7a;color:#000}.bg-gradient-teal-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #79a764;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #79a764;color:#fff}.bg-gradient-teal-green{--bslib-color-fg: #000;--bslib-color-bg: #2cc164;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #2cc164;color:#000}.bg-gradient-teal-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #509aa5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #509aa5;color:#fff}.bg-gradient-cyan-blue{--bslib-color-fg: #fff;--bslib-color-bg: #6b66cb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #6b66cb;color:#fff}.bg-gradient-cyan-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #8539d1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #8539d1;color:#fff}.bg-gradient-cyan-purple{--bslib-color-fg: #fff;--bslib-color-bg: #834ba2;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #834ba2;color:#fff}.bg-gradient-cyan-pink{--bslib-color-fg: #fff;--bslib-color-bg: #b94ba8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #b94ba8;color:#fff}.bg-gradient-cyan-red{--bslib-color-fg: #fff;--bslib-color-bg: #c23287;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #c23287;color:#fff}.bg-gradient-cyan-orange{--bslib-color-fg: #fff;--bslib-color-bg: #bc788f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #bc788f;color:#fff}.bg-gradient-cyan-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #c2617a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #c2617a;color:#fff}.bg-gradient-cyan-green{--bslib-color-fg: #fff;--bslib-color-bg: #757b7a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #757b7a;color:#fff}.bg-gradient-cyan-teal{--bslib-color-fg: #fff;--bslib-color-bg: #6983ad;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #6983ad;color:#fff}:root{--bslib-spacer: 1rem;--bslib-mb-spacer: var(--bslib-spacer, 1rem)}.bslib-mb-spacing{margin-bottom:var(--bslib-mb-spacer)}.bslib-gap-spacing{gap:var(--bslib-mb-spacer)}.bslib-gap-spacing>.bslib-mb-spacing,.bslib-gap-spacing>.form-group,.bslib-gap-spacing>p,.bslib-gap-spacing>pre{margin-bottom:0}.html-fill-container>.html-fill-item.bslib-mb-spacing{margin-bottom:0}:root{--bslib-spacer: 1rem;--bslib-mb-spacer: var(--bslib-spacer, 1rem)}.bslib-mb-spacing{margin-bottom:var(--bslib-mb-spacer)}.bslib-gap-spacing{gap:var(--bslib-mb-spacer)}.bslib-gap-spacing>.bslib-mb-spacing,.bslib-gap-spacing>.form-group,.bslib-gap-spacing>p,.bslib-gap-spacing>pre{margin-bottom:0}.html-fill-container>.html-fill-item.bslib-mb-spacing{margin-bottom:0}.tab-content>.tab-pane.html-fill-container{display:none}.tab-content>.active.html-fill-container{display:flex}.tab-content.html-fill-container{padding:0}.bg-blue{--bslib-color-bg: #2780e3;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-blue{--bslib-color-fg: #2780e3;color:var(--bslib-color-fg)}.bg-indigo{--bslib-color-bg: #6610f2;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-indigo{--bslib-color-fg: #6610f2;color:var(--bslib-color-fg)}.bg-purple{--bslib-color-bg: #613d7c;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-purple{--bslib-color-fg: #613d7c;color:var(--bslib-color-fg)}.bg-pink{--bslib-color-bg: #e83e8c;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-pink{--bslib-color-fg: #e83e8c;color:var(--bslib-color-fg)}.bg-red{--bslib-color-bg: #ff0039;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-red{--bslib-color-fg: #ff0039;color:var(--bslib-color-fg)}.bg-orange{--bslib-color-bg: #f0ad4e;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-orange{--bslib-color-fg: #f0ad4e;color:var(--bslib-color-fg)}.bg-yellow{--bslib-color-bg: #ff7518;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-yellow{--bslib-color-fg: #ff7518;color:var(--bslib-color-fg)}.bg-green{--bslib-color-bg: #3fb618;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-green{--bslib-color-fg: #3fb618;color:var(--bslib-color-fg)}.bg-teal{--bslib-color-bg: #20c997;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-teal{--bslib-color-fg: #20c997;color:var(--bslib-color-fg)}.bg-cyan{--bslib-color-bg: #9954bb;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-cyan{--bslib-color-fg: #9954bb;color:var(--bslib-color-fg)}.text-default{--bslib-color-fg: #343a40}.bg-default{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.text-primary{--bslib-color-fg: #2780e3}.bg-primary{--bslib-color-bg: #2780e3;--bslib-color-fg: #fff}.text-secondary{--bslib-color-fg: #343a40}.bg-secondary{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.text-success{--bslib-color-fg: #3fb618}.bg-success{--bslib-color-bg: #3fb618;--bslib-color-fg: #fff}.text-info{--bslib-color-fg: #9954bb}.bg-info{--bslib-color-bg: #9954bb;--bslib-color-fg: #fff}.text-warning{--bslib-color-fg: #ff7518}.bg-warning{--bslib-color-bg: #ff7518;--bslib-color-fg: #fff}.text-danger{--bslib-color-fg: #ff0039}.bg-danger{--bslib-color-bg: #ff0039;--bslib-color-fg: #fff}.text-light{--bslib-color-fg: #f8f9fa}.bg-light{--bslib-color-bg: #f8f9fa;--bslib-color-fg: #000}.text-dark{--bslib-color-fg: #343a40}.bg-dark{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.bg-gradient-blue-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #4053e9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #4053e9;color:#fff}.bg-gradient-blue-purple{--bslib-color-fg: #fff;--bslib-color-bg: #3e65ba;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #3e65ba;color:#fff}.bg-gradient-blue-pink{--bslib-color-fg: #fff;--bslib-color-bg: #7466c0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #7466c0;color:#fff}.bg-gradient-blue-red{--bslib-color-fg: #fff;--bslib-color-bg: #7d4d9f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #7d4d9f;color:#fff}.bg-gradient-blue-orange{--bslib-color-fg: #fff;--bslib-color-bg: #7792a7;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #7792a7;color:#fff}.bg-gradient-blue-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #7d7c92;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #7d7c92;color:#fff}.bg-gradient-blue-green{--bslib-color-fg: #fff;--bslib-color-bg: #319692;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #319692;color:#fff}.bg-gradient-blue-teal{--bslib-color-fg: #fff;--bslib-color-bg: #249dc5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #249dc5;color:#fff}.bg-gradient-blue-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #556ed3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #556ed3;color:#fff}.bg-gradient-indigo-blue{--bslib-color-fg: #fff;--bslib-color-bg: #4d3dec;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #4d3dec;color:#fff}.bg-gradient-indigo-purple{--bslib-color-fg: #fff;--bslib-color-bg: #6422c3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #6422c3;color:#fff}.bg-gradient-indigo-pink{--bslib-color-fg: #fff;--bslib-color-bg: #9a22c9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #9a22c9;color:#fff}.bg-gradient-indigo-red{--bslib-color-fg: #fff;--bslib-color-bg: #a30aa8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #a30aa8;color:#fff}.bg-gradient-indigo-orange{--bslib-color-fg: #fff;--bslib-color-bg: #9d4fb0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #9d4fb0;color:#fff}.bg-gradient-indigo-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #a3389b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #a3389b;color:#fff}.bg-gradient-indigo-green{--bslib-color-fg: #fff;--bslib-color-bg: #56529b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #56529b;color:#fff}.bg-gradient-indigo-teal{--bslib-color-fg: #fff;--bslib-color-bg: #4a5ace;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4a5ace;color:#fff}.bg-gradient-indigo-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #7a2bdc;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #7a2bdc;color:#fff}.bg-gradient-purple-blue{--bslib-color-fg: #fff;--bslib-color-bg: #4a58a5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #4a58a5;color:#fff}.bg-gradient-purple-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #632bab;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #632bab;color:#fff}.bg-gradient-purple-pink{--bslib-color-fg: #fff;--bslib-color-bg: #973d82;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #973d82;color:#fff}.bg-gradient-purple-red{--bslib-color-fg: #fff;--bslib-color-bg: #a02561;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #a02561;color:#fff}.bg-gradient-purple-orange{--bslib-color-fg: #fff;--bslib-color-bg: #9a6a6a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #9a6a6a;color:#fff}.bg-gradient-purple-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #a05354;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #a05354;color:#fff}.bg-gradient-purple-green{--bslib-color-fg: #fff;--bslib-color-bg: #536d54;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #536d54;color:#fff}.bg-gradient-purple-teal{--bslib-color-fg: #fff;--bslib-color-bg: #477587;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #477587;color:#fff}.bg-gradient-purple-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #774695;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #774695;color:#fff}.bg-gradient-pink-blue{--bslib-color-fg: #fff;--bslib-color-bg: #9b58af;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #9b58af;color:#fff}.bg-gradient-pink-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #b42cb5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #b42cb5;color:#fff}.bg-gradient-pink-purple{--bslib-color-fg: #fff;--bslib-color-bg: #b23e86;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #b23e86;color:#fff}.bg-gradient-pink-red{--bslib-color-fg: #fff;--bslib-color-bg: #f1256b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #f1256b;color:#fff}.bg-gradient-pink-orange{--bslib-color-fg: #fff;--bslib-color-bg: #eb6a73;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #eb6a73;color:#fff}.bg-gradient-pink-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #f1545e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #f1545e;color:#fff}.bg-gradient-pink-green{--bslib-color-fg: #fff;--bslib-color-bg: #a46e5e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #a46e5e;color:#fff}.bg-gradient-pink-teal{--bslib-color-fg: #fff;--bslib-color-bg: #987690;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #987690;color:#fff}.bg-gradient-pink-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #c8479f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #c8479f;color:#fff}.bg-gradient-red-blue{--bslib-color-fg: #fff;--bslib-color-bg: #a9337d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #a9337d;color:#fff}.bg-gradient-red-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #c20683;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c20683;color:#fff}.bg-gradient-red-purple{--bslib-color-fg: #fff;--bslib-color-bg: #c01854;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #c01854;color:#fff}.bg-gradient-red-pink{--bslib-color-fg: #fff;--bslib-color-bg: #f6195a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #f6195a;color:#fff}.bg-gradient-red-orange{--bslib-color-fg: #fff;--bslib-color-bg: #f94541;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #f94541;color:#fff}.bg-gradient-red-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #ff2f2c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #ff2f2c;color:#fff}.bg-gradient-red-green{--bslib-color-fg: #fff;--bslib-color-bg: #b2492c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #b2492c;color:#fff}.bg-gradient-red-teal{--bslib-color-fg: #fff;--bslib-color-bg: #a6505f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a6505f;color:#fff}.bg-gradient-red-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #d6226d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #d6226d;color:#fff}.bg-gradient-orange-blue{--bslib-color-fg: #fff;--bslib-color-bg: #a09b8a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #a09b8a;color:#fff}.bg-gradient-orange-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #b96e90;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #b96e90;color:#fff}.bg-gradient-orange-purple{--bslib-color-fg: #fff;--bslib-color-bg: #b78060;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #b78060;color:#fff}.bg-gradient-orange-pink{--bslib-color-fg: #fff;--bslib-color-bg: #ed8167;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #ed8167;color:#fff}.bg-gradient-orange-red{--bslib-color-fg: #fff;--bslib-color-bg: #f66846;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #f66846;color:#fff}.bg-gradient-orange-yellow{--bslib-color-fg: #000;--bslib-color-bg: #f69738;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #f69738;color:#000}.bg-gradient-orange-green{--bslib-color-fg: #000;--bslib-color-bg: #a9b138;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #a9b138;color:#000}.bg-gradient-orange-teal{--bslib-color-fg: #000;--bslib-color-bg: #9db86b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #9db86b;color:#000}.bg-gradient-orange-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #cd897a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #cd897a;color:#fff}.bg-gradient-yellow-blue{--bslib-color-fg: #fff;--bslib-color-bg: #a97969;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #a97969;color:#fff}.bg-gradient-yellow-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #c24d6f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c24d6f;color:#fff}.bg-gradient-yellow-purple{--bslib-color-fg: #fff;--bslib-color-bg: #c05f40;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #c05f40;color:#fff}.bg-gradient-yellow-pink{--bslib-color-fg: #fff;--bslib-color-bg: #f65f46;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #f65f46;color:#fff}.bg-gradient-yellow-red{--bslib-color-fg: #fff;--bslib-color-bg: #ff4625;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #ff4625;color:#fff}.bg-gradient-yellow-orange{--bslib-color-fg: #000;--bslib-color-bg: #f98b2e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #f98b2e;color:#000}.bg-gradient-yellow-green{--bslib-color-fg: #fff;--bslib-color-bg: #b28f18;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #b28f18;color:#fff}.bg-gradient-yellow-teal{--bslib-color-fg: #fff;--bslib-color-bg: #a6974b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a6974b;color:#fff}.bg-gradient-yellow-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #d66859;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #d66859;color:#fff}.bg-gradient-green-blue{--bslib-color-fg: #fff;--bslib-color-bg: #35a069;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #35a069;color:#fff}.bg-gradient-green-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #4f746f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #4f746f;color:#fff}.bg-gradient-green-purple{--bslib-color-fg: #fff;--bslib-color-bg: #4d8640;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #4d8640;color:#fff}.bg-gradient-green-pink{--bslib-color-fg: #fff;--bslib-color-bg: #838646;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #838646;color:#fff}.bg-gradient-green-red{--bslib-color-fg: #fff;--bslib-color-bg: #8c6d25;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #8c6d25;color:#fff}.bg-gradient-green-orange{--bslib-color-fg: #000;--bslib-color-bg: #86b22e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #86b22e;color:#000}.bg-gradient-green-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #8c9c18;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #8c9c18;color:#fff}.bg-gradient-green-teal{--bslib-color-fg: #000;--bslib-color-bg: #33be4b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #33be4b;color:#000}.bg-gradient-green-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #638f59;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #638f59;color:#fff}.bg-gradient-teal-blue{--bslib-color-fg: #fff;--bslib-color-bg: #23acb5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #23acb5;color:#fff}.bg-gradient-teal-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #3c7fbb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3c7fbb;color:#fff}.bg-gradient-teal-purple{--bslib-color-fg: #fff;--bslib-color-bg: #3a918c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #3a918c;color:#fff}.bg-gradient-teal-pink{--bslib-color-fg: #fff;--bslib-color-bg: #709193;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #709193;color:#fff}.bg-gradient-teal-red{--bslib-color-fg: #fff;--bslib-color-bg: #797971;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #797971;color:#fff}.bg-gradient-teal-orange{--bslib-color-fg: #000;--bslib-color-bg: #73be7a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #73be7a;color:#000}.bg-gradient-teal-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #79a764;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #79a764;color:#fff}.bg-gradient-teal-green{--bslib-color-fg: #000;--bslib-color-bg: #2cc164;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #2cc164;color:#000}.bg-gradient-teal-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #509aa5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #509aa5;color:#fff}.bg-gradient-cyan-blue{--bslib-color-fg: #fff;--bslib-color-bg: #6b66cb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #6b66cb;color:#fff}.bg-gradient-cyan-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #8539d1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #8539d1;color:#fff}.bg-gradient-cyan-purple{--bslib-color-fg: #fff;--bslib-color-bg: #834ba2;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #834ba2;color:#fff}.bg-gradient-cyan-pink{--bslib-color-fg: #fff;--bslib-color-bg: #b94ba8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #b94ba8;color:#fff}.bg-gradient-cyan-red{--bslib-color-fg: #fff;--bslib-color-bg: #c23287;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #c23287;color:#fff}.bg-gradient-cyan-orange{--bslib-color-fg: #fff;--bslib-color-bg: #bc788f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #bc788f;color:#fff}.bg-gradient-cyan-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #c2617a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #c2617a;color:#fff}.bg-gradient-cyan-green{--bslib-color-fg: #fff;--bslib-color-bg: #757b7a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #757b7a;color:#fff}.bg-gradient-cyan-teal{--bslib-color-fg: #fff;--bslib-color-bg: #6983ad;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #6983ad;color:#fff}.tab-content>.tab-pane.html-fill-container{display:none}.tab-content>.active.html-fill-container{display:flex}.tab-content.html-fill-container{padding:0}.accordion .accordion-header{font-size:calc(1.29rem + 0.48vw);margin-top:0;margin-bottom:.5rem;font-weight:400;line-height:1.2;color:var(--bs-heading-color);margin-bottom:0}@media(min-width: 1200px){.accordion .accordion-header{font-size:1.65rem}}.accordion .accordion-icon:not(:empty){margin-right:.75rem;display:flex}.accordion .accordion-button:not(.collapsed){box-shadow:none}.accordion .accordion-button:not(.collapsed):focus{box-shadow:var(--bs-accordion-btn-focus-box-shadow)}:root{--bslib-value-box-shadow: none;--bslib-value-box-border-width-auto-yes: var(--bslib-value-box-border-width-baseline);--bslib-value-box-border-width-auto-no: 0;--bslib-value-box-border-width-baseline: 1px}.bslib-value-box{border-width:var(--bslib-value-box-border-width-auto-no, var(--bslib-value-box-border-width-baseline));container-name:bslib-value-box;container-type:inline-size}.bslib-value-box.card{box-shadow:var(--bslib-value-box-shadow)}.bslib-value-box.border-auto{border-width:var(--bslib-value-box-border-width-auto-yes, var(--bslib-value-box-border-width-baseline))}.bslib-value-box.default{--bslib-value-box-bg-default: var(--bs-card-bg, #fff);--bslib-value-box-border-color-default: var(--bs-card-border-color, rgba(0, 0, 0, 0.175));color:var(--bslib-value-box-color);background-color:var(--bslib-value-box-bg, var(--bslib-value-box-bg-default));border-color:var(--bslib-value-box-border-color, var(--bslib-value-box-border-color-default))}.bslib-value-box .value-box-grid{display:grid;grid-template-areas:"left right";align-items:center;overflow:hidden}.bslib-value-box .value-box-showcase{height:100%;max-height:var(---bslib-value-box-showcase-max-h, 100%)}.bslib-value-box .value-box-showcase,.bslib-value-box .value-box-showcase>.html-fill-item{width:100%}.bslib-value-box[data-full-screen=true] .value-box-showcase{max-height:var(---bslib-value-box-showcase-max-h-fs, 100%)}@media screen and (min-width: 575.98px){@container bslib-value-box (max-width: 300px){.bslib-value-box:not(.showcase-bottom) .value-box-grid{grid-template-columns:1fr !important;grid-template-rows:auto auto;grid-template-areas:"top" "bottom"}.bslib-value-box:not(.showcase-bottom) .value-box-grid .value-box-showcase{grid-area:top !important}.bslib-value-box:not(.showcase-bottom) .value-box-grid .value-box-area{grid-area:bottom !important;justify-content:end}}}.bslib-value-box .value-box-area{justify-content:center;padding:1.5rem 1rem;font-size:.9rem;font-weight:500}.bslib-value-box .value-box-area *{margin-bottom:0;margin-top:0}.bslib-value-box .value-box-title{font-size:1rem;margin-top:0;margin-bottom:.5rem;font-weight:400;line-height:1.2}.bslib-value-box .value-box-title:empty::after{content:" "}.bslib-value-box .value-box-value{font-size:calc(1.29rem + 0.48vw);margin-top:0;margin-bottom:.5rem;font-weight:400;line-height:1.2}@media(min-width: 1200px){.bslib-value-box .value-box-value{font-size:1.65rem}}.bslib-value-box .value-box-value:empty::after{content:" "}.bslib-value-box .value-box-showcase{align-items:center;justify-content:center;margin-top:auto;margin-bottom:auto;padding:1rem}.bslib-value-box .value-box-showcase .bi,.bslib-value-box .value-box-showcase .fa,.bslib-value-box .value-box-showcase .fab,.bslib-value-box .value-box-showcase .fas,.bslib-value-box .value-box-showcase .far{opacity:.85;min-width:50px;max-width:125%}.bslib-value-box .value-box-showcase .bi,.bslib-value-box .value-box-showcase .fa,.bslib-value-box .value-box-showcase .fab,.bslib-value-box .value-box-showcase .fas,.bslib-value-box .value-box-showcase .far{font-size:4rem}.bslib-value-box.showcase-top-right .value-box-grid{grid-template-columns:1fr var(---bslib-value-box-showcase-w, 50%)}.bslib-value-box.showcase-top-right .value-box-grid .value-box-showcase{grid-area:right;margin-left:auto;align-self:start;align-items:end;padding-left:0;padding-bottom:0}.bslib-value-box.showcase-top-right .value-box-grid .value-box-area{grid-area:left;align-self:end}.bslib-value-box.showcase-top-right[data-full-screen=true] .value-box-grid{grid-template-columns:auto var(---bslib-value-box-showcase-w-fs, 1fr)}.bslib-value-box.showcase-top-right[data-full-screen=true] .value-box-grid>div{align-self:center}.bslib-value-box.showcase-top-right:not([data-full-screen=true]) .value-box-showcase{margin-top:0}@container bslib-value-box (max-width: 300px){.bslib-value-box.showcase-top-right:not([data-full-screen=true]) .value-box-grid .value-box-showcase{padding-left:1rem}}.bslib-value-box.showcase-left-center .value-box-grid{grid-template-columns:var(---bslib-value-box-showcase-w, 30%) auto}.bslib-value-box.showcase-left-center[data-full-screen=true] .value-box-grid{grid-template-columns:var(---bslib-value-box-showcase-w-fs, 1fr) auto}.bslib-value-box.showcase-left-center:not([data-fill-screen=true]) .value-box-grid .value-box-showcase{grid-area:left}.bslib-value-box.showcase-left-center:not([data-fill-screen=true]) .value-box-grid .value-box-area{grid-area:right}.bslib-value-box.showcase-bottom .value-box-grid{grid-template-columns:1fr;grid-template-rows:1fr var(---bslib-value-box-showcase-h, auto);grid-template-areas:"top" "bottom";overflow:hidden}.bslib-value-box.showcase-bottom .value-box-grid .value-box-showcase{grid-area:bottom;padding:0;margin:0}.bslib-value-box.showcase-bottom .value-box-grid .value-box-area{grid-area:top}.bslib-value-box.showcase-bottom[data-full-screen=true] .value-box-grid{grid-template-rows:1fr var(---bslib-value-box-showcase-h-fs, 2fr)}.bslib-value-box.showcase-bottom[data-full-screen=true] .value-box-grid .value-box-showcase{padding:1rem}[data-bs-theme=dark] .bslib-value-box{--bslib-value-box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 50%)}.bslib-card{overflow:auto}.bslib-card .card-body+.card-body{padding-top:0}.bslib-card .card-body{overflow:auto}.bslib-card .card-body p{margin-top:0}.bslib-card .card-body p:last-child{margin-bottom:0}.bslib-card .card-body{max-height:var(--bslib-card-body-max-height, none)}.bslib-card[data-full-screen=true]>.card-body{max-height:var(--bslib-card-body-max-height-full-screen, none)}.bslib-card .card-header .form-group{margin-bottom:0}.bslib-card .card-header .selectize-control{margin-bottom:0}.bslib-card .card-header .selectize-control .item{margin-right:1.15rem}.bslib-card .card-footer{margin-top:auto}.bslib-card .bslib-navs-card-title{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center}.bslib-card .bslib-navs-card-title .nav{margin-left:auto}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border=true]){border:none}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border-radius=true]){border-top-left-radius:0;border-top-right-radius:0}[data-full-screen=true]{position:fixed;inset:3.5rem 1rem 1rem;height:auto !important;max-height:none !important;width:auto !important;z-index:1070}.bslib-full-screen-enter{display:none;position:absolute;bottom:var(--bslib-full-screen-enter-bottom, 0.2rem);right:var(--bslib-full-screen-enter-right, 0);top:var(--bslib-full-screen-enter-top);left:var(--bslib-full-screen-enter-left);color:var(--bslib-color-fg, var(--bs-card-color));background-color:var(--bslib-color-bg, var(--bs-card-bg, var(--bs-body-bg)));border:var(--bs-card-border-width) solid var(--bslib-color-fg, var(--bs-card-border-color));box-shadow:0 2px 4px rgba(0,0,0,.15);margin:.2rem .4rem;padding:.55rem !important;font-size:.8rem;cursor:pointer;opacity:.7;z-index:1070}.bslib-full-screen-enter:hover{opacity:1}.card[data-full-screen=false]:hover>*>.bslib-full-screen-enter{display:block}.bslib-has-full-screen .card:hover>*>.bslib-full-screen-enter{display:none}@media(max-width: 575.98px){.bslib-full-screen-enter{display:none !important}}.bslib-full-screen-exit{position:relative;top:1.35rem;font-size:.9rem;cursor:pointer;text-decoration:none;display:flex;float:right;margin-right:2.15rem;align-items:center;color:rgba(var(--bs-body-bg-rgb), 0.8)}.bslib-full-screen-exit:hover{color:rgba(var(--bs-body-bg-rgb), 1)}.bslib-full-screen-exit svg{margin-left:.5rem;font-size:1.5rem}#bslib-full-screen-overlay{position:fixed;inset:0;background-color:rgba(var(--bs-body-color-rgb), 0.6);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);z-index:1069;animation:bslib-full-screen-overlay-enter 400ms cubic-bezier(0.6, 0.02, 0.65, 1) forwards}@keyframes bslib-full-screen-overlay-enter{0%{opacity:0}100%{opacity:1}}:root{--bslib-page-sidebar-title-bg: #2780e3;--bslib-page-sidebar-title-color: #fff}.bslib-page-title{background-color:var(--bslib-page-sidebar-title-bg);color:var(--bslib-page-sidebar-title-color);font-size:1.25rem;font-weight:300;padding:var(--bslib-spacer, 1rem);padding-left:1.5rem;margin-bottom:0;border-bottom:1px solid #dee2e6}.navbar+.container-fluid:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-sm:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-md:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-lg:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-xl:has(>.tab-content>.tab-pane.active.html-fill-container),.navbar+.container-xxl:has(>.tab-content>.tab-pane.active.html-fill-container){padding-left:0;padding-right:0}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container,.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container{padding:var(--bslib-spacer, 1rem);gap:var(--bslib-spacer, 1rem)}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container:has(>.bslib-sidebar-layout:only-child){padding:0}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border=true]){border-left:none;border-right:none;border-bottom:none}.navbar+.container-fluid>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-sm>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-md>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-lg>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-xl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]),.navbar+.container-xxl>.tab-content>.tab-pane.active.html-fill-container>.bslib-sidebar-layout:only-child:not([data-bslib-sidebar-border-radius=true]){border-radius:0}.navbar+div>.bslib-sidebar-layout{border-top:var(--bslib-sidebar-border)}.bslib-grid{display:grid !important;gap:var(--bslib-spacer, 1rem);height:var(--bslib-grid-height)}.bslib-grid.grid{grid-template-columns:repeat(var(--bs-columns, 12), minmax(0, 1fr));grid-template-rows:unset;grid-auto-rows:var(--bslib-grid--row-heights);--bslib-grid--row-heights--xs: unset;--bslib-grid--row-heights--sm: unset;--bslib-grid--row-heights--md: unset;--bslib-grid--row-heights--lg: unset;--bslib-grid--row-heights--xl: unset;--bslib-grid--row-heights--xxl: unset}.bslib-grid.grid.bslib-grid--row-heights--xs{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xs)}@media(min-width: 576px){.bslib-grid.grid.bslib-grid--row-heights--sm{--bslib-grid--row-heights: var(--bslib-grid--row-heights--sm)}}@media(min-width: 768px){.bslib-grid.grid.bslib-grid--row-heights--md{--bslib-grid--row-heights: var(--bslib-grid--row-heights--md)}}@media(min-width: 992px){.bslib-grid.grid.bslib-grid--row-heights--lg{--bslib-grid--row-heights: var(--bslib-grid--row-heights--lg)}}@media(min-width: 1200px){.bslib-grid.grid.bslib-grid--row-heights--xl{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xl)}}@media(min-width: 1400px){.bslib-grid.grid.bslib-grid--row-heights--xxl{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xxl)}}.bslib-grid>*>.shiny-input-container{width:100%}.bslib-grid-item{grid-column:auto/span 1}@media(max-width: 767.98px){.bslib-grid-item{grid-column:1/-1}}@media(max-width: 575.98px){.bslib-grid{grid-template-columns:1fr !important;height:var(--bslib-grid-height-mobile)}.bslib-grid.grid{height:unset !important;grid-auto-rows:var(--bslib-grid--row-heights--xs, auto)}}.bslib-sidebar-layout{--bslib-sidebar-transition-duration: 500ms;--bslib-sidebar-transition-easing-x: cubic-bezier(0.8, 0.78, 0.22, 1.07);--bslib-sidebar-border: var(--bs-card-border-width, 1px) solid var(--bs-card-border-color, rgba(0, 0, 0, 0.175));--bslib-sidebar-border-radius: var(--bs-border-radius);--bslib-sidebar-vert-border: var(--bs-card-border-width, 1px) solid var(--bs-card-border-color, rgba(0, 0, 0, 0.175));--bslib-sidebar-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05);--bslib-sidebar-fg: var(--bs-emphasis-color, black);--bslib-sidebar-main-fg: var(--bs-card-color, var(--bs-body-color));--bslib-sidebar-main-bg: var(--bs-card-bg, var(--bs-body-bg));--bslib-sidebar-toggle-bg: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.1);--bslib-sidebar-padding: calc(var(--bslib-spacer) * 1.5);--bslib-sidebar-icon-size: var(--bslib-spacer, 1rem);--bslib-sidebar-icon-button-size: calc(var(--bslib-sidebar-icon-size, 1rem) * 2);--bslib-sidebar-padding-icon: calc(var(--bslib-sidebar-icon-button-size, 2rem) * 1.5);--bslib-collapse-toggle-border-radius: var(--bs-border-radius, 0.25rem);--bslib-collapse-toggle-transform: 0deg;--bslib-sidebar-toggle-transition-easing: cubic-bezier(1, 0, 0, 1);--bslib-collapse-toggle-right-transform: 180deg;--bslib-sidebar-column-main: minmax(0, 1fr);display:grid !important;grid-template-columns:min(100% - var(--bslib-sidebar-icon-size),var(--bslib-sidebar-width, 250px)) var(--bslib-sidebar-column-main);position:relative;transition:grid-template-columns ease-in-out var(--bslib-sidebar-transition-duration);border:var(--bslib-sidebar-border);border-radius:var(--bslib-sidebar-border-radius)}@media(prefers-reduced-motion: reduce){.bslib-sidebar-layout{transition:none}}.bslib-sidebar-layout[data-bslib-sidebar-border=false]{border:none}.bslib-sidebar-layout[data-bslib-sidebar-border-radius=false]{border-radius:initial}.bslib-sidebar-layout>.main,.bslib-sidebar-layout>.sidebar{grid-row:1/2;border-radius:inherit;overflow:auto}.bslib-sidebar-layout>.main{grid-column:2/3;border-top-left-radius:0;border-bottom-left-radius:0;padding:var(--bslib-sidebar-padding);transition:padding var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration);color:var(--bslib-sidebar-main-fg);background-color:var(--bslib-sidebar-main-bg)}.bslib-sidebar-layout>.sidebar{grid-column:1/2;width:100%;height:100%;border-right:var(--bslib-sidebar-vert-border);border-top-right-radius:0;border-bottom-right-radius:0;color:var(--bslib-sidebar-fg);background-color:var(--bslib-sidebar-bg);backdrop-filter:blur(5px)}.bslib-sidebar-layout>.sidebar>.sidebar-content{display:flex;flex-direction:column;gap:var(--bslib-spacer, 1rem);padding:var(--bslib-sidebar-padding);padding-top:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout>.sidebar>.sidebar-content>:last-child:not(.sidebar-title){margin-bottom:0}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion{margin-left:calc(-1*var(--bslib-sidebar-padding));margin-right:calc(-1*var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:last-child{margin-bottom:calc(-1*var(--bslib-sidebar-padding))}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child){margin-bottom:1rem}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion .accordion-body{display:flex;flex-direction:column}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:first-child) .accordion-item:first-child{border-top:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content>.accordion:not(:last-child) .accordion-item:last-child{border-bottom:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.bslib-sidebar-layout>.sidebar>.sidebar-content.has-accordion>.sidebar-title{border-bottom:none;padding-bottom:0}.bslib-sidebar-layout>.sidebar .shiny-input-container{width:100%}.bslib-sidebar-layout[data-bslib-sidebar-open=always]>.sidebar>.sidebar-content{padding-top:var(--bslib-sidebar-padding)}.bslib-sidebar-layout>.collapse-toggle{grid-row:1/2;grid-column:1/2;display:inline-flex;align-items:center;position:absolute;right:calc(var(--bslib-sidebar-icon-size));top:calc(var(--bslib-sidebar-icon-size, 1rem)/2);border:none;border-radius:var(--bslib-collapse-toggle-border-radius);height:var(--bslib-sidebar-icon-button-size, 2rem);width:var(--bslib-sidebar-icon-button-size, 2rem);display:flex;align-items:center;justify-content:center;padding:0;color:var(--bslib-sidebar-fg);background-color:unset;transition:color var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),top var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),right var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration),left var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover{background-color:var(--bslib-sidebar-toggle-bg)}.bslib-sidebar-layout>.collapse-toggle>.collapse-icon{opacity:.8;width:var(--bslib-sidebar-icon-size);height:var(--bslib-sidebar-icon-size);transform:rotateY(var(--bslib-collapse-toggle-transform));transition:transform var(--bslib-sidebar-toggle-transition-easing) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout>.collapse-toggle:hover>.collapse-icon{opacity:1}.bslib-sidebar-layout .sidebar-title{font-size:1.25rem;line-height:1.25;margin-top:0;margin-bottom:1rem;padding-bottom:1rem;border-bottom:var(--bslib-sidebar-border)}.bslib-sidebar-layout.sidebar-right{grid-template-columns:var(--bslib-sidebar-column-main) min(100% - var(--bslib-sidebar-icon-size),var(--bslib-sidebar-width, 250px))}.bslib-sidebar-layout.sidebar-right>.main{grid-column:1/2;border-top-right-radius:0;border-bottom-right-radius:0;border-top-left-radius:inherit;border-bottom-left-radius:inherit}.bslib-sidebar-layout.sidebar-right>.sidebar{grid-column:2/3;border-right:none;border-left:var(--bslib-sidebar-vert-border);border-top-left-radius:0;border-bottom-left-radius:0}.bslib-sidebar-layout.sidebar-right>.collapse-toggle{grid-column:2/3;left:var(--bslib-sidebar-icon-size);right:unset;border:var(--bslib-collapse-toggle-border)}.bslib-sidebar-layout.sidebar-right>.collapse-toggle>.collapse-icon{transform:rotateY(var(--bslib-collapse-toggle-right-transform))}.bslib-sidebar-layout.sidebar-collapsed{--bslib-collapse-toggle-transform: 180deg;--bslib-collapse-toggle-right-transform: 0deg;--bslib-sidebar-vert-border: none;grid-template-columns:0 minmax(0, 1fr)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right{grid-template-columns:minmax(0, 1fr) 0}.bslib-sidebar-layout.sidebar-collapsed:not(.transitioning)>.sidebar>*{display:none}.bslib-sidebar-layout.sidebar-collapsed>.main{border-radius:inherit}.bslib-sidebar-layout.sidebar-collapsed:not(.sidebar-right)>.main{padding-left:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.main{padding-right:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout.sidebar-collapsed>.collapse-toggle{color:var(--bslib-sidebar-main-fg);top:calc(var(--bslib-sidebar-overlap-counter, 0)*(var(--bslib-sidebar-icon-size) + var(--bslib-sidebar-padding)) + var(--bslib-sidebar-icon-size, 1rem)/2);right:calc(-2.5*var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px))}.bslib-sidebar-layout.sidebar-collapsed.sidebar-right>.collapse-toggle{left:calc(-2.5*var(--bslib-sidebar-icon-size) - var(--bs-card-border-width, 1px));right:unset}@media(min-width: 576px){.bslib-sidebar-layout.transitioning>.sidebar>.sidebar-content{display:none}}@media(max-width: 575.98px){.bslib-sidebar-layout[data-bslib-sidebar-open=desktop]{--bslib-sidebar-js-init-collapsed: true}.bslib-sidebar-layout>.sidebar,.bslib-sidebar-layout.sidebar-right>.sidebar{border:none}.bslib-sidebar-layout>.main,.bslib-sidebar-layout.sidebar-right>.main{grid-column:1/3}.bslib-sidebar-layout[data-bslib-sidebar-open=always]{display:block !important}.bslib-sidebar-layout[data-bslib-sidebar-open=always]>.sidebar{max-height:var(--bslib-sidebar-max-height-mobile);overflow-y:auto;border-top:var(--bslib-sidebar-vert-border)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]){grid-template-columns:100% 0}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-collapsed)>.sidebar{z-index:1}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-collapsed)>.collapse-toggle{z-index:1}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-right{grid-template-columns:0 100%}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed{grid-template-columns:0 100%}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed.sidebar-right{grid-template-columns:100% 0}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]):not(.sidebar-right)>.main{padding-left:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-right>.main{padding-right:var(--bslib-sidebar-padding-icon)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always])>.main{opacity:0;transition:opacity var(--bslib-sidebar-transition-easing-x) var(--bslib-sidebar-transition-duration)}.bslib-sidebar-layout:not([data-bslib-sidebar-open=always]).sidebar-collapsed>.main{opacity:1}}@media(min-width: 576px){.nav:not(.nav-hidden){display:flex !important;display:-webkit-flex !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column){float:none !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column)>.bslib-nav-spacer{margin-left:auto !important}.nav:not(.nav-hidden):not(.nav-stacked):not(.flex-column)>.form-inline{margin-top:auto;margin-bottom:auto}.nav:not(.nav-hidden).nav-stacked{flex-direction:column;-webkit-flex-direction:column;height:100%}.nav:not(.nav-hidden).nav-stacked>.bslib-nav-spacer{margin-top:auto !important}}html{height:100%}.bslib-page-fill{width:100%;height:100%;margin:0;padding:var(--bslib-spacer, 1rem);gap:var(--bslib-spacer, 1rem)}@media(max-width: 575.98px){.bslib-page-fill{height:var(--bslib-page-fill-mobile-height, auto)}}.html-fill-container{display:flex;flex-direction:column;min-height:0;min-width:0}.html-fill-container>.html-fill-item{flex:1 1 auto;min-height:0;min-width:0}.html-fill-container>:not(.html-fill-item){flex:0 0 auto}.quarto-container{min-height:calc(100vh - 132px)}body.hypothesis-enabled #quarto-header{margin-right:16px}footer.footer .nav-footer,#quarto-header>nav{padding-left:1em;padding-right:1em}footer.footer div.nav-footer p:first-child{margin-top:0}footer.footer div.nav-footer p:last-child{margin-bottom:0}#quarto-content>*{padding-top:14px}#quarto-content>#quarto-sidebar-glass{padding-top:0px}@media(max-width: 991.98px){#quarto-content>*{padding-top:0}#quarto-content .subtitle{padding-top:14px}#quarto-content section:first-of-type h2:first-of-type,#quarto-content section:first-of-type .h2:first-of-type{margin-top:1rem}}.headroom-target,header.headroom{will-change:transform;transition:position 200ms linear;transition:all 200ms linear}header.headroom--pinned{transform:translateY(0%)}header.headroom--unpinned{transform:translateY(-100%)}.navbar-container{width:100%}.navbar-brand{overflow:hidden;text-overflow:ellipsis}.navbar-brand-container{max-width:calc(100% - 115px);min-width:0;display:flex;align-items:center}@media(min-width: 992px){.navbar-brand-container{margin-right:1em}}.navbar-brand.navbar-brand-logo{margin-right:4px;display:inline-flex}.navbar-toggler{flex-basis:content;flex-shrink:0}.navbar .navbar-brand-container{order:2}.navbar .navbar-toggler{order:1}.navbar .navbar-container>.navbar-nav{order:20}.navbar .navbar-container>.navbar-brand-container{margin-left:0 !important;margin-right:0 !important}.navbar .navbar-collapse{order:20}.navbar #quarto-search{order:4;margin-left:auto}.navbar .navbar-toggler{margin-right:.5em}.navbar-collapse .quarto-navbar-tools{margin-left:.5em}.navbar-logo{max-height:24px;width:auto;padding-right:4px}nav .nav-item:not(.compact){padding-top:1px}nav .nav-link i,nav .dropdown-item i{padding-right:1px}.navbar-expand-lg .navbar-nav .nav-link{padding-left:.6rem;padding-right:.6rem}nav .nav-item.compact .nav-link{padding-left:.5rem;padding-right:.5rem;font-size:1.1rem}.navbar .quarto-navbar-tools{order:3}.navbar .quarto-navbar-tools div.dropdown{display:inline-block}.navbar .quarto-navbar-tools .quarto-navigation-tool{color:#fdfeff}.navbar .quarto-navbar-tools .quarto-navigation-tool:hover{color:#fdfdff}.navbar-nav .dropdown-menu{min-width:220px;font-size:.9rem}.navbar .navbar-nav .nav-link.dropdown-toggle::after{opacity:.75;vertical-align:.175em}.navbar ul.dropdown-menu{padding-top:0;padding-bottom:0}.navbar .dropdown-header{text-transform:uppercase;font-size:.8rem;padding:0 .5rem}.navbar .dropdown-item{padding:.4rem .5rem}.navbar .dropdown-item>i.bi{margin-left:.1rem;margin-right:.25em}.sidebar #quarto-search{margin-top:-1px}.sidebar #quarto-search svg.aa-SubmitIcon{width:16px;height:16px}.sidebar-navigation a{color:inherit}.sidebar-title{margin-top:.25rem;padding-bottom:.5rem;font-size:1.3rem;line-height:1.6rem;visibility:visible}.sidebar-title>a{font-size:inherit;text-decoration:none}.sidebar-title .sidebar-tools-main{margin-top:-6px}@media(max-width: 991.98px){#quarto-sidebar div.sidebar-header{padding-top:.2em}}.sidebar-header-stacked .sidebar-title{margin-top:.6rem}.sidebar-logo{max-width:90%;padding-bottom:.5rem}.sidebar-logo-link{text-decoration:none}.sidebar-navigation li a{text-decoration:none}.sidebar-navigation .quarto-navigation-tool{opacity:.7;font-size:.875rem}#quarto-sidebar>nav>.sidebar-tools-main{margin-left:14px}.sidebar-tools-main{display:inline-flex;margin-left:0px;order:2}.sidebar-tools-main:not(.tools-wide){vertical-align:middle}.sidebar-navigation .quarto-navigation-tool.dropdown-toggle::after{display:none}.sidebar.sidebar-navigation>*{padding-top:1em}.sidebar-item{margin-bottom:.2em;line-height:1rem;margin-top:.4rem}.sidebar-section{padding-left:.5em;padding-bottom:.2em}.sidebar-item .sidebar-item-container{display:flex;justify-content:space-between;cursor:pointer}.sidebar-item-toggle:hover{cursor:pointer}.sidebar-item .sidebar-item-toggle .bi{font-size:.7rem;text-align:center}.sidebar-item .sidebar-item-toggle .bi-chevron-right::before{transition:transform 200ms ease}.sidebar-item .sidebar-item-toggle[aria-expanded=false] .bi-chevron-right::before{transform:none}.sidebar-item .sidebar-item-toggle[aria-expanded=true] .bi-chevron-right::before{transform:rotate(90deg)}.sidebar-item-text{width:100%}.sidebar-navigation .sidebar-divider{margin-left:0;margin-right:0;margin-top:.5rem;margin-bottom:.5rem}@media(max-width: 991.98px){.quarto-secondary-nav{display:block}.quarto-secondary-nav button.quarto-search-button{padding-right:0em;padding-left:2em}.quarto-secondary-nav button.quarto-btn-toggle{margin-left:-0.75rem;margin-right:.15rem}.quarto-secondary-nav nav.quarto-title-breadcrumbs{display:none}.quarto-secondary-nav nav.quarto-page-breadcrumbs{display:flex;align-items:center;padding-right:1em;margin-left:-0.25em}.quarto-secondary-nav nav.quarto-page-breadcrumbs a{text-decoration:none}.quarto-secondary-nav nav.quarto-page-breadcrumbs ol.breadcrumb{margin-bottom:0}}@media(min-width: 992px){.quarto-secondary-nav{display:none}}.quarto-title-breadcrumbs .breadcrumb{margin-bottom:.5em;font-size:.9rem}.quarto-title-breadcrumbs .breadcrumb li:last-of-type a{color:#6c757d}.quarto-secondary-nav .quarto-btn-toggle{color:#595959}.quarto-secondary-nav[aria-expanded=false] .quarto-btn-toggle .bi-chevron-right::before{transform:none}.quarto-secondary-nav[aria-expanded=true] .quarto-btn-toggle .bi-chevron-right::before{transform:rotate(90deg)}.quarto-secondary-nav .quarto-btn-toggle .bi-chevron-right::before{transition:transform 200ms ease}.quarto-secondary-nav{cursor:pointer}.no-decor{text-decoration:none}.quarto-secondary-nav-title{margin-top:.3em;color:#595959;padding-top:4px}.quarto-secondary-nav nav.quarto-page-breadcrumbs{color:#595959}.quarto-secondary-nav nav.quarto-page-breadcrumbs a{color:#595959}.quarto-secondary-nav nav.quarto-page-breadcrumbs a:hover{color:rgba(33,81,191,.8)}.quarto-secondary-nav nav.quarto-page-breadcrumbs .breadcrumb-item::before{color:#8c8c8c}.breadcrumb-item{line-height:1.2rem}div.sidebar-item-container{color:#595959}div.sidebar-item-container:hover,div.sidebar-item-container:focus{color:rgba(33,81,191,.8)}div.sidebar-item-container.disabled{color:rgba(89,89,89,.75)}div.sidebar-item-container .active,div.sidebar-item-container .show>.nav-link,div.sidebar-item-container .sidebar-link>code{color:#2151bf}div.sidebar.sidebar-navigation.rollup.quarto-sidebar-toggle-contents,nav.sidebar.sidebar-navigation:not(.rollup){background-color:#fff}@media(max-width: 991.98px){.sidebar-navigation .sidebar-item a,.nav-page .nav-page-text,.sidebar-navigation{font-size:1rem}.sidebar-navigation ul.sidebar-section.depth1 .sidebar-section-item{font-size:1.1rem}.sidebar-logo{display:none}.sidebar.sidebar-navigation{position:static;border-bottom:1px solid #dee2e6}.sidebar.sidebar-navigation.collapsing{position:fixed;z-index:1000}.sidebar.sidebar-navigation.show{position:fixed;z-index:1000}.sidebar.sidebar-navigation{min-height:100%}nav.quarto-secondary-nav{background-color:#fff;border-bottom:1px solid #dee2e6}.quarto-banner nav.quarto-secondary-nav{background-color:#2780e3;color:#fdfeff;border-top:1px solid #dee2e6}.sidebar .sidebar-footer{visibility:visible;padding-top:1rem;position:inherit}.sidebar-tools-collapse{display:block}}#quarto-sidebar{transition:width .15s ease-in}#quarto-sidebar>*{padding-right:1em}@media(max-width: 991.98px){#quarto-sidebar .sidebar-menu-container{white-space:nowrap;min-width:225px}#quarto-sidebar.show{transition:width .15s ease-out}}@media(min-width: 992px){#quarto-sidebar{display:flex;flex-direction:column}.nav-page .nav-page-text,.sidebar-navigation .sidebar-section .sidebar-item{font-size:.875rem}.sidebar-navigation .sidebar-item{font-size:.925rem}.sidebar.sidebar-navigation{display:block;position:sticky}.sidebar-search{width:100%}.sidebar .sidebar-footer{visibility:visible}}@media(min-width: 992px){#quarto-sidebar-glass{display:none}}@media(max-width: 991.98px){#quarto-sidebar-glass{position:fixed;top:0;bottom:0;left:0;right:0;background-color:rgba(255,255,255,0);transition:background-color .15s ease-in;z-index:-1}#quarto-sidebar-glass.collapsing{z-index:1000}#quarto-sidebar-glass.show{transition:background-color .15s ease-out;background-color:rgba(102,102,102,.4);z-index:1000}}.sidebar .sidebar-footer{padding:.5rem 1rem;align-self:flex-end;color:#6c757d;width:100%}.quarto-page-breadcrumbs .breadcrumb-item+.breadcrumb-item,.quarto-page-breadcrumbs .breadcrumb-item{padding-right:.33em;padding-left:0}.quarto-page-breadcrumbs .breadcrumb-item::before{padding-right:.33em}.quarto-sidebar-footer{font-size:.875em}.sidebar-section .bi-chevron-right{vertical-align:middle}.sidebar-section .bi-chevron-right::before{font-size:.9em}.notransition{-webkit-transition:none !important;-moz-transition:none !important;-o-transition:none !important;transition:none !important}.btn:focus:not(:focus-visible){box-shadow:none}.page-navigation{display:flex;justify-content:space-between}.nav-page{padding-bottom:.75em}.nav-page .bi{font-size:1.8rem;vertical-align:middle}.nav-page .nav-page-text{padding-left:.25em;padding-right:.25em}.nav-page a{color:#6c757d;text-decoration:none;display:flex;align-items:center}.nav-page a:hover{color:#1f4eb6}.nav-footer .toc-actions{padding-bottom:.5em;padding-top:.5em}.nav-footer .toc-actions a,.nav-footer .toc-actions a:hover{text-decoration:none}.nav-footer .toc-actions ul{display:flex;list-style:none}.nav-footer .toc-actions ul :first-child{margin-left:auto}.nav-footer .toc-actions ul :last-child{margin-right:auto}.nav-footer .toc-actions ul li{padding-right:1.5em}.nav-footer .toc-actions ul li i.bi{padding-right:.4em}.nav-footer .toc-actions ul li:last-of-type{padding-right:0}.nav-footer{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:baseline;text-align:center;padding-top:.5rem;padding-bottom:.5rem;background-color:#fff}body.nav-fixed{padding-top:64px}.nav-footer-contents{color:#6c757d;margin-top:.25rem}.nav-footer{min-height:3.5em;color:#757575}.nav-footer a{color:#757575}.nav-footer .nav-footer-left{font-size:.825em}.nav-footer .nav-footer-center{font-size:.825em}.nav-footer .nav-footer-right{font-size:.825em}.nav-footer-left .footer-items,.nav-footer-center .footer-items,.nav-footer-right .footer-items{display:inline-flex;padding-top:.3em;padding-bottom:.3em;margin-bottom:0em}.nav-footer-left .footer-items .nav-link,.nav-footer-center .footer-items .nav-link,.nav-footer-right .footer-items .nav-link{padding-left:.6em;padding-right:.6em}@media(min-width: 768px){.nav-footer-left{flex:1 1 0px;text-align:left}}@media(max-width: 575.98px){.nav-footer-left{margin-bottom:1em;flex:100%}}@media(min-width: 768px){.nav-footer-right{flex:1 1 0px;text-align:right}}@media(max-width: 575.98px){.nav-footer-right{margin-bottom:1em;flex:100%}}.nav-footer-center{text-align:center;min-height:3em}@media(min-width: 768px){.nav-footer-center{flex:1 1 0px}}.nav-footer-center .footer-items{justify-content:center}@media(max-width: 767.98px){.nav-footer-center{margin-bottom:1em;flex:100%}}@media(max-width: 767.98px){.nav-footer-center{margin-top:3em;order:10}}.navbar .quarto-reader-toggle.reader .quarto-reader-toggle-btn{background-color:#fdfeff;border-radius:3px}@media(max-width: 991.98px){.quarto-reader-toggle{display:none}}.quarto-reader-toggle.reader.quarto-navigation-tool .quarto-reader-toggle-btn{background-color:#595959;border-radius:3px}.quarto-reader-toggle .quarto-reader-toggle-btn{display:inline-flex;padding-left:.2em;padding-right:.2em;margin-left:-0.2em;margin-right:-0.2em;text-align:center}.navbar .quarto-reader-toggle:not(.reader) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-reader-toggle.reader .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-reader-toggle:not(.reader) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-reader-toggle.reader .bi::before{background-image:url('data:image/svg+xml,')}#quarto-back-to-top{display:none;position:fixed;bottom:50px;background-color:#fff;border-radius:.25rem;box-shadow:0 .2rem .5rem #6c757d,0 0 .05rem #6c757d;color:#6c757d;text-decoration:none;font-size:.9em;text-align:center;left:50%;padding:.4rem .8rem;transform:translate(-50%, 0)}#quarto-announcement{padding:.5em;display:flex;justify-content:space-between;margin-bottom:0;font-size:.9em}#quarto-announcement .quarto-announcement-content{margin-right:auto}#quarto-announcement .quarto-announcement-content p{margin-bottom:0}#quarto-announcement .quarto-announcement-icon{margin-right:.5em;font-size:1.2em;margin-top:-0.15em}#quarto-announcement .quarto-announcement-action{cursor:pointer}.aa-DetachedSearchButtonQuery{display:none}.aa-DetachedOverlay ul.aa-List,#quarto-search-results ul.aa-List{list-style:none;padding-left:0}.aa-DetachedOverlay .aa-Panel,#quarto-search-results .aa-Panel{background-color:#fff;position:absolute;z-index:2000}#quarto-search-results .aa-Panel{max-width:400px}#quarto-search input{font-size:.925rem}@media(min-width: 992px){.navbar #quarto-search{margin-left:.25rem;order:999}}.navbar.navbar-expand-sm #quarto-search,.navbar.navbar-expand-md #quarto-search{order:999}@media(min-width: 992px){.navbar .quarto-navbar-tools{order:900}}@media(min-width: 992px){.navbar .quarto-navbar-tools.tools-end{margin-left:auto !important}}@media(max-width: 991.98px){#quarto-sidebar .sidebar-search{display:none}}#quarto-sidebar .sidebar-search .aa-Autocomplete{width:100%}.navbar .aa-Autocomplete .aa-Form{width:180px}.navbar #quarto-search.type-overlay .aa-Autocomplete{width:40px}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form{background-color:inherit;border:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form:focus-within{box-shadow:none;outline:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-InputWrapper{display:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-InputWrapper:focus-within{display:inherit}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-Label svg,.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-LoadingIndicator svg{width:26px;height:26px;color:#fdfeff;opacity:1}.navbar #quarto-search.type-overlay .aa-Autocomplete svg.aa-SubmitIcon{width:26px;height:26px;color:#fdfeff;opacity:1}.aa-Autocomplete .aa-Form,.aa-DetachedFormContainer .aa-Form{align-items:center;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;color:#343a40;display:flex;line-height:1em;margin:0;position:relative;width:100%}.aa-Autocomplete .aa-Form:focus-within,.aa-DetachedFormContainer .aa-Form:focus-within{box-shadow:rgba(39,128,227,.6) 0 0 0 1px;outline:currentColor none medium}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix{align-items:center;display:flex;flex-shrink:0;order:1}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-Label,.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-Label,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator{cursor:initial;flex-shrink:0;padding:0;text-align:left}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-Label svg,.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-Label svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator svg{color:#343a40;opacity:.5}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-SubmitButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-SubmitButton{appearance:none;background:none;border:0;margin:0}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator{align-items:center;display:flex;justify-content:center}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator[hidden]{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapper,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper{order:3;position:relative;width:100%}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input{appearance:none;background:none;border:0;color:#343a40;font:inherit;height:calc(1.5em + .1rem + 2px);padding:0;width:100%}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::placeholder,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::placeholder{color:#343a40;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input:focus{border-color:none;box-shadow:none;outline:none}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-decoration,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-cancel-button,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-button,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-decoration,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-decoration,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-cancel-button,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-button,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-decoration{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix{align-items:center;display:flex;order:4}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton{align-items:center;background:none;border:0;color:#343a40;opacity:.8;cursor:pointer;display:flex;margin:0;width:calc(1.5em + .1rem + 2px)}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:hover,.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:hover,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:focus{color:#343a40;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton[hidden]{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton svg{width:calc(1.5em + 0.75rem + calc(1px * 2))}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton{border:none;align-items:center;background:none;color:#343a40;opacity:.4;font-size:.7rem;cursor:pointer;display:none;margin:0;width:calc(1em + .1rem + 2px)}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:hover,.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:hover,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:focus{color:#343a40;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton[hidden]{display:none}.aa-PanelLayout:empty{display:none}.quarto-search-no-results.no-query{display:none}.aa-Source:has(.no-query){display:none}#quarto-search-results .aa-Panel{border:solid #dee2e6 1px}#quarto-search-results .aa-SourceNoResults{width:398px}.aa-DetachedOverlay .aa-Panel,#quarto-search-results .aa-Panel{max-height:65vh;overflow-y:auto;font-size:.925rem}.aa-DetachedOverlay .aa-SourceNoResults,#quarto-search-results .aa-SourceNoResults{height:60px;display:flex;justify-content:center;align-items:center}.aa-DetachedOverlay .search-error,#quarto-search-results .search-error{padding-top:10px;padding-left:20px;padding-right:20px;cursor:default}.aa-DetachedOverlay .search-error .search-error-title,#quarto-search-results .search-error .search-error-title{font-size:1.1rem;margin-bottom:.5rem}.aa-DetachedOverlay .search-error .search-error-title .search-error-icon,#quarto-search-results .search-error .search-error-title .search-error-icon{margin-right:8px}.aa-DetachedOverlay .search-error .search-error-text,#quarto-search-results .search-error .search-error-text{font-weight:300}.aa-DetachedOverlay .search-result-text,#quarto-search-results .search-result-text{font-weight:300;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.2rem;max-height:2.4rem}.aa-DetachedOverlay .aa-SourceHeader .search-result-header,#quarto-search-results .aa-SourceHeader .search-result-header{font-size:.875rem;background-color:#f2f2f2;padding-left:14px;padding-bottom:4px;padding-top:4px}.aa-DetachedOverlay .aa-SourceHeader .search-result-header-no-results,#quarto-search-results .aa-SourceHeader .search-result-header-no-results{display:none}.aa-DetachedOverlay .aa-SourceFooter .algolia-search-logo,#quarto-search-results .aa-SourceFooter .algolia-search-logo{width:110px;opacity:.85;margin:8px;float:right}.aa-DetachedOverlay .search-result-section,#quarto-search-results .search-result-section{font-size:.925em}.aa-DetachedOverlay a.search-result-link,#quarto-search-results a.search-result-link{color:inherit;text-decoration:none}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item,#quarto-search-results li.aa-Item[aria-selected=true] .search-item{background-color:#2780e3}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item.search-result-more,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-section,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-text,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-title-container,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-text-container,#quarto-search-results li.aa-Item[aria-selected=true] .search-item.search-result-more,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-section,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-text,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-title-container,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-text-container{color:#fff;background-color:#2780e3}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item mark.search-match,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-match.mark,#quarto-search-results li.aa-Item[aria-selected=true] .search-item mark.search-match,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-match.mark{color:#fff;background-color:#4b95e8}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item,#quarto-search-results li.aa-Item[aria-selected=false] .search-item{background-color:#fff}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item.search-result-more,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-section,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-title-container,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text-container,#quarto-search-results li.aa-Item[aria-selected=false] .search-item.search-result-more,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-section,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-title-container,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text-container{color:#343a40}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item mark.search-match,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-match.mark,#quarto-search-results li.aa-Item[aria-selected=false] .search-item mark.search-match,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-match.mark{color:inherit;background-color:#e5effc}.aa-DetachedOverlay .aa-Item .search-result-doc:not(.document-selectable) .search-result-title-container,#quarto-search-results .aa-Item .search-result-doc:not(.document-selectable) .search-result-title-container{background-color:#fff;color:#343a40}.aa-DetachedOverlay .aa-Item .search-result-doc:not(.document-selectable) .search-result-text-container,#quarto-search-results .aa-Item .search-result-doc:not(.document-selectable) .search-result-text-container{padding-top:0px}.aa-DetachedOverlay li.aa-Item .search-result-doc.document-selectable .search-result-text-container,#quarto-search-results li.aa-Item .search-result-doc.document-selectable .search-result-text-container{margin-top:-4px}.aa-DetachedOverlay .aa-Item,#quarto-search-results .aa-Item{cursor:pointer}.aa-DetachedOverlay .aa-Item .search-item,#quarto-search-results .aa-Item .search-item{border-left:none;border-right:none;border-top:none;background-color:#fff;border-color:#dee2e6;color:#343a40}.aa-DetachedOverlay .aa-Item .search-item p,#quarto-search-results .aa-Item .search-item p{margin-top:0;margin-bottom:0}.aa-DetachedOverlay .aa-Item .search-item i.bi,#quarto-search-results .aa-Item .search-item i.bi{padding-left:8px;padding-right:8px;font-size:1.3em}.aa-DetachedOverlay .aa-Item .search-item .search-result-title,#quarto-search-results .aa-Item .search-item .search-result-title{margin-top:.3em;margin-bottom:0em}.aa-DetachedOverlay .aa-Item .search-item .search-result-crumbs,#quarto-search-results .aa-Item .search-item .search-result-crumbs{white-space:nowrap;text-overflow:ellipsis;font-size:.8em;font-weight:300;margin-right:1em}.aa-DetachedOverlay .aa-Item .search-item .search-result-crumbs:not(.search-result-crumbs-wrap),#quarto-search-results .aa-Item .search-item .search-result-crumbs:not(.search-result-crumbs-wrap){max-width:30%;margin-left:auto;margin-top:.5em;margin-bottom:.1rem}.aa-DetachedOverlay .aa-Item .search-item .search-result-crumbs.search-result-crumbs-wrap,#quarto-search-results .aa-Item .search-item .search-result-crumbs.search-result-crumbs-wrap{flex-basis:100%;margin-top:0em;margin-bottom:.2em;margin-left:37px}.aa-DetachedOverlay .aa-Item .search-result-title-container,#quarto-search-results .aa-Item .search-result-title-container{font-size:1em;display:flex;flex-wrap:wrap;padding:6px 4px 6px 4px}.aa-DetachedOverlay .aa-Item .search-result-text-container,#quarto-search-results .aa-Item .search-result-text-container{padding-bottom:8px;padding-right:8px;margin-left:42px}.aa-DetachedOverlay .aa-Item .search-result-doc-section,.aa-DetachedOverlay .aa-Item .search-result-more,#quarto-search-results .aa-Item .search-result-doc-section,#quarto-search-results .aa-Item .search-result-more{padding-top:8px;padding-bottom:8px;padding-left:44px}.aa-DetachedOverlay .aa-Item .search-result-more,#quarto-search-results .aa-Item .search-result-more{font-size:.8em;font-weight:400}.aa-DetachedOverlay .aa-Item .search-result-doc,#quarto-search-results .aa-Item .search-result-doc{border-top:1px solid #dee2e6}.aa-DetachedSearchButton{background:none;border:none}.aa-DetachedSearchButton .aa-DetachedSearchButtonPlaceholder{display:none}.navbar .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon{color:#fdfeff}.sidebar-tools-collapse #quarto-search,.sidebar-tools-main #quarto-search{display:inline}.sidebar-tools-collapse #quarto-search .aa-Autocomplete,.sidebar-tools-main #quarto-search .aa-Autocomplete{display:inline}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton{padding-left:4px;padding-right:4px}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon{color:#595959}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon .aa-SubmitIcon,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon .aa-SubmitIcon{margin-top:-3px}.aa-DetachedContainer{background:rgba(255,255,255,.65);width:90%;bottom:0;box-shadow:rgba(222,226,230,.6) 0 0 0 1px;outline:currentColor none medium;display:flex;flex-direction:column;left:0;margin:0;overflow:hidden;padding:0;position:fixed;right:0;top:0;z-index:1101}.aa-DetachedContainer::after{height:32px}.aa-DetachedContainer .aa-SourceHeader{margin:var(--aa-spacing-half) 0 var(--aa-spacing-half) 2px}.aa-DetachedContainer .aa-Panel{background-color:#fff;border-radius:0;box-shadow:none;flex-grow:1;margin:0;padding:0;position:relative}.aa-DetachedContainer .aa-PanelLayout{bottom:0;box-shadow:none;left:0;margin:0;max-height:none;overflow-y:auto;position:absolute;right:0;top:0;width:100%}.aa-DetachedFormContainer{background-color:#fff;border-bottom:1px solid #dee2e6;display:flex;flex-direction:row;justify-content:space-between;margin:0;padding:.5em}.aa-DetachedCancelButton{background:none;font-size:.8em;border:0;border-radius:3px;color:#343a40;cursor:pointer;margin:0 0 0 .5em;padding:0 .5em}.aa-DetachedCancelButton:hover,.aa-DetachedCancelButton:focus{box-shadow:rgba(39,128,227,.6) 0 0 0 1px;outline:currentColor none medium}.aa-DetachedContainer--modal{bottom:inherit;height:auto;margin:0 auto;position:absolute;top:100px;border-radius:6px;max-width:850px}@media(max-width: 575.98px){.aa-DetachedContainer--modal{width:100%;top:0px;border-radius:0px;border:none}}.aa-DetachedContainer--modal .aa-PanelLayout{max-height:var(--aa-detached-modal-max-height);padding-bottom:var(--aa-spacing-half);position:static}.aa-Detached{height:100vh;overflow:hidden}.aa-DetachedOverlay{background-color:rgba(52,58,64,.4);position:fixed;left:0;right:0;top:0;margin:0;padding:0;height:100vh;z-index:1100}.quarto-dashboard.nav-fixed.dashboard-sidebar #quarto-content.quarto-dashboard-content{padding:0em}.quarto-dashboard #quarto-content.quarto-dashboard-content{padding:1em}.quarto-dashboard #quarto-content.quarto-dashboard-content>*{padding-top:0}@media(min-width: 576px){.quarto-dashboard{height:100%}}.quarto-dashboard .card.valuebox.bslib-card.bg-primary{background-color:#5397e9 !important}.quarto-dashboard .card.valuebox.bslib-card.bg-secondary{background-color:#343a40 !important}.quarto-dashboard .card.valuebox.bslib-card.bg-success{background-color:#3aa716 !important}.quarto-dashboard .card.valuebox.bslib-card.bg-info{background-color:rgba(153,84,187,.7019607843) !important}.quarto-dashboard .card.valuebox.bslib-card.bg-warning{background-color:#fa6400 !important}.quarto-dashboard .card.valuebox.bslib-card.bg-danger{background-color:rgba(255,0,57,.7019607843) !important}.quarto-dashboard .card.valuebox.bslib-card.bg-light{background-color:#f8f9fa !important}.quarto-dashboard .card.valuebox.bslib-card.bg-dark{background-color:#343a40 !important}.quarto-dashboard.dashboard-fill{display:flex;flex-direction:column}.quarto-dashboard #quarto-appendix{display:none}.quarto-dashboard #quarto-header #quarto-dashboard-header{border-top:solid 1px #549be9;border-bottom:solid 1px #549be9}.quarto-dashboard #quarto-header #quarto-dashboard-header>nav{padding-left:1em;padding-right:1em}.quarto-dashboard #quarto-header #quarto-dashboard-header>nav .navbar-brand-container{padding-left:0}.quarto-dashboard #quarto-header #quarto-dashboard-header .navbar-toggler{margin-right:0}.quarto-dashboard #quarto-header #quarto-dashboard-header .navbar-toggler-icon{height:1em;width:1em;background-image:url('data:image/svg+xml,')}.quarto-dashboard #quarto-header #quarto-dashboard-header .navbar-brand-container{padding-right:1em}.quarto-dashboard #quarto-header #quarto-dashboard-header .navbar-title{font-size:1.1em}.quarto-dashboard #quarto-header #quarto-dashboard-header .navbar-nav{font-size:.9em}.quarto-dashboard #quarto-dashboard-header .navbar{padding:0}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-container{padding-left:1em}.quarto-dashboard #quarto-dashboard-header .navbar.slim .navbar-brand-container .nav-link,.quarto-dashboard #quarto-dashboard-header .navbar.slim .navbar-nav .nav-link{padding:.7em}.quarto-dashboard #quarto-dashboard-header .navbar .quarto-color-scheme-toggle{order:9}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-toggler{margin-left:.5em;order:10}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-nav .nav-link{padding:.5em;height:100%;display:flex;align-items:center}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-nav .active{background-color:#4b95e8}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-brand-container{padding:.5em .5em .5em 0;display:flex;flex-direction:row;margin-right:2em;align-items:center}@media(max-width: 767.98px){.quarto-dashboard #quarto-dashboard-header .navbar .navbar-brand-container{margin-right:auto}}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-collapse{align-self:stretch}@media(min-width: 768px){.quarto-dashboard #quarto-dashboard-header .navbar .navbar-collapse{order:8}}@media(max-width: 767.98px){.quarto-dashboard #quarto-dashboard-header .navbar .navbar-collapse{order:1000;padding-bottom:.5em}}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-collapse .navbar-nav{align-self:stretch}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-title{font-size:1.25em;line-height:1.1em;display:flex;flex-direction:row;flex-wrap:wrap;align-items:baseline}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-title .navbar-title-text{margin-right:.4em}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-title a{text-decoration:none;color:inherit}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-subtitle,.quarto-dashboard #quarto-dashboard-header .navbar .navbar-author{font-size:.9rem;margin-right:.5em}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-author{margin-left:auto}.quarto-dashboard #quarto-dashboard-header .navbar .navbar-logo{max-height:48px;min-height:30px;object-fit:cover;margin-right:1em}.quarto-dashboard #quarto-dashboard-header .navbar .quarto-dashboard-links{order:9;padding-right:1em}.quarto-dashboard #quarto-dashboard-header .navbar .quarto-dashboard-link-text{margin-left:.25em}.quarto-dashboard #quarto-dashboard-header .navbar .quarto-dashboard-link{padding-right:0em;padding-left:.7em;text-decoration:none;color:#fdfeff}.quarto-dashboard .page-layout-custom .tab-content{padding:0;border:none}.quarto-dashboard-img-contain{height:100%;width:100%;object-fit:contain}@media(max-width: 575.98px){.quarto-dashboard .bslib-grid{grid-template-rows:minmax(1em, max-content) !important}.quarto-dashboard .sidebar-content{height:inherit}.quarto-dashboard .page-layout-custom{min-height:100vh}}.quarto-dashboard.dashboard-toolbar>.page-layout-custom,.quarto-dashboard.dashboard-sidebar>.page-layout-custom{padding:0}.quarto-dashboard .quarto-dashboard-content.quarto-dashboard-pages{padding:0}.quarto-dashboard .callout{margin-bottom:0;margin-top:0}.quarto-dashboard .html-fill-container figure{overflow:hidden}.quarto-dashboard bslib-tooltip .rounded-pill{border:solid #6c757d 1px}.quarto-dashboard bslib-tooltip .rounded-pill .svg{fill:#343a40}.quarto-dashboard .tabset .dashboard-card-no-title .nav-tabs{margin-left:0;margin-right:auto}.quarto-dashboard .tabset .tab-content{border:none}.quarto-dashboard .tabset .card-header .nav-link[role=tab]{margin-top:-6px;padding-top:6px;padding-bottom:6px}.quarto-dashboard .card.valuebox,.quarto-dashboard .card.bslib-value-box{min-height:3rem}.quarto-dashboard .card.valuebox .card-body,.quarto-dashboard .card.bslib-value-box .card-body{padding:0}.quarto-dashboard .bslib-value-box .value-box-value{font-size:clamp(.1em,15cqw,5em)}.quarto-dashboard .bslib-value-box .value-box-showcase .bi{font-size:clamp(.1em,max(18cqw,5.2cqh),5em);text-align:center;height:1em}.quarto-dashboard .bslib-value-box .value-box-showcase .bi::before{vertical-align:1em}.quarto-dashboard .bslib-value-box .value-box-area{margin-top:auto;margin-bottom:auto}.quarto-dashboard .card figure.quarto-float{display:flex;flex-direction:column;align-items:center}.quarto-dashboard .dashboard-scrolling{padding:1em}.quarto-dashboard .full-height{height:100%}.quarto-dashboard .showcase-bottom .value-box-grid{display:grid;grid-template-columns:1fr;grid-template-rows:1fr auto;grid-template-areas:"top" "bottom"}.quarto-dashboard .showcase-bottom .value-box-grid .value-box-showcase{grid-area:bottom;padding:0;margin:0}.quarto-dashboard .showcase-bottom .value-box-grid .value-box-showcase i.bi{font-size:4rem}.quarto-dashboard .showcase-bottom .value-box-grid .value-box-area{grid-area:top}.quarto-dashboard .tab-content{margin-bottom:0}.quarto-dashboard .bslib-card .bslib-navs-card-title{justify-content:stretch;align-items:end}.quarto-dashboard .card-header{display:flex;flex-wrap:wrap;justify-content:space-between}.quarto-dashboard .card-header .card-title{display:flex;flex-direction:column;justify-content:center;margin-bottom:0}.quarto-dashboard .tabset .card-toolbar{margin-bottom:1em}.quarto-dashboard .bslib-grid>.bslib-sidebar-layout{border:none;gap:var(--bslib-spacer, 1rem)}.quarto-dashboard .bslib-grid>.bslib-sidebar-layout>.main{padding:0}.quarto-dashboard .bslib-grid>.bslib-sidebar-layout>.sidebar{border-radius:.25rem;border:1px solid rgba(0,0,0,.175)}.quarto-dashboard .bslib-grid>.bslib-sidebar-layout>.collapse-toggle{display:none}@media(max-width: 767.98px){.quarto-dashboard .bslib-grid>.bslib-sidebar-layout{grid-template-columns:1fr;grid-template-rows:max-content 1fr}.quarto-dashboard .bslib-grid>.bslib-sidebar-layout>.main{grid-column:1;grid-row:2}.quarto-dashboard .bslib-grid>.bslib-sidebar-layout .sidebar{grid-column:1;grid-row:1}}.quarto-dashboard .sidebar-right .sidebar{padding-left:2.5em}.quarto-dashboard .sidebar-right .collapse-toggle{left:2px}.quarto-dashboard .quarto-dashboard .sidebar-right button.collapse-toggle:not(.transitioning){left:unset}.quarto-dashboard aside.sidebar{padding-left:1em;padding-right:1em;background-color:rgba(52,58,64,.25);color:#343a40}.quarto-dashboard .bslib-sidebar-layout>div.main{padding:.7em}.quarto-dashboard .bslib-sidebar-layout button.collapse-toggle{margin-top:.3em}.quarto-dashboard .bslib-sidebar-layout .collapse-toggle{top:0}.quarto-dashboard .bslib-sidebar-layout.sidebar-collapsed:not(.transitioning):not(.sidebar-right) .collapse-toggle{left:2px}.quarto-dashboard .sidebar>section>.h3:first-of-type{margin-top:0em}.quarto-dashboard .sidebar .h3,.quarto-dashboard .sidebar .h4,.quarto-dashboard .sidebar .h5,.quarto-dashboard .sidebar .h6{margin-top:.5em}.quarto-dashboard .sidebar form{flex-direction:column;align-items:start;margin-bottom:1em}.quarto-dashboard .sidebar form div[class*=oi-][class$=-input]{flex-direction:column}.quarto-dashboard .sidebar form[class*=oi-][class$=-toggle]{flex-direction:row-reverse;align-items:center;justify-content:start}.quarto-dashboard .sidebar form input[type=range]{margin-top:.5em;margin-right:.8em;margin-left:1em}.quarto-dashboard .sidebar label{width:fit-content}.quarto-dashboard .sidebar .card-body{margin-bottom:2em}.quarto-dashboard .sidebar .shiny-input-container{margin-bottom:1em}.quarto-dashboard .sidebar .shiny-options-group{margin-top:0}.quarto-dashboard .sidebar .control-label{margin-bottom:.3em}.quarto-dashboard .card .card-body .quarto-layout-row{align-items:stretch}.quarto-dashboard .toolbar{font-size:.9em;display:flex;flex-direction:row;border-top:solid 1px #bcbfc0;padding:1em;flex-wrap:wrap;background-color:rgba(52,58,64,.25)}.quarto-dashboard .toolbar .cell-output-display{display:flex}.quarto-dashboard .toolbar .shiny-input-container{padding-bottom:.5em;margin-bottom:.5em;width:inherit}.quarto-dashboard .toolbar .shiny-input-container>.checkbox:first-child{margin-top:6px}.quarto-dashboard .toolbar>*:last-child{margin-right:0}.quarto-dashboard .toolbar>*>*{margin-right:1em;align-items:baseline}.quarto-dashboard .toolbar>*>*>a{text-decoration:none;margin-top:auto;margin-bottom:auto}.quarto-dashboard .toolbar .shiny-input-container{padding-bottom:0;margin-bottom:0}.quarto-dashboard .toolbar .shiny-input-container>*{flex-shrink:0;flex-grow:0}.quarto-dashboard .toolbar .form-group.shiny-input-container:not([role=group])>label{margin-bottom:0}.quarto-dashboard .toolbar .shiny-input-container.no-baseline{align-items:start;padding-top:6px}.quarto-dashboard .toolbar .shiny-input-container{display:flex;align-items:baseline}.quarto-dashboard .toolbar .shiny-input-container label{padding-right:.4em}.quarto-dashboard .toolbar .shiny-input-container .bslib-input-switch{margin-top:6px}.quarto-dashboard .toolbar input[type=text]{line-height:1;width:inherit}.quarto-dashboard .toolbar .input-daterange{width:inherit}.quarto-dashboard .toolbar .input-daterange input[type=text]{height:2.4em;width:10em}.quarto-dashboard .toolbar .input-daterange .input-group-addon{height:auto;padding:0;margin-left:-5px !important;margin-right:-5px}.quarto-dashboard .toolbar .input-daterange .input-group-addon .input-group-text{padding-top:0;padding-bottom:0;height:100%}.quarto-dashboard .toolbar span.irs.irs--shiny{width:10em}.quarto-dashboard .toolbar span.irs.irs--shiny .irs-line{top:9px}.quarto-dashboard .toolbar span.irs.irs--shiny .irs-min,.quarto-dashboard .toolbar span.irs.irs--shiny .irs-max,.quarto-dashboard .toolbar span.irs.irs--shiny .irs-from,.quarto-dashboard .toolbar span.irs.irs--shiny .irs-to,.quarto-dashboard .toolbar span.irs.irs--shiny .irs-single{top:20px}.quarto-dashboard .toolbar span.irs.irs--shiny .irs-bar{top:8px}.quarto-dashboard .toolbar span.irs.irs--shiny .irs-handle{top:0px}.quarto-dashboard .toolbar .shiny-input-checkboxgroup>label{margin-top:6px}.quarto-dashboard .toolbar .shiny-input-checkboxgroup>.shiny-options-group{margin-top:0;align-items:baseline}.quarto-dashboard .toolbar .shiny-input-radiogroup>label{margin-top:6px}.quarto-dashboard .toolbar .shiny-input-radiogroup>.shiny-options-group{align-items:baseline;margin-top:0}.quarto-dashboard .toolbar .shiny-input-radiogroup>.shiny-options-group>.radio{margin-right:.3em}.quarto-dashboard .toolbar .form-select{padding-top:.2em;padding-bottom:.2em}.quarto-dashboard .toolbar .shiny-input-select{min-width:6em}.quarto-dashboard .toolbar div.checkbox{margin-bottom:0px}.quarto-dashboard .toolbar>.checkbox:first-child{margin-top:6px}.quarto-dashboard .toolbar form{width:fit-content}.quarto-dashboard .toolbar form label{padding-top:.2em;padding-bottom:.2em;width:fit-content}.quarto-dashboard .toolbar form input[type=date]{width:fit-content}.quarto-dashboard .toolbar form input[type=color]{width:3em}.quarto-dashboard .toolbar form button{padding:.4em}.quarto-dashboard .toolbar form select{width:fit-content}.quarto-dashboard .toolbar>*{font-size:.9em;flex-grow:0}.quarto-dashboard .toolbar .shiny-input-container label{margin-bottom:1px}.quarto-dashboard .toolbar-bottom{margin-top:1em;margin-bottom:0 !important;order:2}.quarto-dashboard .quarto-dashboard-content>.dashboard-toolbar-container>.toolbar-content>.tab-content>.tab-pane>*:not(.bslib-sidebar-layout){padding:1em}.quarto-dashboard .quarto-dashboard-content>.dashboard-toolbar-container>.toolbar-content>*:not(.tab-content){padding:1em}.quarto-dashboard .quarto-dashboard-content>.tab-content>.dashboard-page>.dashboard-toolbar-container>.toolbar-content,.quarto-dashboard .quarto-dashboard-content>.tab-content>.dashboard-page:not(.dashboard-sidebar-container)>*:not(.dashboard-toolbar-container){padding:1em}.quarto-dashboard .toolbar-content{padding:0}.quarto-dashboard .quarto-dashboard-content.quarto-dashboard-pages .tab-pane>.dashboard-toolbar-container .toolbar{border-radius:0;margin-bottom:0}.quarto-dashboard .dashboard-toolbar-container.toolbar-toplevel .toolbar{border-bottom:1px solid rgba(0,0,0,.175)}.quarto-dashboard .dashboard-toolbar-container.toolbar-toplevel .toolbar-bottom{margin-top:0}.quarto-dashboard .dashboard-toolbar-container:not(.toolbar-toplevel) .toolbar{margin-bottom:1em;border-top:none;border-radius:.25rem;border:1px solid rgba(0,0,0,.175)}.quarto-dashboard .vega-embed.has-actions details{width:1.7em;height:2em;position:absolute !important;top:0;right:0}.quarto-dashboard .dashboard-toolbar-container{padding:0}.quarto-dashboard .card .card-header p:last-child,.quarto-dashboard .card .card-footer p:last-child{margin-bottom:0}.quarto-dashboard .card .card-body>.h4:first-child{margin-top:0}.quarto-dashboard .card .card-body{z-index:4}@media(max-width: 767.98px){.quarto-dashboard .card .card-body .itables div.dataTables_wrapper div.dataTables_length,.quarto-dashboard .card .card-body .itables div.dataTables_wrapper div.dataTables_info,.quarto-dashboard .card .card-body .itables div.dataTables_wrapper div.dataTables_paginate{text-align:initial}.quarto-dashboard .card .card-body .itables div.dataTables_wrapper div.dataTables_filter{text-align:right}.quarto-dashboard .card .card-body .itables div.dataTables_wrapper div.dataTables_paginate ul.pagination{justify-content:initial}}.quarto-dashboard .card .card-body .itables .dataTables_wrapper{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;padding-top:0}.quarto-dashboard .card .card-body .itables .dataTables_wrapper table{flex-shrink:0}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dt-buttons{margin-bottom:.5em;margin-left:auto;width:fit-content;float:right}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dt-buttons.btn-group{background:#fff;border:none}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dt-buttons .btn-secondary{background-color:#fff;background-image:none;border:solid #dee2e6 1px;padding:.2em .7em}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dt-buttons .btn span{font-size:.8em;color:#343a40}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_info{margin-left:.5em;margin-bottom:.5em;padding-top:0}@media(min-width: 768px){.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_info{font-size:.875em}}@media(max-width: 767.98px){.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_info{font-size:.8em}}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_filter{margin-bottom:.5em;font-size:.875em}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_filter input[type=search]{padding:1px 5px 1px 5px;font-size:.875em}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_length{flex-basis:1 1 50%;margin-bottom:.5em;font-size:.875em}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_length select{padding:.4em 3em .4em .5em;font-size:.875em;margin-left:.2em;margin-right:.2em}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_paginate{flex-shrink:0}@media(min-width: 768px){.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_paginate{margin-left:auto}}.quarto-dashboard .card .card-body .itables .dataTables_wrapper .dataTables_paginate ul.pagination .paginate_button .page-link{font-size:.8em}.quarto-dashboard .card .card-footer{font-size:.9em}.quarto-dashboard .card .card-toolbar{display:flex;flex-grow:1;flex-direction:row;width:100%;flex-wrap:wrap}.quarto-dashboard .card .card-toolbar>*{font-size:.8em;flex-grow:0}.quarto-dashboard .card .card-toolbar>.card-title{font-size:1em;flex-grow:1;align-self:flex-start;margin-top:.1em}.quarto-dashboard .card .card-toolbar .cell-output-display{display:flex}.quarto-dashboard .card .card-toolbar .shiny-input-container{padding-bottom:.5em;margin-bottom:.5em;width:inherit}.quarto-dashboard .card .card-toolbar .shiny-input-container>.checkbox:first-child{margin-top:6px}.quarto-dashboard .card .card-toolbar>*:last-child{margin-right:0}.quarto-dashboard .card .card-toolbar>*>*{margin-right:1em;align-items:baseline}.quarto-dashboard .card .card-toolbar>*>*>a{text-decoration:none;margin-top:auto;margin-bottom:auto}.quarto-dashboard .card .card-toolbar form{width:fit-content}.quarto-dashboard .card .card-toolbar form label{padding-top:.2em;padding-bottom:.2em;width:fit-content}.quarto-dashboard .card .card-toolbar form input[type=date]{width:fit-content}.quarto-dashboard .card .card-toolbar form input[type=color]{width:3em}.quarto-dashboard .card .card-toolbar form button{padding:.4em}.quarto-dashboard .card .card-toolbar form select{width:fit-content}.quarto-dashboard .card .card-toolbar .cell-output-display{display:flex}.quarto-dashboard .card .card-toolbar .shiny-input-container{padding-bottom:.5em;margin-bottom:.5em;width:inherit}.quarto-dashboard .card .card-toolbar .shiny-input-container>.checkbox:first-child{margin-top:6px}.quarto-dashboard .card .card-toolbar>*:last-child{margin-right:0}.quarto-dashboard .card .card-toolbar>*>*{margin-right:1em;align-items:baseline}.quarto-dashboard .card .card-toolbar>*>*>a{text-decoration:none;margin-top:auto;margin-bottom:auto}.quarto-dashboard .card .card-toolbar .shiny-input-container{padding-bottom:0;margin-bottom:0}.quarto-dashboard .card .card-toolbar .shiny-input-container>*{flex-shrink:0;flex-grow:0}.quarto-dashboard .card .card-toolbar .form-group.shiny-input-container:not([role=group])>label{margin-bottom:0}.quarto-dashboard .card .card-toolbar .shiny-input-container.no-baseline{align-items:start;padding-top:6px}.quarto-dashboard .card .card-toolbar .shiny-input-container{display:flex;align-items:baseline}.quarto-dashboard .card .card-toolbar .shiny-input-container label{padding-right:.4em}.quarto-dashboard .card .card-toolbar .shiny-input-container .bslib-input-switch{margin-top:6px}.quarto-dashboard .card .card-toolbar input[type=text]{line-height:1;width:inherit}.quarto-dashboard .card .card-toolbar .input-daterange{width:inherit}.quarto-dashboard .card .card-toolbar .input-daterange input[type=text]{height:2.4em;width:10em}.quarto-dashboard .card .card-toolbar .input-daterange .input-group-addon{height:auto;padding:0;margin-left:-5px !important;margin-right:-5px}.quarto-dashboard .card .card-toolbar .input-daterange .input-group-addon .input-group-text{padding-top:0;padding-bottom:0;height:100%}.quarto-dashboard .card .card-toolbar span.irs.irs--shiny{width:10em}.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-line{top:9px}.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-min,.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-max,.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-from,.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-to,.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-single{top:20px}.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-bar{top:8px}.quarto-dashboard .card .card-toolbar span.irs.irs--shiny .irs-handle{top:0px}.quarto-dashboard .card .card-toolbar .shiny-input-checkboxgroup>label{margin-top:6px}.quarto-dashboard .card .card-toolbar .shiny-input-checkboxgroup>.shiny-options-group{margin-top:0;align-items:baseline}.quarto-dashboard .card .card-toolbar .shiny-input-radiogroup>label{margin-top:6px}.quarto-dashboard .card .card-toolbar .shiny-input-radiogroup>.shiny-options-group{align-items:baseline;margin-top:0}.quarto-dashboard .card .card-toolbar .shiny-input-radiogroup>.shiny-options-group>.radio{margin-right:.3em}.quarto-dashboard .card .card-toolbar .form-select{padding-top:.2em;padding-bottom:.2em}.quarto-dashboard .card .card-toolbar .shiny-input-select{min-width:6em}.quarto-dashboard .card .card-toolbar div.checkbox{margin-bottom:0px}.quarto-dashboard .card .card-toolbar>.checkbox:first-child{margin-top:6px}.quarto-dashboard .card-body>table>thead{border-top:none}.quarto-dashboard .card-body>.table>:not(caption)>*>*{background-color:#fff}.tableFloatingHeaderOriginal{background-color:#fff;position:sticky !important;top:0 !important}.dashboard-data-table{margin-top:-1px}div.value-box-area span.observablehq--number{font-size:calc(clamp(.1em,15cqw,5em)*1.25);line-height:1.2;color:inherit;font-family:var(--bs-body-font-family)}.quarto-listing{padding-bottom:1em}.listing-pagination{padding-top:.5em}ul.pagination{float:right;padding-left:8px;padding-top:.5em}ul.pagination li{padding-right:.75em}ul.pagination li.disabled a,ul.pagination li.active a{color:#fff;text-decoration:none}ul.pagination li:last-of-type{padding-right:0}.listing-actions-group{display:flex}.quarto-listing-filter{margin-bottom:1em;width:200px;margin-left:auto}.quarto-listing-sort{margin-bottom:1em;margin-right:auto;width:auto}.quarto-listing-sort .input-group-text{font-size:.8em}.input-group-text{border-right:none}.quarto-listing-sort select.form-select{font-size:.8em}.listing-no-matching{text-align:center;padding-top:2em;padding-bottom:3em;font-size:1em}#quarto-margin-sidebar .quarto-listing-category{padding-top:0;font-size:1rem}#quarto-margin-sidebar .quarto-listing-category-title{cursor:pointer;font-weight:600;font-size:1rem}.quarto-listing-category .category{cursor:pointer}.quarto-listing-category .category.active{font-weight:600}.quarto-listing-category.category-cloud{display:flex;flex-wrap:wrap;align-items:baseline}.quarto-listing-category.category-cloud .category{padding-right:5px}.quarto-listing-category.category-cloud .category-cloud-1{font-size:.75em}.quarto-listing-category.category-cloud .category-cloud-2{font-size:.95em}.quarto-listing-category.category-cloud .category-cloud-3{font-size:1.15em}.quarto-listing-category.category-cloud .category-cloud-4{font-size:1.35em}.quarto-listing-category.category-cloud .category-cloud-5{font-size:1.55em}.quarto-listing-category.category-cloud .category-cloud-6{font-size:1.75em}.quarto-listing-category.category-cloud .category-cloud-7{font-size:1.95em}.quarto-listing-category.category-cloud .category-cloud-8{font-size:2.15em}.quarto-listing-category.category-cloud .category-cloud-9{font-size:2.35em}.quarto-listing-category.category-cloud .category-cloud-10{font-size:2.55em}.quarto-listing-cols-1{grid-template-columns:repeat(1, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-1{grid-template-columns:repeat(1, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-1{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-2{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-2{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-2{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-3{grid-template-columns:repeat(3, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-3{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-3{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-4{grid-template-columns:repeat(4, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-4{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-4{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-5{grid-template-columns:repeat(5, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-5{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-5{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-6{grid-template-columns:repeat(6, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-6{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-6{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-7{grid-template-columns:repeat(7, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-7{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-7{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-8{grid-template-columns:repeat(8, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-8{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-8{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-9{grid-template-columns:repeat(9, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-9{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-9{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-10{grid-template-columns:repeat(10, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-10{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-10{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-11{grid-template-columns:repeat(11, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-11{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-11{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-12{grid-template-columns:repeat(12, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-12{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-12{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-grid{gap:1.5em}.quarto-grid-item.borderless{border:none}.quarto-grid-item.borderless .listing-categories .listing-category:last-of-type,.quarto-grid-item.borderless .listing-categories .listing-category:first-of-type{padding-left:0}.quarto-grid-item.borderless .listing-categories .listing-category{border:0}.quarto-grid-link{text-decoration:none;color:inherit}.quarto-grid-link:hover{text-decoration:none;color:inherit}.quarto-grid-item h5.title,.quarto-grid-item .title.h5{margin-top:0;margin-bottom:0}.quarto-grid-item .card-footer{display:flex;justify-content:space-between;font-size:.8em}.quarto-grid-item .card-footer p{margin-bottom:0}.quarto-grid-item p.card-img-top{margin-bottom:0}.quarto-grid-item p.card-img-top>img{object-fit:cover}.quarto-grid-item .card-other-values{margin-top:.5em;font-size:.8em}.quarto-grid-item .card-other-values tr{margin-bottom:.5em}.quarto-grid-item .card-other-values tr>td:first-of-type{font-weight:600;padding-right:1em;padding-left:1em;vertical-align:top}.quarto-grid-item div.post-contents{display:flex;flex-direction:column;text-decoration:none;height:100%}.quarto-grid-item .listing-item-img-placeholder{background-color:rgba(52,58,64,.25);flex-shrink:0}.quarto-grid-item .card-attribution{padding-top:1em;display:flex;gap:1em;text-transform:uppercase;color:#6c757d;font-weight:500;flex-grow:10;align-items:flex-end}.quarto-grid-item .description{padding-bottom:1em}.quarto-grid-item .card-attribution .date{align-self:flex-end}.quarto-grid-item .card-attribution.justify{justify-content:space-between}.quarto-grid-item .card-attribution.start{justify-content:flex-start}.quarto-grid-item .card-attribution.end{justify-content:flex-end}.quarto-grid-item .card-title{margin-bottom:.1em}.quarto-grid-item .card-subtitle{padding-top:.25em}.quarto-grid-item .card-text{font-size:.9em}.quarto-grid-item .listing-reading-time{padding-bottom:.25em}.quarto-grid-item .card-text-small{font-size:.8em}.quarto-grid-item .card-subtitle.subtitle{font-size:.9em;font-weight:600;padding-bottom:.5em}.quarto-grid-item .listing-categories{display:flex;flex-wrap:wrap;padding-bottom:5px}.quarto-grid-item .listing-categories .listing-category{color:#6c757d;border:solid 1px #dee2e6;border-radius:.25rem;text-transform:uppercase;font-size:.65em;padding-left:.5em;padding-right:.5em;padding-top:.15em;padding-bottom:.15em;cursor:pointer;margin-right:4px;margin-bottom:4px}.quarto-grid-item.card-right{text-align:right}.quarto-grid-item.card-right .listing-categories{justify-content:flex-end}.quarto-grid-item.card-left{text-align:left}.quarto-grid-item.card-center{text-align:center}.quarto-grid-item.card-center .listing-description{text-align:justify}.quarto-grid-item.card-center .listing-categories{justify-content:center}table.quarto-listing-table td.image{padding:0px}table.quarto-listing-table td.image img{width:100%;max-width:50px;object-fit:contain}table.quarto-listing-table a{text-decoration:none;word-break:keep-all}table.quarto-listing-table th a{color:inherit}table.quarto-listing-table th a.asc:after{margin-bottom:-2px;margin-left:5px;display:inline-block;height:1rem;width:1rem;background-repeat:no-repeat;background-size:1rem 1rem;background-image:url('data:image/svg+xml,');content:""}table.quarto-listing-table th a.desc:after{margin-bottom:-2px;margin-left:5px;display:inline-block;height:1rem;width:1rem;background-repeat:no-repeat;background-size:1rem 1rem;background-image:url('data:image/svg+xml,');content:""}table.quarto-listing-table.table-hover td{cursor:pointer}.quarto-post.image-left{flex-direction:row}.quarto-post.image-right{flex-direction:row-reverse}@media(max-width: 767.98px){.quarto-post.image-right,.quarto-post.image-left{gap:0em;flex-direction:column}.quarto-post .metadata{padding-bottom:1em;order:2}.quarto-post .body{order:1}.quarto-post .thumbnail{order:3}}.list.quarto-listing-default div:last-of-type{border-bottom:none}@media(min-width: 992px){.quarto-listing-container-default{margin-right:2em}}div.quarto-post{display:flex;gap:2em;margin-bottom:1.5em;border-bottom:1px solid #dee2e6}@media(max-width: 767.98px){div.quarto-post{padding-bottom:1em}}div.quarto-post .metadata{flex-basis:20%;flex-grow:0;margin-top:.2em;flex-shrink:10}div.quarto-post .thumbnail{flex-basis:30%;flex-grow:0;flex-shrink:0}div.quarto-post .thumbnail img{margin-top:.4em;width:100%;object-fit:cover}div.quarto-post .body{flex-basis:45%;flex-grow:1;flex-shrink:0}div.quarto-post .body h3.listing-title,div.quarto-post .body .listing-title.h3{margin-top:0px;margin-bottom:0px;border-bottom:none}div.quarto-post .body .listing-subtitle{font-size:.875em;margin-bottom:.5em;margin-top:.2em}div.quarto-post .body .description{font-size:.9em}div.quarto-post .body pre code{white-space:pre-wrap}div.quarto-post a{color:#343a40;text-decoration:none}div.quarto-post .metadata{display:flex;flex-direction:column;font-size:.8em;font-family:"Source Sans Pro",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";flex-basis:33%}div.quarto-post .listing-categories{display:flex;flex-wrap:wrap;padding-bottom:5px}div.quarto-post .listing-categories .listing-category{color:#6c757d;border:solid 1px #dee2e6;border-radius:.25rem;text-transform:uppercase;font-size:.65em;padding-left:.5em;padding-right:.5em;padding-top:.15em;padding-bottom:.15em;cursor:pointer;margin-right:4px;margin-bottom:4px}div.quarto-post .listing-description{margin-bottom:.5em}div.quarto-about-jolla{display:flex !important;flex-direction:column;align-items:center;margin-top:10%;padding-bottom:1em}div.quarto-about-jolla .about-image{object-fit:cover;margin-left:auto;margin-right:auto;margin-bottom:1.5em}div.quarto-about-jolla img.round{border-radius:50%}div.quarto-about-jolla img.rounded{border-radius:10px}div.quarto-about-jolla .quarto-title h1.title,div.quarto-about-jolla .quarto-title .title.h1{text-align:center}div.quarto-about-jolla .quarto-title .description{text-align:center}div.quarto-about-jolla h2,div.quarto-about-jolla .h2{border-bottom:none}div.quarto-about-jolla .about-sep{width:60%}div.quarto-about-jolla main{text-align:center}div.quarto-about-jolla .about-links{display:flex}@media(min-width: 992px){div.quarto-about-jolla .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-jolla .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-jolla .about-link{color:#626d78;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-jolla .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-jolla .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-jolla .about-link:hover{color:#2761e3}div.quarto-about-jolla .about-link i.bi{margin-right:.15em}div.quarto-about-solana{display:flex !important;flex-direction:column;padding-top:3em !important;padding-bottom:1em}div.quarto-about-solana .about-entity{display:flex !important;align-items:start;justify-content:space-between}@media(min-width: 992px){div.quarto-about-solana .about-entity{flex-direction:row}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity{flex-direction:column-reverse;align-items:center;text-align:center}}div.quarto-about-solana .about-entity .entity-contents{display:flex;flex-direction:column}@media(max-width: 767.98px){div.quarto-about-solana .about-entity .entity-contents{width:100%}}div.quarto-about-solana .about-entity .about-image{object-fit:cover}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-image{margin-bottom:1.5em}}div.quarto-about-solana .about-entity img.round{border-radius:50%}div.quarto-about-solana .about-entity img.rounded{border-radius:10px}div.quarto-about-solana .about-entity .about-links{display:flex;justify-content:left;padding-bottom:1.2em}@media(min-width: 992px){div.quarto-about-solana .about-entity .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-solana .about-entity .about-link{color:#626d78;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-solana .about-entity .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-solana .about-entity .about-link:hover{color:#2761e3}div.quarto-about-solana .about-entity .about-link i.bi{margin-right:.15em}div.quarto-about-solana .about-contents{padding-right:1.5em;flex-basis:0;flex-grow:1}div.quarto-about-solana .about-contents main.content{margin-top:0}div.quarto-about-solana .about-contents h2,div.quarto-about-solana .about-contents .h2{border-bottom:none}div.quarto-about-trestles{display:flex !important;flex-direction:row;padding-top:3em !important;padding-bottom:1em}@media(max-width: 991.98px){div.quarto-about-trestles{flex-direction:column;padding-top:0em !important}}div.quarto-about-trestles .about-entity{display:flex !important;flex-direction:column;align-items:center;text-align:center;padding-right:1em}@media(min-width: 992px){div.quarto-about-trestles .about-entity{flex:0 0 42%}}div.quarto-about-trestles .about-entity .about-image{object-fit:cover;margin-bottom:1.5em}div.quarto-about-trestles .about-entity img.round{border-radius:50%}div.quarto-about-trestles .about-entity img.rounded{border-radius:10px}div.quarto-about-trestles .about-entity .about-links{display:flex;justify-content:center}@media(min-width: 992px){div.quarto-about-trestles .about-entity .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-trestles .about-entity .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-trestles .about-entity .about-link{color:#626d78;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-trestles .about-entity .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-trestles .about-entity .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-trestles .about-entity .about-link:hover{color:#2761e3}div.quarto-about-trestles .about-entity .about-link i.bi{margin-right:.15em}div.quarto-about-trestles .about-contents{flex-basis:0;flex-grow:1}div.quarto-about-trestles .about-contents h2,div.quarto-about-trestles .about-contents .h2{border-bottom:none}@media(min-width: 992px){div.quarto-about-trestles .about-contents{border-left:solid 1px #dee2e6;padding-left:1.5em}}div.quarto-about-trestles .about-contents main.content{margin-top:0}div.quarto-about-marquee{padding-bottom:1em}div.quarto-about-marquee .about-contents{display:flex;flex-direction:column}div.quarto-about-marquee .about-image{max-height:550px;margin-bottom:1.5em;object-fit:cover}div.quarto-about-marquee img.round{border-radius:50%}div.quarto-about-marquee img.rounded{border-radius:10px}div.quarto-about-marquee h2,div.quarto-about-marquee .h2{border-bottom:none}div.quarto-about-marquee .about-links{display:flex;justify-content:center;padding-top:1.5em}@media(min-width: 992px){div.quarto-about-marquee .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-marquee .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-marquee .about-link{color:#626d78;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-marquee .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-marquee .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-marquee .about-link:hover{color:#2761e3}div.quarto-about-marquee .about-link i.bi{margin-right:.15em}@media(min-width: 992px){div.quarto-about-marquee .about-link{border:none}}div.quarto-about-broadside{display:flex;flex-direction:column;padding-bottom:1em}div.quarto-about-broadside .about-main{display:flex !important;padding-top:0 !important}@media(min-width: 992px){div.quarto-about-broadside .about-main{flex-direction:row;align-items:flex-start}}@media(max-width: 991.98px){div.quarto-about-broadside .about-main{flex-direction:column}}@media(max-width: 991.98px){div.quarto-about-broadside .about-main .about-entity{flex-shrink:0;width:100%;height:450px;margin-bottom:1.5em;background-size:cover;background-repeat:no-repeat}}@media(min-width: 992px){div.quarto-about-broadside .about-main .about-entity{flex:0 10 50%;margin-right:1.5em;width:100%;height:100%;background-size:100%;background-repeat:no-repeat}}div.quarto-about-broadside .about-main .about-contents{padding-top:14px;flex:0 0 50%}div.quarto-about-broadside h2,div.quarto-about-broadside .h2{border-bottom:none}div.quarto-about-broadside .about-sep{margin-top:1.5em;width:60%;align-self:center}div.quarto-about-broadside .about-links{display:flex;justify-content:center;column-gap:20px;padding-top:1.5em}@media(min-width: 992px){div.quarto-about-broadside .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-broadside .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-broadside .about-link{color:#626d78;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-broadside .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-broadside .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-broadside .about-link:hover{color:#2761e3}div.quarto-about-broadside .about-link i.bi{margin-right:.15em}@media(min-width: 992px){div.quarto-about-broadside .about-link{border:none}}.tippy-box[data-theme~=quarto]{background-color:#fff;border:solid 1px #dee2e6;border-radius:.25rem;color:#343a40;font-size:.875rem}.tippy-box[data-theme~=quarto]>.tippy-backdrop{background-color:#fff}.tippy-box[data-theme~=quarto]>.tippy-arrow:after,.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{content:"";position:absolute;z-index:-1}.tippy-box[data-theme~=quarto]>.tippy-arrow:after{border-color:rgba(0,0,0,0);border-style:solid}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-6px}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-6px}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-6px}.tippy-box[data-placement^=left]>.tippy-arrow:before{right:-6px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:before{border-top-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:after{border-top-color:#dee2e6;border-width:7px 7px 0;top:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow>svg{top:16px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow:after{top:17px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#fff;bottom:16px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:after{border-bottom-color:#dee2e6;border-width:0 7px 7px;bottom:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow>svg{bottom:15px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow:after{bottom:17px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:before{border-left-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:after{border-left-color:#dee2e6;border-width:7px 0 7px 7px;left:17px;top:1px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow>svg{left:11px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow:after{left:12px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:before{border-right-color:#fff;right:16px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:after{border-width:7px 7px 7px 0;right:17px;top:1px;border-right-color:#dee2e6}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow>svg{right:11px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow:after{right:12px}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow{fill:#343a40}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCA2czEuNzk2LS4wMTMgNC42Ny0zLjYxNUM1Ljg1MS45IDYuOTMuMDA2IDggMGMxLjA3LS4wMDYgMi4xNDguODg3IDMuMzQzIDIuMzg1QzE0LjIzMyA2LjAwNSAxNiA2IDE2IDZIMHoiIGZpbGw9InJnYmEoMCwgOCwgMTYsIDAuMikiLz48L3N2Zz4=);background-size:16px 6px;width:16px;height:6px}.top-right{position:absolute;top:1em;right:1em}.visually-hidden{border:0;clip:rect(0 0 0 0);height:auto;margin:0;overflow:hidden;padding:0;position:absolute;width:1px;white-space:nowrap}.hidden{display:none !important}.zindex-bottom{z-index:-1 !important}figure.figure{display:block}.quarto-layout-panel{margin-bottom:1em}.quarto-layout-panel>figure{width:100%}.quarto-layout-panel>figure>figcaption,.quarto-layout-panel>.panel-caption{margin-top:10pt}.quarto-layout-panel>.table-caption{margin-top:0px}.table-caption p{margin-bottom:.5em}.quarto-layout-row{display:flex;flex-direction:row;align-items:flex-start}.quarto-layout-valign-top{align-items:flex-start}.quarto-layout-valign-bottom{align-items:flex-end}.quarto-layout-valign-center{align-items:center}.quarto-layout-cell{position:relative;margin-right:20px}.quarto-layout-cell:last-child{margin-right:0}.quarto-layout-cell figure,.quarto-layout-cell>p{margin:.2em}.quarto-layout-cell img{max-width:100%}.quarto-layout-cell .html-widget{width:100% !important}.quarto-layout-cell div figure p{margin:0}.quarto-layout-cell figure{display:block;margin-inline-start:0;margin-inline-end:0}.quarto-layout-cell table{display:inline-table}.quarto-layout-cell-subref figcaption,figure .quarto-layout-row figure figcaption{text-align:center;font-style:italic}.quarto-figure{position:relative;margin-bottom:1em}.quarto-figure>figure{width:100%;margin-bottom:0}.quarto-figure-left>figure>p,.quarto-figure-left>figure>div{text-align:left}.quarto-figure-center>figure>p,.quarto-figure-center>figure>div{text-align:center}.quarto-figure-right>figure>p,.quarto-figure-right>figure>div{text-align:right}.quarto-figure>figure>div.cell-annotation,.quarto-figure>figure>div code{text-align:left}figure>p:empty{display:none}figure>p:first-child{margin-top:0;margin-bottom:0}figure>figcaption.quarto-float-caption-bottom{margin-bottom:.5em}figure>figcaption.quarto-float-caption-top{margin-top:.5em}div[id^=tbl-]{position:relative}.quarto-figure>.anchorjs-link{position:absolute;top:.6em;right:.5em}div[id^=tbl-]>.anchorjs-link{position:absolute;top:.7em;right:.3em}.quarto-figure:hover>.anchorjs-link,div[id^=tbl-]:hover>.anchorjs-link,h2:hover>.anchorjs-link,.h2:hover>.anchorjs-link,h3:hover>.anchorjs-link,.h3:hover>.anchorjs-link,h4:hover>.anchorjs-link,.h4:hover>.anchorjs-link,h5:hover>.anchorjs-link,.h5:hover>.anchorjs-link,h6:hover>.anchorjs-link,.h6:hover>.anchorjs-link,.reveal-anchorjs-link>.anchorjs-link{opacity:1}#title-block-header{margin-block-end:1rem;position:relative;margin-top:-1px}#title-block-header .abstract{margin-block-start:1rem}#title-block-header .abstract .abstract-title{font-weight:600}#title-block-header a{text-decoration:none}#title-block-header .author,#title-block-header .date,#title-block-header .doi{margin-block-end:.2rem}#title-block-header .quarto-title-block>div{display:flex}#title-block-header .quarto-title-block>div>h1,#title-block-header .quarto-title-block>div>.h1{flex-grow:1}#title-block-header .quarto-title-block>div>button{flex-shrink:0;height:2.25rem;margin-top:0}@media(min-width: 992px){#title-block-header .quarto-title-block>div>button{margin-top:5px}}tr.header>th>p:last-of-type{margin-bottom:0px}table,table.table{margin-top:.5rem;margin-bottom:.5rem}caption,.table-caption{padding-top:.5rem;padding-bottom:.5rem;text-align:center}figure.quarto-float-tbl figcaption.quarto-float-caption-top{margin-top:.5rem;margin-bottom:.25rem;text-align:center}figure.quarto-float-tbl figcaption.quarto-float-caption-bottom{padding-top:.25rem;margin-bottom:.5rem;text-align:center}.utterances{max-width:none;margin-left:-8px}iframe{margin-bottom:1em}details{margin-bottom:1em}details[show]{margin-bottom:0}details>summary{color:#6c757d}details>summary>p:only-child{display:inline}pre.sourceCode,code.sourceCode{position:relative}dd code:not(.sourceCode),p code:not(.sourceCode){white-space:pre-wrap}code{white-space:pre}@media print{code{white-space:pre-wrap}}pre>code{display:block}pre>code.sourceCode{white-space:pre}pre>code.sourceCode>span>a:first-child::before{text-decoration:none}pre.code-overflow-wrap>code.sourceCode{white-space:pre-wrap}pre.code-overflow-scroll>code.sourceCode{white-space:pre}code a:any-link{color:inherit;text-decoration:none}code a:hover{color:inherit;text-decoration:underline}ul.task-list{padding-left:1em}[data-tippy-root]{display:inline-block}.tippy-content .footnote-back{display:none}.footnote-back{margin-left:.2em}.tippy-content{overflow-x:auto}.quarto-embedded-source-code{display:none}.quarto-unresolved-ref{font-weight:600}.quarto-cover-image{max-width:35%;float:right;margin-left:30px}.cell-output-display .widget-subarea{margin-bottom:1em}.cell-output-display:not(.no-overflow-x),.knitsql-table:not(.no-overflow-x){overflow-x:auto}.panel-input{margin-bottom:1em}.panel-input>div,.panel-input>div>div{display:inline-block;vertical-align:top;padding-right:12px}.panel-input>p:last-child{margin-bottom:0}.layout-sidebar{margin-bottom:1em}.layout-sidebar .tab-content{border:none}.tab-content>.page-columns.active{display:grid}div.sourceCode>iframe{width:100%;height:300px;margin-bottom:-0.5em}a{text-underline-offset:3px}div.ansi-escaped-output{font-family:monospace;display:block}/*! +* +* ansi colors from IPython notebook's +* +* we also add `bright-[color]-` synonyms for the `-[color]-intense` classes since +* that seems to be what ansi_up emits +* +*/.ansi-black-fg{color:#3e424d}.ansi-black-bg{background-color:#3e424d}.ansi-black-intense-black,.ansi-bright-black-fg{color:#282c36}.ansi-black-intense-black,.ansi-bright-black-bg{background-color:#282c36}.ansi-red-fg{color:#e75c58}.ansi-red-bg{background-color:#e75c58}.ansi-red-intense-red,.ansi-bright-red-fg{color:#b22b31}.ansi-red-intense-red,.ansi-bright-red-bg{background-color:#b22b31}.ansi-green-fg{color:#00a250}.ansi-green-bg{background-color:#00a250}.ansi-green-intense-green,.ansi-bright-green-fg{color:#007427}.ansi-green-intense-green,.ansi-bright-green-bg{background-color:#007427}.ansi-yellow-fg{color:#ddb62b}.ansi-yellow-bg{background-color:#ddb62b}.ansi-yellow-intense-yellow,.ansi-bright-yellow-fg{color:#b27d12}.ansi-yellow-intense-yellow,.ansi-bright-yellow-bg{background-color:#b27d12}.ansi-blue-fg{color:#208ffb}.ansi-blue-bg{background-color:#208ffb}.ansi-blue-intense-blue,.ansi-bright-blue-fg{color:#0065ca}.ansi-blue-intense-blue,.ansi-bright-blue-bg{background-color:#0065ca}.ansi-magenta-fg{color:#d160c4}.ansi-magenta-bg{background-color:#d160c4}.ansi-magenta-intense-magenta,.ansi-bright-magenta-fg{color:#a03196}.ansi-magenta-intense-magenta,.ansi-bright-magenta-bg{background-color:#a03196}.ansi-cyan-fg{color:#60c6c8}.ansi-cyan-bg{background-color:#60c6c8}.ansi-cyan-intense-cyan,.ansi-bright-cyan-fg{color:#258f8f}.ansi-cyan-intense-cyan,.ansi-bright-cyan-bg{background-color:#258f8f}.ansi-white-fg{color:#c5c1b4}.ansi-white-bg{background-color:#c5c1b4}.ansi-white-intense-white,.ansi-bright-white-fg{color:#a1a6b2}.ansi-white-intense-white,.ansi-bright-white-bg{background-color:#a1a6b2}.ansi-default-inverse-fg{color:#fff}.ansi-default-inverse-bg{background-color:#000}.ansi-bold{font-weight:bold}.ansi-underline{text-decoration:underline}:root{--quarto-body-bg: #fff;--quarto-body-color: #343a40;--quarto-text-muted: #6c757d;--quarto-border-color: #dee2e6;--quarto-border-width: 1px;--quarto-border-radius: 0.25rem}table.gt_table{color:var(--quarto-body-color);font-size:1em;width:100%;background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_column_spanner_outer{color:var(--quarto-body-color);background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_col_heading{color:var(--quarto-body-color);font-weight:bold;background-color:rgba(0,0,0,0)}table.gt_table thead.gt_col_headings{border-bottom:1px solid currentColor;border-top-width:inherit;border-top-color:var(--quarto-border-color)}table.gt_table thead.gt_col_headings:not(:first-child){border-top-width:1px;border-top-color:var(--quarto-border-color)}table.gt_table td.gt_row{border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-width:0px}table.gt_table tbody.gt_table_body{border-top-width:1px;border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-color:currentColor}div.columns{display:initial;gap:initial}div.column{display:inline-block;overflow-x:initial;vertical-align:top;width:50%}.code-annotation-tip-content{word-wrap:break-word}.code-annotation-container-hidden{display:none !important}dl.code-annotation-container-grid{display:grid;grid-template-columns:min-content auto}dl.code-annotation-container-grid dt{grid-column:1}dl.code-annotation-container-grid dd{grid-column:2}pre.sourceCode.code-annotation-code{padding-right:0}code.sourceCode .code-annotation-anchor{z-index:100;position:relative;float:right;background-color:rgba(0,0,0,0)}input[type=checkbox]{margin-right:.5ch}:root{--mermaid-bg-color: #fff;--mermaid-edge-color: #343a40;--mermaid-node-fg-color: #343a40;--mermaid-fg-color: #343a40;--mermaid-fg-color--lighter: #4b545c;--mermaid-fg-color--lightest: #626d78;--mermaid-font-family: Source Sans Pro, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;--mermaid-label-bg-color: #fff;--mermaid-label-fg-color: #2780e3;--mermaid-node-bg-color: rgba(39, 128, 227, 0.1);--mermaid-node-fg-color: #343a40}@media print{:root{font-size:11pt}#quarto-sidebar,#TOC,.nav-page{display:none}.page-columns .content{grid-column-start:page-start}.fixed-top{position:relative}.panel-caption,.figure-caption,figcaption{color:#666}}.code-copy-button{position:absolute;top:0;right:0;border:0;margin-top:5px;margin-right:5px;background-color:rgba(0,0,0,0);z-index:3}.code-copy-button:focus{outline:none}.code-copy-button-tooltip{font-size:.75em}pre.sourceCode:hover>.code-copy-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}pre.sourceCode:hover>.code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button-checked:hover>.bi::before{background-image:url('data:image/svg+xml,')}main ol ol,main ul ul,main ol ul,main ul ol{margin-bottom:1em}ul>li:not(:has(>p))>ul,ol>li:not(:has(>p))>ul,ul>li:not(:has(>p))>ol,ol>li:not(:has(>p))>ol{margin-bottom:0}ul>li:not(:has(>p))>ul>li:has(>p),ol>li:not(:has(>p))>ul>li:has(>p),ul>li:not(:has(>p))>ol>li:has(>p),ol>li:not(:has(>p))>ol>li:has(>p){margin-top:1rem}body{margin:0}main.page-columns>header>h1.title,main.page-columns>header>.title.h1{margin-bottom:0}@media(min-width: 992px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start page-start-inset] 25.2px [body-start-outset] 25.2px [body-start] 1rem [body-content-start] minmax(500px, calc(1030px - 2rem)) [body-content-end] 1rem [body-end] 42px [body-end-outset] minmax(90px, 174px) [page-end-inset] 42px [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start page-start-inset] 25.2px [body-start-outset] 25.2px [body-start] 1rem [body-content-start] minmax(500px, calc(1030px - 2rem)) [body-content-end] 1rem [body-end] 42px [body-end-outset] 42px [page-end-inset page-end] 5fr [screen-end-inset] 1rem}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start page-start-inset] 25.2px [body-start-outset] 25.2px [body-start] 1rem [body-content-start] minmax(500px, calc(1030px - 2rem)) [body-content-end] 1rem [body-end] 60px [body-end-outset] minmax(0px, 240px) [page-end-inset] 25.2px [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start] minmax(36px, 72px) [page-start-inset] 36px [body-start-outset] 36px [body-start] 1rem [body-content-start] minmax(500px, calc(1030px - 2rem)) [body-content-end] 2rem [body-end] 36px [body-end-outset] minmax(0px, 300px) [page-end-inset] minmax(36px, 72px) [page-end] 1fr [screen-end-inset] 1rem [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start] 25.2px [page-start-inset] minmax(0px, 126px) [body-start-outset] 25.2px [body-start] 1rem [body-content-start] minmax(450px, calc(980px - 2rem)) [body-content-end] 1rem [body-end] 60px [body-end-outset] minmax(0px, 240px) [page-end-inset] 60px [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start] 25.2px [page-start-inset] minmax(0px, 126px) [body-start-outset] 25.2px [body-start] 1rem [body-content-start] minmax(450px, calc(980px - 2rem)) [body-content-end] 1rem [body-end] 60px [body-end-outset] minmax(0px, 240px) [page-end-inset] 60px [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start] minmax(18px, 36px) [page-start-inset] minmax(36px, 108px) [body-start-outset] minmax(18px, 36px) [body-start] 1rem [body-content-start] minmax(500px, calc(980px - 2rem)) [body-content-end] 1rem [body-end] minmax(30px, 60px) [body-end-outset] minmax(60px, 180px) [page-end-inset] minmax(30px, 60px) [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start] minmax(36px, 72px) [page-start-inset] 36px [body-start-outset] 36px [body-start] 1rem [body-content-start] minmax(500px, calc(1180px - 2rem)) [body-content-end] 1rem [body-end] 60px [body-end-outset] minmax(60px, 120px) [page-end-inset] 60px [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start] minmax(36px, 72px) [page-start-inset] 36px [body-start-outset] 36px [body-start] 1rem [body-content-start] minmax(500px, calc(1180px - 2rem)) [body-content-end] 1rem [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start] 36px [page-start-inset] minmax(36px, 108px) [body-start-outset] 36px [body-start] 1rem [body-content-start] minmax(500px, calc(980px - 2rem)) [body-content-end] 1rem [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start] minmax(36px, 72px) [page-start-inset] 36px [body-start-outset] 36px [body-start] 1rem [body-content-start] minmax(450px, calc(930px - 2rem)) [body-content-end] 1rem [body-end] 60px [body-end-outset] minmax(0px, 240px) [page-end-inset] 60px [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start] minmax(36px, 72px) [page-start-inset] 36px [body-start-outset] 36px [body-start] 1rem [body-content-start] minmax(500px, calc(1180px - 2rem)) [body-content-end] 1rem [body-end] 60px [body-end-outset] minmax(0px, 240px) [page-end-inset] 60px [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start] 36px [page-start-inset] minmax(36px, 108px) [body-start-outset] 36px [body-start] 1rem [body-content-start] minmax(450px, calc(930px - 2rem)) [body-content-end] 1rem [body-end] 60px [body-end-outset] minmax(60px, 180px) [page-end-inset] 60px [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start] minmax(18px, 36px) [page-start-inset] minmax(36px, 108px) [body-start-outset] minmax(18px, 36px) [body-start] 1rem [body-content-start] minmax(500px, calc(980px - 2rem)) [body-content-end] 1rem [body-end] minmax(30px, 60px) [body-end-outset] minmax(60px, 180px) [page-end-inset] minmax(30px, 60px) [page-end] 5fr [screen-end-inset] 1rem [screen-end]}}@media(max-width: 991.98px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1rem [body-content-start] minmax(500px, calc(980px - 2rem)) [body-content-end] 1rem [body-end] 42px [body-end-outset] minmax(90px, 174px) [page-end-inset] 42px [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1rem [body-content-start] minmax(500px, calc(980px - 2rem)) [body-content-end] 1rem [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1rem [body-content-start] minmax(500px, calc(980px - 2rem)) [body-content-end] 1rem [body-end] 42px [body-end-outset] minmax(90px, 174px) [page-end-inset] 42px [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1rem [body-content-start] minmax(500px, calc(1430px - 2rem)) [body-content-end body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1rem [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start] 25.2px [page-start-inset] minmax(0px, 104.4px) [body-start-outset] 25.2px [body-start] 1rem [body-content-start] minmax(450px, calc(980px - 2rem)) [body-content-end] 1rem [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1rem [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start] 25.2px [page-start-inset] minmax(0px, 104.4px) [body-start-outset] 25.2px [body-start] 1rem [body-content-start] minmax(450px, calc(980px - 2rem)) [body-content-end] 1rem [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1rem [body-content-start] minmax(500px, calc(930px - 2rem)) [body-content-end] 1rem [body-end] 60px [body-end-outset] minmax(90px, 180px) [page-end-inset] 30px [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(930px - 2rem)) [body-content-end] 1rem [body-end] 60px [body-end-outset] minmax(30px, 60px) [page-end-inset] 60px [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(1180px - 2rem)) [body-content-end] 1rem [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] .6666666667rem [body-content-start] minmax(500px, calc(980px - 2rem)) [body-content-end] 1rem [body-end body-end-outset page-end-inset page-end] 4fr [screen-end-inset] 1rem [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(930px - 2rem)) [body-content-end] 1rem [body-end] 60px [body-end-outset] minmax(30px, 60px) [page-end-inset] 60px [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(930px - 2rem)) [body-content-end] 1rem [body-end] 60px [body-end-outset] minmax(30px, 60px) [page-end-inset] 60px [page-end] 5fr [screen-end-inset] 1rem [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] .6666666667rem [body-content-start] minmax(500px, calc(930px - 2rem)) [body-content-end] 1rem [body-end] 42px [body-end-outset] minmax(90px, 174px) [page-end-inset] 42px [page-end] 4fr [screen-end-inset] 1rem [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] .6666666667rem [body-content-start] minmax(500px, calc(930px - 2rem)) [body-content-end] 1rem [body-end] 60px [body-end-outset] minmax(90px, 180px) [page-end-inset] 30px [page-end] 4fr [screen-end-inset] 1rem [screen-end]}}@media(max-width: 767.98px){body .page-columns,body.fullcontent:not(.floating):not(.docked) .page-columns,body.slimcontent:not(.floating):not(.docked) .page-columns,body.docked .page-columns,body.docked.slimcontent .page-columns,body.docked.fullcontent .page-columns,body.floating .page-columns,body.floating.slimcontent .page-columns,body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1rem [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1rem [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1rem [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1rem [screen-end]}nav[role=doc-toc]{display:none}}body,.page-row-navigation{grid-template-rows:[page-top] max-content [contents-top] max-content [contents-bottom] max-content [page-bottom]}.page-rows-contents{grid-template-rows:[content-top] minmax(max-content, 1fr) [content-bottom] minmax(60px, max-content) [page-bottom]}.page-full{grid-column:screen-start/screen-end !important}.page-columns>*{grid-column:body-content-start/body-content-end}.page-columns.column-page>*{grid-column:page-start/page-end}.page-columns.column-page-left .page-columns.page-full>*,.page-columns.column-page-left>*{grid-column:page-start/body-content-end}.page-columns.column-page-right .page-columns.page-full>*,.page-columns.column-page-right>*{grid-column:body-content-start/page-end}.page-rows{grid-auto-rows:auto}.header{grid-column:screen-start/screen-end;grid-row:page-top/contents-top}#quarto-content{padding:0;grid-column:screen-start/screen-end;grid-row:contents-top/contents-bottom}body.floating .sidebar.sidebar-navigation{grid-column:page-start/body-start;grid-row:content-top/page-bottom}body.docked .sidebar.sidebar-navigation{grid-column:screen-start/body-start;grid-row:content-top/page-bottom}.sidebar.toc-left{grid-column:page-start/body-start;grid-row:content-top/page-bottom}.sidebar.margin-sidebar{grid-column:body-end/page-end;grid-row:content-top/page-bottom}.page-columns .content{grid-column:body-content-start/body-content-end;grid-row:content-top/content-bottom;align-content:flex-start}.page-columns .page-navigation{grid-column:body-content-start/body-content-end;grid-row:content-bottom/page-bottom}.page-columns .footer{grid-column:screen-start/screen-end;grid-row:contents-bottom/page-bottom}.page-columns .column-body{grid-column:body-content-start/body-content-end}.page-columns .column-body-fullbleed{grid-column:body-start/body-end}.page-columns .column-body-outset{grid-column:body-start-outset/body-end-outset;z-index:998;opacity:.999}.page-columns .column-body-outset table{background:#fff}.page-columns .column-body-outset-left{grid-column:body-start-outset/body-content-end;z-index:998;opacity:.999}.page-columns .column-body-outset-left table{background:#fff}.page-columns .column-body-outset-right{grid-column:body-content-start/body-end-outset;z-index:998;opacity:.999}.page-columns .column-body-outset-right table{background:#fff}.page-columns .column-page{grid-column:page-start/page-end;z-index:998;opacity:.999}.page-columns .column-page table{background:#fff}.page-columns .column-page-inset{grid-column:page-start-inset/page-end-inset;z-index:998;opacity:.999}.page-columns .column-page-inset table{background:#fff}.page-columns .column-page-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-page-inset-left table{background:#fff}.page-columns .column-page-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;opacity:.999}.page-columns .column-page-inset-right figcaption table{background:#fff}.page-columns .column-page-left{grid-column:page-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-page-left table{background:#fff}.page-columns .column-page-right{grid-column:body-content-start/page-end;z-index:998;opacity:.999}.page-columns .column-page-right figcaption table{background:#fff}#quarto-content.page-columns #quarto-margin-sidebar,#quarto-content.page-columns #quarto-sidebar{z-index:1}@media(max-width: 991.98px){#quarto-content.page-columns #quarto-margin-sidebar.collapse,#quarto-content.page-columns #quarto-sidebar.collapse,#quarto-content.page-columns #quarto-margin-sidebar.collapsing,#quarto-content.page-columns #quarto-sidebar.collapsing{z-index:1055}}#quarto-content.page-columns main.column-page,#quarto-content.page-columns main.column-page-right,#quarto-content.page-columns main.column-page-left{z-index:0}.page-columns .column-screen-inset{grid-column:screen-start-inset/screen-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:screen-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/screen-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:screen-start/screen-end;z-index:998;opacity:.999}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:screen-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/screen-end;z-index:998;opacity:.999}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:screen-start/screen-end;padding:1em;background:#f8f9fa;z-index:998;opacity:.999;margin-bottom:1em}.zindex-content{z-index:998;opacity:.999}.zindex-modal{z-index:1055;opacity:.999}.zindex-over-content{z-index:999;opacity:.999}img.img-fluid.column-screen,img.img-fluid.column-screen-inset-shaded,img.img-fluid.column-screen-inset,img.img-fluid.column-screen-inset-left,img.img-fluid.column-screen-inset-right,img.img-fluid.column-screen-left,img.img-fluid.column-screen-right{width:100%}@media(min-width: 992px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-end/page-end !important;z-index:998}.column-sidebar{grid-column:page-start/body-start !important;z-index:998}.column-leftmargin{grid-column:screen-start-inset/body-start !important;z-index:998}.no-row-height{height:1em;overflow:visible}}@media(max-width: 991.98px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-end/page-end !important;z-index:998}.no-row-height{height:1em;overflow:visible}.page-columns.page-full{overflow:visible}.page-columns.toc-left .margin-caption,.page-columns.toc-left div.aside,.page-columns.toc-left aside:not(.footnotes):not(.sidebar),.page-columns.toc-left .column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;opacity:.999}.page-columns.toc-left .no-row-height{height:initial;overflow:initial}}@media(max-width: 767.98px){.margin-caption,div.aside,aside:not(.footnotes):not(.sidebar),.column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;opacity:.999}.no-row-height{height:initial;overflow:initial}#quarto-margin-sidebar{display:none}#quarto-sidebar-toc-left{display:none}.hidden-sm{display:none}}.panel-grid{display:grid;grid-template-rows:repeat(1, 1fr);grid-template-columns:repeat(24, 1fr);gap:1em}.panel-grid .g-col-1{grid-column:auto/span 1}.panel-grid .g-col-2{grid-column:auto/span 2}.panel-grid .g-col-3{grid-column:auto/span 3}.panel-grid .g-col-4{grid-column:auto/span 4}.panel-grid .g-col-5{grid-column:auto/span 5}.panel-grid .g-col-6{grid-column:auto/span 6}.panel-grid .g-col-7{grid-column:auto/span 7}.panel-grid .g-col-8{grid-column:auto/span 8}.panel-grid .g-col-9{grid-column:auto/span 9}.panel-grid .g-col-10{grid-column:auto/span 10}.panel-grid .g-col-11{grid-column:auto/span 11}.panel-grid .g-col-12{grid-column:auto/span 12}.panel-grid .g-col-13{grid-column:auto/span 13}.panel-grid .g-col-14{grid-column:auto/span 14}.panel-grid .g-col-15{grid-column:auto/span 15}.panel-grid .g-col-16{grid-column:auto/span 16}.panel-grid .g-col-17{grid-column:auto/span 17}.panel-grid .g-col-18{grid-column:auto/span 18}.panel-grid .g-col-19{grid-column:auto/span 19}.panel-grid .g-col-20{grid-column:auto/span 20}.panel-grid .g-col-21{grid-column:auto/span 21}.panel-grid .g-col-22{grid-column:auto/span 22}.panel-grid .g-col-23{grid-column:auto/span 23}.panel-grid .g-col-24{grid-column:auto/span 24}.panel-grid .g-start-1{grid-column-start:1}.panel-grid .g-start-2{grid-column-start:2}.panel-grid .g-start-3{grid-column-start:3}.panel-grid .g-start-4{grid-column-start:4}.panel-grid .g-start-5{grid-column-start:5}.panel-grid .g-start-6{grid-column-start:6}.panel-grid .g-start-7{grid-column-start:7}.panel-grid .g-start-8{grid-column-start:8}.panel-grid .g-start-9{grid-column-start:9}.panel-grid .g-start-10{grid-column-start:10}.panel-grid .g-start-11{grid-column-start:11}.panel-grid .g-start-12{grid-column-start:12}.panel-grid .g-start-13{grid-column-start:13}.panel-grid .g-start-14{grid-column-start:14}.panel-grid .g-start-15{grid-column-start:15}.panel-grid .g-start-16{grid-column-start:16}.panel-grid .g-start-17{grid-column-start:17}.panel-grid .g-start-18{grid-column-start:18}.panel-grid .g-start-19{grid-column-start:19}.panel-grid .g-start-20{grid-column-start:20}.panel-grid .g-start-21{grid-column-start:21}.panel-grid .g-start-22{grid-column-start:22}.panel-grid .g-start-23{grid-column-start:23}@media(min-width: 576px){.panel-grid .g-col-sm-1{grid-column:auto/span 1}.panel-grid .g-col-sm-2{grid-column:auto/span 2}.panel-grid .g-col-sm-3{grid-column:auto/span 3}.panel-grid .g-col-sm-4{grid-column:auto/span 4}.panel-grid .g-col-sm-5{grid-column:auto/span 5}.panel-grid .g-col-sm-6{grid-column:auto/span 6}.panel-grid .g-col-sm-7{grid-column:auto/span 7}.panel-grid .g-col-sm-8{grid-column:auto/span 8}.panel-grid .g-col-sm-9{grid-column:auto/span 9}.panel-grid .g-col-sm-10{grid-column:auto/span 10}.panel-grid .g-col-sm-11{grid-column:auto/span 11}.panel-grid .g-col-sm-12{grid-column:auto/span 12}.panel-grid .g-col-sm-13{grid-column:auto/span 13}.panel-grid .g-col-sm-14{grid-column:auto/span 14}.panel-grid .g-col-sm-15{grid-column:auto/span 15}.panel-grid .g-col-sm-16{grid-column:auto/span 16}.panel-grid .g-col-sm-17{grid-column:auto/span 17}.panel-grid .g-col-sm-18{grid-column:auto/span 18}.panel-grid .g-col-sm-19{grid-column:auto/span 19}.panel-grid .g-col-sm-20{grid-column:auto/span 20}.panel-grid .g-col-sm-21{grid-column:auto/span 21}.panel-grid .g-col-sm-22{grid-column:auto/span 22}.panel-grid .g-col-sm-23{grid-column:auto/span 23}.panel-grid .g-col-sm-24{grid-column:auto/span 24}.panel-grid .g-start-sm-1{grid-column-start:1}.panel-grid .g-start-sm-2{grid-column-start:2}.panel-grid .g-start-sm-3{grid-column-start:3}.panel-grid .g-start-sm-4{grid-column-start:4}.panel-grid .g-start-sm-5{grid-column-start:5}.panel-grid .g-start-sm-6{grid-column-start:6}.panel-grid .g-start-sm-7{grid-column-start:7}.panel-grid .g-start-sm-8{grid-column-start:8}.panel-grid .g-start-sm-9{grid-column-start:9}.panel-grid .g-start-sm-10{grid-column-start:10}.panel-grid .g-start-sm-11{grid-column-start:11}.panel-grid .g-start-sm-12{grid-column-start:12}.panel-grid .g-start-sm-13{grid-column-start:13}.panel-grid .g-start-sm-14{grid-column-start:14}.panel-grid .g-start-sm-15{grid-column-start:15}.panel-grid .g-start-sm-16{grid-column-start:16}.panel-grid .g-start-sm-17{grid-column-start:17}.panel-grid .g-start-sm-18{grid-column-start:18}.panel-grid .g-start-sm-19{grid-column-start:19}.panel-grid .g-start-sm-20{grid-column-start:20}.panel-grid .g-start-sm-21{grid-column-start:21}.panel-grid .g-start-sm-22{grid-column-start:22}.panel-grid .g-start-sm-23{grid-column-start:23}}@media(min-width: 768px){.panel-grid .g-col-md-1{grid-column:auto/span 1}.panel-grid .g-col-md-2{grid-column:auto/span 2}.panel-grid .g-col-md-3{grid-column:auto/span 3}.panel-grid .g-col-md-4{grid-column:auto/span 4}.panel-grid .g-col-md-5{grid-column:auto/span 5}.panel-grid .g-col-md-6{grid-column:auto/span 6}.panel-grid .g-col-md-7{grid-column:auto/span 7}.panel-grid .g-col-md-8{grid-column:auto/span 8}.panel-grid .g-col-md-9{grid-column:auto/span 9}.panel-grid .g-col-md-10{grid-column:auto/span 10}.panel-grid .g-col-md-11{grid-column:auto/span 11}.panel-grid .g-col-md-12{grid-column:auto/span 12}.panel-grid .g-col-md-13{grid-column:auto/span 13}.panel-grid .g-col-md-14{grid-column:auto/span 14}.panel-grid .g-col-md-15{grid-column:auto/span 15}.panel-grid .g-col-md-16{grid-column:auto/span 16}.panel-grid .g-col-md-17{grid-column:auto/span 17}.panel-grid .g-col-md-18{grid-column:auto/span 18}.panel-grid .g-col-md-19{grid-column:auto/span 19}.panel-grid .g-col-md-20{grid-column:auto/span 20}.panel-grid .g-col-md-21{grid-column:auto/span 21}.panel-grid .g-col-md-22{grid-column:auto/span 22}.panel-grid .g-col-md-23{grid-column:auto/span 23}.panel-grid .g-col-md-24{grid-column:auto/span 24}.panel-grid .g-start-md-1{grid-column-start:1}.panel-grid .g-start-md-2{grid-column-start:2}.panel-grid .g-start-md-3{grid-column-start:3}.panel-grid .g-start-md-4{grid-column-start:4}.panel-grid .g-start-md-5{grid-column-start:5}.panel-grid .g-start-md-6{grid-column-start:6}.panel-grid .g-start-md-7{grid-column-start:7}.panel-grid .g-start-md-8{grid-column-start:8}.panel-grid .g-start-md-9{grid-column-start:9}.panel-grid .g-start-md-10{grid-column-start:10}.panel-grid .g-start-md-11{grid-column-start:11}.panel-grid .g-start-md-12{grid-column-start:12}.panel-grid .g-start-md-13{grid-column-start:13}.panel-grid .g-start-md-14{grid-column-start:14}.panel-grid .g-start-md-15{grid-column-start:15}.panel-grid .g-start-md-16{grid-column-start:16}.panel-grid .g-start-md-17{grid-column-start:17}.panel-grid .g-start-md-18{grid-column-start:18}.panel-grid .g-start-md-19{grid-column-start:19}.panel-grid .g-start-md-20{grid-column-start:20}.panel-grid .g-start-md-21{grid-column-start:21}.panel-grid .g-start-md-22{grid-column-start:22}.panel-grid .g-start-md-23{grid-column-start:23}}@media(min-width: 992px){.panel-grid .g-col-lg-1{grid-column:auto/span 1}.panel-grid .g-col-lg-2{grid-column:auto/span 2}.panel-grid .g-col-lg-3{grid-column:auto/span 3}.panel-grid .g-col-lg-4{grid-column:auto/span 4}.panel-grid .g-col-lg-5{grid-column:auto/span 5}.panel-grid .g-col-lg-6{grid-column:auto/span 6}.panel-grid .g-col-lg-7{grid-column:auto/span 7}.panel-grid .g-col-lg-8{grid-column:auto/span 8}.panel-grid .g-col-lg-9{grid-column:auto/span 9}.panel-grid .g-col-lg-10{grid-column:auto/span 10}.panel-grid .g-col-lg-11{grid-column:auto/span 11}.panel-grid .g-col-lg-12{grid-column:auto/span 12}.panel-grid .g-col-lg-13{grid-column:auto/span 13}.panel-grid .g-col-lg-14{grid-column:auto/span 14}.panel-grid .g-col-lg-15{grid-column:auto/span 15}.panel-grid .g-col-lg-16{grid-column:auto/span 16}.panel-grid .g-col-lg-17{grid-column:auto/span 17}.panel-grid .g-col-lg-18{grid-column:auto/span 18}.panel-grid .g-col-lg-19{grid-column:auto/span 19}.panel-grid .g-col-lg-20{grid-column:auto/span 20}.panel-grid .g-col-lg-21{grid-column:auto/span 21}.panel-grid .g-col-lg-22{grid-column:auto/span 22}.panel-grid .g-col-lg-23{grid-column:auto/span 23}.panel-grid .g-col-lg-24{grid-column:auto/span 24}.panel-grid .g-start-lg-1{grid-column-start:1}.panel-grid .g-start-lg-2{grid-column-start:2}.panel-grid .g-start-lg-3{grid-column-start:3}.panel-grid .g-start-lg-4{grid-column-start:4}.panel-grid .g-start-lg-5{grid-column-start:5}.panel-grid .g-start-lg-6{grid-column-start:6}.panel-grid .g-start-lg-7{grid-column-start:7}.panel-grid .g-start-lg-8{grid-column-start:8}.panel-grid .g-start-lg-9{grid-column-start:9}.panel-grid .g-start-lg-10{grid-column-start:10}.panel-grid .g-start-lg-11{grid-column-start:11}.panel-grid .g-start-lg-12{grid-column-start:12}.panel-grid .g-start-lg-13{grid-column-start:13}.panel-grid .g-start-lg-14{grid-column-start:14}.panel-grid .g-start-lg-15{grid-column-start:15}.panel-grid .g-start-lg-16{grid-column-start:16}.panel-grid .g-start-lg-17{grid-column-start:17}.panel-grid .g-start-lg-18{grid-column-start:18}.panel-grid .g-start-lg-19{grid-column-start:19}.panel-grid .g-start-lg-20{grid-column-start:20}.panel-grid .g-start-lg-21{grid-column-start:21}.panel-grid .g-start-lg-22{grid-column-start:22}.panel-grid .g-start-lg-23{grid-column-start:23}}@media(min-width: 1200px){.panel-grid .g-col-xl-1{grid-column:auto/span 1}.panel-grid .g-col-xl-2{grid-column:auto/span 2}.panel-grid .g-col-xl-3{grid-column:auto/span 3}.panel-grid .g-col-xl-4{grid-column:auto/span 4}.panel-grid .g-col-xl-5{grid-column:auto/span 5}.panel-grid .g-col-xl-6{grid-column:auto/span 6}.panel-grid .g-col-xl-7{grid-column:auto/span 7}.panel-grid .g-col-xl-8{grid-column:auto/span 8}.panel-grid .g-col-xl-9{grid-column:auto/span 9}.panel-grid .g-col-xl-10{grid-column:auto/span 10}.panel-grid .g-col-xl-11{grid-column:auto/span 11}.panel-grid .g-col-xl-12{grid-column:auto/span 12}.panel-grid .g-col-xl-13{grid-column:auto/span 13}.panel-grid .g-col-xl-14{grid-column:auto/span 14}.panel-grid .g-col-xl-15{grid-column:auto/span 15}.panel-grid .g-col-xl-16{grid-column:auto/span 16}.panel-grid .g-col-xl-17{grid-column:auto/span 17}.panel-grid .g-col-xl-18{grid-column:auto/span 18}.panel-grid .g-col-xl-19{grid-column:auto/span 19}.panel-grid .g-col-xl-20{grid-column:auto/span 20}.panel-grid .g-col-xl-21{grid-column:auto/span 21}.panel-grid .g-col-xl-22{grid-column:auto/span 22}.panel-grid .g-col-xl-23{grid-column:auto/span 23}.panel-grid .g-col-xl-24{grid-column:auto/span 24}.panel-grid .g-start-xl-1{grid-column-start:1}.panel-grid .g-start-xl-2{grid-column-start:2}.panel-grid .g-start-xl-3{grid-column-start:3}.panel-grid .g-start-xl-4{grid-column-start:4}.panel-grid .g-start-xl-5{grid-column-start:5}.panel-grid .g-start-xl-6{grid-column-start:6}.panel-grid .g-start-xl-7{grid-column-start:7}.panel-grid .g-start-xl-8{grid-column-start:8}.panel-grid .g-start-xl-9{grid-column-start:9}.panel-grid .g-start-xl-10{grid-column-start:10}.panel-grid .g-start-xl-11{grid-column-start:11}.panel-grid .g-start-xl-12{grid-column-start:12}.panel-grid .g-start-xl-13{grid-column-start:13}.panel-grid .g-start-xl-14{grid-column-start:14}.panel-grid .g-start-xl-15{grid-column-start:15}.panel-grid .g-start-xl-16{grid-column-start:16}.panel-grid .g-start-xl-17{grid-column-start:17}.panel-grid .g-start-xl-18{grid-column-start:18}.panel-grid .g-start-xl-19{grid-column-start:19}.panel-grid .g-start-xl-20{grid-column-start:20}.panel-grid .g-start-xl-21{grid-column-start:21}.panel-grid .g-start-xl-22{grid-column-start:22}.panel-grid .g-start-xl-23{grid-column-start:23}}@media(min-width: 1400px){.panel-grid .g-col-xxl-1{grid-column:auto/span 1}.panel-grid .g-col-xxl-2{grid-column:auto/span 2}.panel-grid .g-col-xxl-3{grid-column:auto/span 3}.panel-grid .g-col-xxl-4{grid-column:auto/span 4}.panel-grid .g-col-xxl-5{grid-column:auto/span 5}.panel-grid .g-col-xxl-6{grid-column:auto/span 6}.panel-grid .g-col-xxl-7{grid-column:auto/span 7}.panel-grid .g-col-xxl-8{grid-column:auto/span 8}.panel-grid .g-col-xxl-9{grid-column:auto/span 9}.panel-grid .g-col-xxl-10{grid-column:auto/span 10}.panel-grid .g-col-xxl-11{grid-column:auto/span 11}.panel-grid .g-col-xxl-12{grid-column:auto/span 12}.panel-grid .g-col-xxl-13{grid-column:auto/span 13}.panel-grid .g-col-xxl-14{grid-column:auto/span 14}.panel-grid .g-col-xxl-15{grid-column:auto/span 15}.panel-grid .g-col-xxl-16{grid-column:auto/span 16}.panel-grid .g-col-xxl-17{grid-column:auto/span 17}.panel-grid .g-col-xxl-18{grid-column:auto/span 18}.panel-grid .g-col-xxl-19{grid-column:auto/span 19}.panel-grid .g-col-xxl-20{grid-column:auto/span 20}.panel-grid .g-col-xxl-21{grid-column:auto/span 21}.panel-grid .g-col-xxl-22{grid-column:auto/span 22}.panel-grid .g-col-xxl-23{grid-column:auto/span 23}.panel-grid .g-col-xxl-24{grid-column:auto/span 24}.panel-grid .g-start-xxl-1{grid-column-start:1}.panel-grid .g-start-xxl-2{grid-column-start:2}.panel-grid .g-start-xxl-3{grid-column-start:3}.panel-grid .g-start-xxl-4{grid-column-start:4}.panel-grid .g-start-xxl-5{grid-column-start:5}.panel-grid .g-start-xxl-6{grid-column-start:6}.panel-grid .g-start-xxl-7{grid-column-start:7}.panel-grid .g-start-xxl-8{grid-column-start:8}.panel-grid .g-start-xxl-9{grid-column-start:9}.panel-grid .g-start-xxl-10{grid-column-start:10}.panel-grid .g-start-xxl-11{grid-column-start:11}.panel-grid .g-start-xxl-12{grid-column-start:12}.panel-grid .g-start-xxl-13{grid-column-start:13}.panel-grid .g-start-xxl-14{grid-column-start:14}.panel-grid .g-start-xxl-15{grid-column-start:15}.panel-grid .g-start-xxl-16{grid-column-start:16}.panel-grid .g-start-xxl-17{grid-column-start:17}.panel-grid .g-start-xxl-18{grid-column-start:18}.panel-grid .g-start-xxl-19{grid-column-start:19}.panel-grid .g-start-xxl-20{grid-column-start:20}.panel-grid .g-start-xxl-21{grid-column-start:21}.panel-grid .g-start-xxl-22{grid-column-start:22}.panel-grid .g-start-xxl-23{grid-column-start:23}}main{margin-top:1em;margin-bottom:1em}h1,.h1,h2,.h2{color:inherit;margin-top:2rem;margin-bottom:1rem;font-weight:600}h1.title,.title.h1{margin-top:0}main.content>section:first-of-type>h2:first-child,main.content>section:first-of-type>.h2:first-child{margin-top:0}h2,.h2{border-bottom:1px solid #dee2e6;padding-bottom:.5rem}h3,.h3{font-weight:600}h3,.h3,h4,.h4{opacity:.9;margin-top:1.5rem}h5,.h5,h6,.h6{opacity:.9}.header-section-number{color:#6d7a86}.nav-link.active .header-section-number{color:inherit}mark,.mark{padding:0em}.panel-caption,.figure-caption,.subfigure-caption,.table-caption,figcaption,caption{font-size:.9rem;color:#6d7a86}.quarto-layout-cell[data-ref-parent] caption{color:#6d7a86}.column-margin figcaption,.margin-caption,div.aside,aside,.column-margin{color:#6d7a86;font-size:.825rem}.panel-caption.margin-caption{text-align:inherit}.column-margin.column-container p{margin-bottom:0}.column-margin.column-container>*:not(.collapse):first-child{padding-bottom:.5em;display:block}.column-margin.column-container>*:not(.collapse):not(:first-child){padding-top:.5em;padding-bottom:.5em;display:block}.column-margin.column-container>*.collapse:not(.show){display:none}@media(min-width: 768px){.column-margin.column-container .callout-margin-content:first-child{margin-top:4.5em}.column-margin.column-container .callout-margin-content-simple:first-child{margin-top:3.5em}}.margin-caption>*{padding-top:.5em;padding-bottom:.5em}@media(max-width: 767.98px){.quarto-layout-row{flex-direction:column}}.nav-tabs .nav-item{margin-top:1px;cursor:pointer}.tab-content{margin-top:0px;border-left:#dee2e6 1px solid;border-right:#dee2e6 1px solid;border-bottom:#dee2e6 1px solid;margin-left:0;padding:1em;margin-bottom:1em}@media(max-width: 767.98px){.layout-sidebar{margin-left:0;margin-right:0}}.panel-sidebar,.panel-sidebar .form-control,.panel-input,.panel-input .form-control,.selectize-dropdown{font-size:.9rem}.panel-sidebar .form-control,.panel-input .form-control{padding-top:.1rem}.tab-pane div.sourceCode{margin-top:0px}.tab-pane>p{padding-top:0}.tab-pane>p:nth-child(1){padding-top:0}.tab-pane>p:last-child{margin-bottom:0}.tab-pane>pre:last-child{margin-bottom:0}.tab-content>.tab-pane:not(.active){display:none !important}div.sourceCode{background-color:rgba(233,236,239,.65);border:1px solid rgba(233,236,239,.65);border-radius:.25rem}pre.sourceCode{background-color:rgba(0,0,0,0)}pre.sourceCode{border-left:3px;border-left-style:solid;border-left-color:#31bae9;padding-left:.6em;border-right:none;border-top:none;border-bottom:none;font-size:.875em;overflow:visible !important;padding:.4em}.callout pre.sourceCode{padding-left:0}div.sourceCode{overflow-y:hidden}.callout div.sourceCode{margin-left:initial}.blockquote{font-size:inherit;padding-left:1rem;padding-right:1.5rem;color:#6d7a86}.blockquote h1:first-child,.blockquote .h1:first-child,.blockquote h2:first-child,.blockquote .h2:first-child,.blockquote h3:first-child,.blockquote .h3:first-child,.blockquote h4:first-child,.blockquote .h4:first-child,.blockquote h5:first-child,.blockquote .h5:first-child{margin-top:0}pre{background-color:initial;padding:initial;border:initial}p pre code:not(.sourceCode),li pre code:not(.sourceCode),pre code:not(.sourceCode){background-color:initial}p code:not(.sourceCode),li code:not(.sourceCode),td code:not(.sourceCode){background-color:#f8f9fa;padding:.2em}nav p code:not(.sourceCode),nav li code:not(.sourceCode),nav td code:not(.sourceCode){background-color:rgba(0,0,0,0);padding:0}td code:not(.sourceCode){white-space:pre-wrap}#quarto-embedded-source-code-modal>.modal-dialog{max-width:1000px;padding-left:1.75rem;padding-right:1.75rem}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body{padding:0}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body div.sourceCode{margin:0;padding:.2rem .2rem;border-radius:0px;border:none}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-header{padding:.7rem}.code-tools-button{font-size:1rem;padding:.15rem .15rem;margin-left:5px;color:#6c757d;background-color:rgba(0,0,0,0);transition:initial;cursor:pointer}.code-tools-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}.code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}.sidebar{will-change:top;transition:top 200ms linear;position:sticky;overflow-y:auto;padding-top:1.2em;max-height:100vh}.sidebar.toc-left,.sidebar.margin-sidebar{top:0px;padding-top:1em}.sidebar.quarto-banner-title-block-sidebar>*{padding-top:1.65em}figure .quarto-notebook-link{margin-top:.5em}.quarto-notebook-link{font-size:.75em;color:#6c757d;margin-bottom:1em;text-decoration:none;display:block}.quarto-notebook-link:hover{text-decoration:underline;color:#2761e3}.quarto-notebook-link::before{display:inline-block;height:.75rem;width:.75rem;margin-bottom:0em;margin-right:.25em;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:.75rem .75rem}.toc-actions i.bi,.quarto-code-links i.bi,.quarto-other-links i.bi,.quarto-alternate-notebooks i.bi,.quarto-alternate-formats i.bi{margin-right:.4em;font-size:.8rem}.quarto-other-links-text-target .quarto-code-links i.bi,.quarto-other-links-text-target .quarto-other-links i.bi{margin-right:.2em}.quarto-other-formats-text-target .quarto-alternate-formats i.bi{margin-right:.1em}.toc-actions i.bi.empty,.quarto-code-links i.bi.empty,.quarto-other-links i.bi.empty,.quarto-alternate-notebooks i.bi.empty,.quarto-alternate-formats i.bi.empty{padding-left:1em}.quarto-notebook h2,.quarto-notebook .h2{border-bottom:none}.quarto-notebook .cell-container{display:flex}.quarto-notebook .cell-container .cell{flex-grow:4}.quarto-notebook .cell-container .cell-decorator{padding-top:1.5em;padding-right:1em;text-align:right}.quarto-notebook .cell-container.code-fold .cell-decorator{padding-top:3em}.quarto-notebook .cell-code code{white-space:pre-wrap}.quarto-notebook .cell .cell-output-stderr pre code,.quarto-notebook .cell .cell-output-stdout pre code{white-space:pre-wrap;overflow-wrap:anywhere}.toc-actions,.quarto-alternate-formats,.quarto-other-links,.quarto-code-links,.quarto-alternate-notebooks{padding-left:0em}.sidebar .toc-actions a,.sidebar .quarto-alternate-formats a,.sidebar .quarto-other-links a,.sidebar .quarto-code-links a,.sidebar .quarto-alternate-notebooks a,.sidebar nav[role=doc-toc] a{text-decoration:none}.sidebar .toc-actions a:hover,.sidebar .quarto-other-links a:hover,.sidebar .quarto-code-links a:hover,.sidebar .quarto-alternate-formats a:hover,.sidebar .quarto-alternate-notebooks a:hover{color:#2761e3}.sidebar .toc-actions h2,.sidebar .toc-actions .h2,.sidebar .quarto-code-links h2,.sidebar .quarto-code-links .h2,.sidebar .quarto-other-links h2,.sidebar .quarto-other-links .h2,.sidebar .quarto-alternate-notebooks h2,.sidebar .quarto-alternate-notebooks .h2,.sidebar .quarto-alternate-formats h2,.sidebar .quarto-alternate-formats .h2,.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-weight:500;margin-bottom:.2rem;margin-top:.3rem;font-family:inherit;border-bottom:0;padding-bottom:0;padding-top:0px}.sidebar .toc-actions>h2,.sidebar .toc-actions>.h2,.sidebar .quarto-code-links>h2,.sidebar .quarto-code-links>.h2,.sidebar .quarto-other-links>h2,.sidebar .quarto-other-links>.h2,.sidebar .quarto-alternate-notebooks>h2,.sidebar .quarto-alternate-notebooks>.h2,.sidebar .quarto-alternate-formats>h2,.sidebar .quarto-alternate-formats>.h2{font-size:.8rem}.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-size:.875rem}.sidebar nav[role=doc-toc]>ul a{border-left:1px solid #e9ecef;padding-left:.6rem}.sidebar .toc-actions h2>ul a,.sidebar .toc-actions .h2>ul a,.sidebar .quarto-code-links h2>ul a,.sidebar .quarto-code-links .h2>ul a,.sidebar .quarto-other-links h2>ul a,.sidebar .quarto-other-links .h2>ul a,.sidebar .quarto-alternate-notebooks h2>ul a,.sidebar .quarto-alternate-notebooks .h2>ul a,.sidebar .quarto-alternate-formats h2>ul a,.sidebar .quarto-alternate-formats .h2>ul a{border-left:none;padding-left:.6rem}.sidebar .toc-actions ul a:empty,.sidebar .quarto-code-links ul a:empty,.sidebar .quarto-other-links ul a:empty,.sidebar .quarto-alternate-notebooks ul a:empty,.sidebar .quarto-alternate-formats ul a:empty,.sidebar nav[role=doc-toc]>ul a:empty{display:none}.sidebar .toc-actions ul,.sidebar .quarto-code-links ul,.sidebar .quarto-other-links ul,.sidebar .quarto-alternate-notebooks ul,.sidebar .quarto-alternate-formats ul{padding-left:0;list-style:none}.sidebar nav[role=doc-toc] ul{list-style:none;padding-left:0;list-style:none}.sidebar nav[role=doc-toc]>ul{margin-left:.45em}.quarto-margin-sidebar nav[role=doc-toc]{padding-left:.5em}.sidebar .toc-actions>ul,.sidebar .quarto-code-links>ul,.sidebar .quarto-other-links>ul,.sidebar .quarto-alternate-notebooks>ul,.sidebar .quarto-alternate-formats>ul{font-size:.8rem}.sidebar nav[role=doc-toc]>ul{font-size:.875rem}.sidebar .toc-actions ul li a,.sidebar .quarto-code-links ul li a,.sidebar .quarto-other-links ul li a,.sidebar .quarto-alternate-notebooks ul li a,.sidebar .quarto-alternate-formats ul li a,.sidebar nav[role=doc-toc]>ul li a{line-height:1.1rem;padding-bottom:.2rem;padding-top:.2rem;color:inherit}.sidebar nav[role=doc-toc] ul>li>ul>li>a{padding-left:1.2em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>a{padding-left:2.4em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>a{padding-left:3.6em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:4.8em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:6em}.sidebar nav[role=doc-toc] ul>li>a.active,.sidebar nav[role=doc-toc] ul>li>ul>li>a.active{border-left:1px solid #2761e3;color:#2761e3 !important}.sidebar nav[role=doc-toc] ul>li>a:hover,.sidebar nav[role=doc-toc] ul>li>ul>li>a:hover{color:#2761e3 !important}kbd,.kbd{color:#343a40;background-color:#f8f9fa;border:1px solid;border-radius:5px;border-color:#dee2e6}.quarto-appendix-contents div.hanging-indent{margin-left:0em}.quarto-appendix-contents div.hanging-indent div.csl-entry{margin-left:1em;text-indent:-1em}.citation a,.footnote-ref{text-decoration:none}.footnotes ol{padding-left:1em}.tippy-content>*{margin-bottom:.7em}.tippy-content>*:last-child{margin-bottom:0}@media(min-width: 992px){.callout:not(.no-icon){margin-left:calc(calc(-0.4em + -5px) + -1px)}.callout{margin-left:calc(-0.4em + -5px)}div.sourceCode{margin-left:calc(calc(-0.6em + -3px) + 2px)}}.callout{margin-top:1.25rem;margin-bottom:1.25rem;border-radius:.25rem;overflow-wrap:break-word}.callout .callout-title-container{overflow-wrap:anywhere}.callout.callout-style-simple{padding:.4em .7em;border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout.callout-style-default{border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout .callout-body-container{flex-grow:1}.callout.callout-style-simple .callout-body{font-size:.9rem;font-weight:400}.callout.callout-style-default .callout-body{font-size:.9rem;font-weight:400}.callout:not(.no-icon).callout-titled.callout-style-simple .callout-body{padding-left:1.6em}.callout.callout-titled>.callout-header{padding-top:.2em;margin-bottom:-0.2em}.callout.callout-style-simple>div.callout-header{border-bottom:none;font-size:.9rem;font-weight:600;opacity:75%}.callout.callout-style-default>div.callout-header{border-bottom:none;font-weight:600;opacity:85%;font-size:.9rem;padding-left:.5em;padding-right:.5em}.callout.callout-style-default .callout-body{padding-left:.5em;padding-right:.5em}.callout.callout-style-default .callout-body>:first-child{padding-top:.5rem;margin-top:0}.callout>div.callout-header[data-bs-toggle=collapse]{cursor:pointer}.callout.callout-style-default .callout-header[aria-expanded=false],.callout.callout-style-default .callout-header[aria-expanded=true]{padding-top:0px;margin-bottom:0px;align-items:center}.callout.callout-titled .callout-body>:last-child:not(.sourceCode),.callout.callout-titled .callout-body>div>:last-child:not(.sourceCode){padding-bottom:.5rem;margin-bottom:0}.callout:not(.callout-titled) .callout-body>:first-child,.callout:not(.callout-titled) .callout-body>div>:first-child{margin-top:.25rem}.callout:not(.callout-titled) .callout-body>:last-child,.callout:not(.callout-titled) .callout-body>div>:last-child{margin-bottom:.2rem}.callout.callout-style-simple .callout-icon::before,.callout.callout-style-simple .callout-toggle::before{height:1rem;width:1rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.callout.callout-style-default .callout-icon::before,.callout.callout-style-default .callout-toggle::before{height:.9rem;width:.9rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:.9rem .9rem}.callout.callout-style-default .callout-toggle::before{margin-top:5px}.callout .callout-btn-toggle .callout-toggle::before{transition:transform .2s linear}.callout .callout-header[aria-expanded=false] .callout-toggle::before{transform:rotate(-90deg)}.callout .callout-header[aria-expanded=true] .callout-toggle::before{transform:none}.callout.callout-style-simple:not(.no-icon) div.callout-icon-container{padding-top:.2em;padding-right:.55em}.callout.callout-style-default:not(.no-icon) div.callout-icon-container{padding-top:.1em;padding-right:.35em}.callout.callout-style-default:not(.no-icon) div.callout-title-container{margin-top:-1px}.callout.callout-style-default.callout-caution:not(.no-icon) div.callout-icon-container{padding-top:.3em;padding-right:.35em}.callout>.callout-body>.callout-icon-container>.no-icon,.callout>.callout-header>.callout-icon-container>.no-icon{display:none}div.callout.callout{border-left-color:#6c757d}div.callout.callout-style-default>.callout-header{background-color:#6c757d}div.callout-note.callout{border-left-color:#2780e3}div.callout-note.callout-style-default>.callout-header{background-color:#e9f2fc}div.callout-note:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-tip.callout{border-left-color:#3fb618}div.callout-tip.callout-style-default>.callout-header{background-color:#ecf8e8}div.callout-tip:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-warning.callout{border-left-color:#ff7518}div.callout-warning.callout-style-default>.callout-header{background-color:#fff1e8}div.callout-warning:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-caution.callout{border-left-color:#f0ad4e}div.callout-caution.callout-style-default>.callout-header{background-color:#fef7ed}div.callout-caution:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-important.callout{border-left-color:#ff0039}div.callout-important.callout-style-default>.callout-header{background-color:#ffe6eb}div.callout-important:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important .callout-toggle::before{background-image:url('data:image/svg+xml,')}.quarto-toggle-container{display:flex;align-items:center}.quarto-reader-toggle .bi::before,.quarto-color-scheme-toggle .bi::before{display:inline-block;height:1rem;width:1rem;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.sidebar-navigation{padding-left:20px}.navbar{background-color:#2780e3;color:#fdfeff}.navbar .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.quarto-sidebar-toggle{border-color:#dee2e6;border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem;border-style:solid;border-width:1px;overflow:hidden;border-top-width:0px;padding-top:0px !important}.quarto-sidebar-toggle-title{cursor:pointer;padding-bottom:2px;margin-left:.25em;text-align:center;font-weight:400;font-size:.775em}#quarto-content .quarto-sidebar-toggle{background:#fafafa}#quarto-content .quarto-sidebar-toggle-title{color:#343a40}.quarto-sidebar-toggle-icon{color:#dee2e6;margin-right:.5em;float:right;transition:transform .2s ease}.quarto-sidebar-toggle-icon::before{padding-top:5px}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-icon{transform:rotate(-180deg)}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-title{border-bottom:solid #dee2e6 1px}.quarto-sidebar-toggle-contents{background-color:#fff;padding-right:10px;padding-left:10px;margin-top:0px !important;transition:max-height .5s ease}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-contents{padding-top:1em;padding-bottom:10px}@media(max-width: 767.98px){.sidebar-menu-container{padding-bottom:5em}}.quarto-sidebar-toggle:not(.expanded) .quarto-sidebar-toggle-contents{padding-top:0px !important;padding-bottom:0px}nav[role=doc-toc]{z-index:1020}#quarto-sidebar>*,nav[role=doc-toc]>*{transition:opacity .1s ease,border .1s ease}#quarto-sidebar.slow>*,nav[role=doc-toc].slow>*{transition:opacity .4s ease,border .4s ease}.quarto-color-scheme-toggle:not(.alternate).top-right .bi::before{background-image:url('data:image/svg+xml,')}.quarto-color-scheme-toggle.alternate.top-right .bi::before{background-image:url('data:image/svg+xml,')}#quarto-appendix.default{border-top:1px solid #dee2e6}#quarto-appendix.default{background-color:#fff;padding-top:1.5em;margin-top:2em;z-index:998}#quarto-appendix.default .quarto-appendix-heading{margin-top:0;line-height:1.4em;font-weight:600;opacity:.9;border-bottom:none;margin-bottom:0}#quarto-appendix.default .footnotes ol,#quarto-appendix.default .footnotes ol li>p:last-of-type,#quarto-appendix.default .quarto-appendix-contents>p:last-of-type{margin-bottom:0}#quarto-appendix.default .footnotes ol{margin-left:.5em}#quarto-appendix.default .quarto-appendix-secondary-label{margin-bottom:.4em}#quarto-appendix.default .quarto-appendix-bibtex{font-size:.7em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-bibtex code.sourceCode{white-space:pre-wrap}#quarto-appendix.default .quarto-appendix-citeas{font-size:.9em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-heading{font-size:1em !important}#quarto-appendix.default *[role=doc-endnotes]>ol,#quarto-appendix.default .quarto-appendix-contents>*:not(h2):not(.h2){font-size:.9em}#quarto-appendix.default section{padding-bottom:1.5em}#quarto-appendix.default section *[role=doc-endnotes],#quarto-appendix.default section>*:not(a){opacity:.9;word-wrap:break-word}.btn.btn-quarto,div.cell-output-display .btn-quarto{--bs-btn-color: #cacccd;--bs-btn-bg: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #cacccd;--bs-btn-hover-bg: #52585d;--bs-btn-hover-border-color: #484e53;--bs-btn-focus-shadow-rgb: 75, 80, 85;--bs-btn-active-color: #fff;--bs-btn-active-bg: #5d6166;--bs-btn-active-border-color: #484e53;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #343a40;--bs-btn-disabled-border-color: #343a40}nav.quarto-secondary-nav.color-navbar{background-color:#2780e3;color:#fdfeff}nav.quarto-secondary-nav.color-navbar h1,nav.quarto-secondary-nav.color-navbar .h1,nav.quarto-secondary-nav.color-navbar .quarto-btn-toggle{color:#fdfeff}@media(max-width: 991.98px){body.nav-sidebar .quarto-title-banner{margin-bottom:0;padding-bottom:1em}body.nav-sidebar #title-block-header{margin-block-end:0}}p.subtitle{margin-top:.25em;margin-bottom:.5em}code a:any-link{color:inherit;text-decoration-color:#6c757d}/*! light */div.observablehq table thead tr th{background-color:var(--bs-body-bg)}input,button,select,optgroup,textarea{background-color:var(--bs-body-bg)}.code-annotated .code-copy-button{margin-right:1.25em;margin-top:0;padding-bottom:0;padding-top:3px}.code-annotation-gutter-bg{background-color:#fff}.code-annotation-gutter{background-color:rgba(233,236,239,.65)}.code-annotation-gutter,.code-annotation-gutter-bg{height:100%;width:calc(20px + .5em);position:absolute;top:0;right:0}dl.code-annotation-container-grid dt{margin-right:1em;margin-top:.25rem}dl.code-annotation-container-grid dt{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;color:#4b545c;border:solid #4b545c 1px;border-radius:50%;height:22px;width:22px;line-height:22px;font-size:11px;text-align:center;vertical-align:middle;text-decoration:none}dl.code-annotation-container-grid dt[data-target-cell]{cursor:pointer}dl.code-annotation-container-grid dt[data-target-cell].code-annotation-active{color:#fff;border:solid #aaa 1px;background-color:#aaa}pre.code-annotation-code{padding-top:0;padding-bottom:0}pre.code-annotation-code code{z-index:3}#code-annotation-line-highlight-gutter{width:100%;border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}#code-annotation-line-highlight{margin-left:-4em;width:calc(100% + 4em);border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}code.sourceCode .code-annotation-anchor.code-annotation-active{background-color:var(--quarto-hl-normal-color, #aaaaaa);border:solid var(--quarto-hl-normal-color, #aaaaaa) 1px;color:#e9ecef;font-weight:bolder}code.sourceCode .code-annotation-anchor{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;color:var(--quarto-hl-co-color);border:solid var(--quarto-hl-co-color) 1px;border-radius:50%;height:18px;width:18px;font-size:9px;margin-top:2px}code.sourceCode button.code-annotation-anchor{padding:2px;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none}code.sourceCode a.code-annotation-anchor{line-height:18px;text-align:center;vertical-align:middle;cursor:default;text-decoration:none}@media print{.page-columns .column-screen-inset{grid-column:page-start-inset/page-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;opacity:.999}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:page-start/page-end;z-index:998;opacity:.999}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:page-start/body-content-end;z-index:998;opacity:.999}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/page-end;z-index:998;opacity:.999}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:page-start-inset/page-end-inset;padding:1em;background:#f8f9fa;z-index:998;opacity:.999;margin-bottom:1em}}.quarto-video{margin-bottom:1em}.table{border-top:1px solid #ebedee;border-bottom:1px solid #ebedee}.table>thead{border-top-width:0;border-bottom:1px solid #b2bac1}.table a{word-break:break-word}.table>:not(caption)>*>*{background-color:unset;color:unset}#quarto-document-content .crosstalk-input .checkbox input[type=checkbox],#quarto-document-content .crosstalk-input .checkbox-inline input[type=checkbox]{position:unset;margin-top:unset;margin-left:unset}#quarto-document-content .row{margin-left:unset;margin-right:unset}.quarto-xref{white-space:nowrap}#quarto-draft-alert{margin-top:0px;margin-bottom:0px;padding:.3em;text-align:center;font-size:.9em}#quarto-draft-alert i{margin-right:.3em}a.external:after{content:"";background-image:url('data:image/svg+xml,');background-size:contain;background-repeat:no-repeat;background-position:center center;margin-left:.2em;padding-right:.75em}div.sourceCode code a.external:after{content:none}a.external:after:hover{cursor:pointer}.quarto-ext-icon{display:inline-block;font-size:.75em;padding-left:.3em}.code-with-filename .code-with-filename-file{margin-bottom:0;padding-bottom:2px;padding-top:2px;padding-left:.7em;border:var(--quarto-border-width) solid var(--quarto-border-color);border-radius:var(--quarto-border-radius);border-bottom:0;border-bottom-left-radius:0%;border-bottom-right-radius:0%}.code-with-filename div.sourceCode,.reveal .code-with-filename div.sourceCode{margin-top:0;border-top-left-radius:0%;border-top-right-radius:0%}.code-with-filename .code-with-filename-file pre{margin-bottom:0}.code-with-filename .code-with-filename-file{background-color:rgba(219,219,219,.8)}.quarto-dark .code-with-filename .code-with-filename-file{background-color:#555}.code-with-filename .code-with-filename-file strong{font-weight:400}.quarto-title-banner{margin-bottom:1em;color:#fdfeff;background:#2780e3}.quarto-title-banner a{color:#fdfeff}.quarto-title-banner h1,.quarto-title-banner .h1,.quarto-title-banner h2,.quarto-title-banner .h2{color:#fdfeff}.quarto-title-banner .code-tools-button{color:#97cbff}.quarto-title-banner .code-tools-button:hover{color:#fdfeff}.quarto-title-banner .code-tools-button>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .quarto-title .title{font-weight:600}.quarto-title-banner .quarto-categories{margin-top:.75em}@media(min-width: 992px){.quarto-title-banner{padding-top:2.5em;padding-bottom:2.5em}}@media(max-width: 991.98px){.quarto-title-banner{padding-top:1em;padding-bottom:1em}}@media(max-width: 767.98px){body.hypothesis-enabled #title-block-header>*{padding-right:20px}}main.quarto-banner-title-block>section:first-child>h2,main.quarto-banner-title-block>section:first-child>.h2,main.quarto-banner-title-block>section:first-child>h3,main.quarto-banner-title-block>section:first-child>.h3,main.quarto-banner-title-block>section:first-child>h4,main.quarto-banner-title-block>section:first-child>.h4{margin-top:0}.quarto-title .quarto-categories{display:flex;flex-wrap:wrap;row-gap:.5em;column-gap:.4em;padding-bottom:.5em;margin-top:.75em}.quarto-title .quarto-categories .quarto-category{padding:.25em .75em;font-size:.65em;text-transform:uppercase;border:solid 1px;border-radius:.25rem;opacity:.6}.quarto-title .quarto-categories .quarto-category a{color:inherit}.quarto-title-meta-container{display:grid;grid-template-columns:1fr auto}.quarto-title-meta-column-end{display:flex;flex-direction:column;padding-left:1em}.quarto-title-meta-column-end a .bi{margin-right:.3em}#title-block-header.quarto-title-block.default .quarto-title-meta{display:grid;grid-template-columns:repeat(2, 1fr);grid-column-gap:1em}#title-block-header.quarto-title-block.default .quarto-title .title{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-author-orcid img{margin-top:-0.2em;height:.8em;width:.8em}#title-block-header.quarto-title-block.default .quarto-title-author-email{opacity:.7}#title-block-header.quarto-title-block.default .quarto-description p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p,#title-block-header.quarto-title-block.default .quarto-title-authors p,#title-block-header.quarto-title-block.default .quarto-title-affiliations p{margin-bottom:.1em}#title-block-header.quarto-title-block.default .quarto-title-meta-heading{text-transform:uppercase;margin-top:1em;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-contents{font-size:.9em}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p.affiliation:last-of-type{margin-bottom:.1em}#title-block-header.quarto-title-block.default p.affiliation{margin-bottom:.1em}#title-block-header.quarto-title-block.default .keywords,#title-block-header.quarto-title-block.default .description,#title-block-header.quarto-title-block.default .abstract{margin-top:0}#title-block-header.quarto-title-block.default .keywords>p,#title-block-header.quarto-title-block.default .description>p,#title-block-header.quarto-title-block.default .abstract>p{font-size:.9em}#title-block-header.quarto-title-block.default .keywords>p:last-of-type,#title-block-header.quarto-title-block.default .description>p:last-of-type,#title-block-header.quarto-title-block.default .abstract>p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .keywords .block-title,#title-block-header.quarto-title-block.default .description .block-title,#title-block-header.quarto-title-block.default .abstract .block-title{margin-top:1em;text-transform:uppercase;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-author{display:grid;grid-template-columns:minmax(max-content, 1fr) 1fr;grid-column-gap:1em}.quarto-title-tools-only{display:flex;justify-content:right}body{-webkit-font-smoothing:antialiased}.badge.bg-light{color:#343a40}.progress .progress-bar{font-size:8px;line-height:8px} diff --git a/site_libs/bootstrap/bootstrap.min.js b/site_libs/bootstrap/bootstrap.min.js new file mode 100644 index 0000000..e8f21f7 --- /dev/null +++ b/site_libs/bootstrap/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.3.1 (https://getbootstrap.com/) + * Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function M(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function j(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${j(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${j(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=M(t.dataset[n])}return e},getDataAttribute:(t,e)=>M(t.getAttribute(`data-bs-${j(e)}`))};class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${r}" but expected type "${s}".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.1"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return n(e)},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},q=".bs.alert",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return"alert"}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(Q,"close"),m(Q);const X='[data-bs-toggle="button"]';class Y extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}N.on(document,"click.bs.button.data-api",X,(t=>{t.preventDefault();const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U=".bs.swipe",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return"swipe"}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add("pointer-event")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ot=".bs.carousel",rt=".data-api",at="next",lt="prev",ct="left",ht="right",dt=`slide${ot}`,ut=`slid${ot}`,ft=`keydown${ot}`,pt=`mouseenter${ot}`,mt=`mouseleave${ot}`,gt=`dragstart${ot}`,_t=`load${ot}${rt}`,bt=`click${ot}${rt}`,vt="carousel",yt="active",wt=".active",At=".carousel-item",Et=wt+At,Tt={ArrowLeft:ht,ArrowRight:ct},Ct={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Ot={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class xt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===vt&&this.cycle()}static get Default(){return Ct}static get DefaultType(){return Ot}static get NAME(){return"carousel"}next(){this._slide(at)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(lt)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,ut,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,ut,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?at:lt;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,ft,(t=>this._keydown(t))),"hover"===this._config.pause&&(N.on(this._element,pt,(()=>this.pause())),N.on(this._element,mt,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(".carousel-item img",this._element))N.on(t,gt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ct)),rightCallback:()=>this._slide(this._directionToOrder(ht)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Tt[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=z.findOne(wt,this._indicatorsElement);e.classList.remove(yt),e.removeAttribute("aria-current");const i=z.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(yt),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===at,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(dt).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(yt),i.classList.remove(yt,c,l),this._isSliding=!1,r(ut)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return z.findOne(Et,this._element)}_getItems(){return z.find(At,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ct?lt:at:t===ct?at:lt}_orderToDirection(t){return p()?t===lt?ct:ht:t===lt?ht:ct}static jQueryInterface(t){return this.each((function(){const e=xt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}N.on(document,bt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(vt))return;t.preventDefault();const i=xt.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===F.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,_t,(()=>{const t=z.find('[data-bs-ride="carousel"]');for(const e of t)xt.getOrCreateInstance(e)})),m(xt);const kt=".bs.collapse",Lt=`show${kt}`,St=`shown${kt}`,Dt=`hide${kt}`,$t=`hidden${kt}`,It=`click${kt}.data-api`,Nt="show",Pt="collapse",Mt="collapsing",jt=`:scope .${Pt} .${Pt}`,Ft='[data-bs-toggle="collapse"]',Ht={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Bt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Ft);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Ht}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Bt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Lt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Pt),this._element.classList.add(Mt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Mt),this._element.classList.add(Pt,Nt),this._element.style[e]="",N.trigger(this._element,St)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(N.trigger(this._element,Dt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(Mt),this._element.classList.remove(Pt,Nt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Mt),this._element.classList.add(Pt),N.trigger(this._element,$t)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(Nt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Ft);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(jt,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Bt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}N.on(document,It,Ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Bt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Bt);var zt="top",Rt="bottom",qt="right",Vt="left",Kt="auto",Qt=[zt,Rt,qt,Vt],Xt="start",Yt="end",Ut="clippingParents",Gt="viewport",Jt="popper",Zt="reference",te=Qt.reduce((function(t,e){return t.concat([e+"-"+Xt,e+"-"+Yt])}),[]),ee=[].concat(Qt,[Kt]).reduce((function(t,e){return t.concat([e,e+"-"+Xt,e+"-"+Yt])}),[]),ie="beforeRead",ne="read",se="afterRead",oe="beforeMain",re="main",ae="afterMain",le="beforeWrite",ce="write",he="afterWrite",de=[ie,ne,se,oe,re,ae,le,ce,he];function ue(t){return t?(t.nodeName||"").toLowerCase():null}function fe(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function pe(t){return t instanceof fe(t).Element||t instanceof Element}function me(t){return t instanceof fe(t).HTMLElement||t instanceof HTMLElement}function ge(t){return"undefined"!=typeof ShadowRoot&&(t instanceof fe(t).ShadowRoot||t instanceof ShadowRoot)}const _e={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];me(s)&&ue(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});me(n)&&ue(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function be(t){return t.split("-")[0]}var ve=Math.max,ye=Math.min,we=Math.round;function Ae(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function Ee(){return!/^((?!chrome|android).)*safari/i.test(Ae())}function Te(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&me(t)&&(s=t.offsetWidth>0&&we(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&we(n.height)/t.offsetHeight||1);var r=(pe(t)?fe(t):window).visualViewport,a=!Ee()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function Ce(t){var e=Te(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Oe(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&ge(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function xe(t){return fe(t).getComputedStyle(t)}function ke(t){return["table","td","th"].indexOf(ue(t))>=0}function Le(t){return((pe(t)?t.ownerDocument:t.document)||window.document).documentElement}function Se(t){return"html"===ue(t)?t:t.assignedSlot||t.parentNode||(ge(t)?t.host:null)||Le(t)}function De(t){return me(t)&&"fixed"!==xe(t).position?t.offsetParent:null}function $e(t){for(var e=fe(t),i=De(t);i&&ke(i)&&"static"===xe(i).position;)i=De(i);return i&&("html"===ue(i)||"body"===ue(i)&&"static"===xe(i).position)?e:i||function(t){var e=/firefox/i.test(Ae());if(/Trident/i.test(Ae())&&me(t)&&"fixed"===xe(t).position)return null;var i=Se(t);for(ge(i)&&(i=i.host);me(i)&&["html","body"].indexOf(ue(i))<0;){var n=xe(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Ie(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function Ne(t,e,i){return ve(t,ye(e,i))}function Pe(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function Me(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const je={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=be(i.placement),l=Ie(a),c=[Vt,qt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Pe("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:Me(t,Qt))}(s.padding,i),d=Ce(o),u="y"===l?zt:Vt,f="y"===l?Rt:qt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=$e(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=Ne(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Oe(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Fe(t){return t.split("-")[1]}var He={top:"auto",right:"auto",bottom:"auto",left:"auto"};function We(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Vt,y=zt,w=window;if(c){var A=$e(i),E="clientHeight",T="clientWidth";A===fe(i)&&"static"!==xe(A=Le(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===zt||(s===Vt||s===qt)&&o===Yt)&&(y=Rt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Vt&&(s!==zt&&s!==Rt||o!==Yt)||(v=qt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&He),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:we(i*s)/s||0,y:we(n*s)/s||0}}({x:f,y:m},fe(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const Be={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:be(e.placement),variation:Fe(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,We(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,We(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var ze={passive:!0};const Re={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=fe(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,ze)})),a&&l.addEventListener("resize",i.update,ze),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,ze)})),a&&l.removeEventListener("resize",i.update,ze)}},data:{}};var qe={left:"right",right:"left",bottom:"top",top:"bottom"};function Ve(t){return t.replace(/left|right|bottom|top/g,(function(t){return qe[t]}))}var Ke={start:"end",end:"start"};function Qe(t){return t.replace(/start|end/g,(function(t){return Ke[t]}))}function Xe(t){var e=fe(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ye(t){return Te(Le(t)).left+Xe(t).scrollLeft}function Ue(t){var e=xe(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ge(t){return["html","body","#document"].indexOf(ue(t))>=0?t.ownerDocument.body:me(t)&&Ue(t)?t:Ge(Se(t))}function Je(t,e){var i;void 0===e&&(e=[]);var n=Ge(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=fe(n),r=s?[o].concat(o.visualViewport||[],Ue(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Je(Se(r)))}function Ze(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ti(t,e,i){return e===Gt?Ze(function(t,e){var i=fe(t),n=Le(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ee();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ye(t),y:l}}(t,i)):pe(e)?function(t,e){var i=Te(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):Ze(function(t){var e,i=Le(t),n=Xe(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ve(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ve(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ye(t),l=-n.scrollTop;return"rtl"===xe(s||i).direction&&(a+=ve(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Le(t)))}function ei(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?be(s):null,r=s?Fe(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case zt:e={x:a,y:i.y-n.height};break;case Rt:e={x:a,y:i.y+i.height};break;case qt:e={x:i.x+i.width,y:l};break;case Vt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Ie(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Xt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Yt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ii(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Ut:a,c=i.rootBoundary,h=void 0===c?Gt:c,d=i.elementContext,u=void 0===d?Jt:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Pe("number"!=typeof g?g:Me(g,Qt)),b=u===Jt?Zt:Jt,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=Je(Se(t)),i=["absolute","fixed"].indexOf(xe(t).position)>=0&&me(t)?$e(t):t;return pe(i)?e.filter((function(t){return pe(t)&&Oe(t,i)&&"body"!==ue(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ti(t,i,n);return e.top=ve(s.top,e.top),e.right=ye(s.right,e.right),e.bottom=ye(s.bottom,e.bottom),e.left=ve(s.left,e.left),e}),ti(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(pe(y)?y:y.contextElement||Le(t.elements.popper),l,h,r),A=Te(t.elements.reference),E=ei({reference:A,element:v,strategy:"absolute",placement:s}),T=Ze(Object.assign({},v,E)),C=u===Jt?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===Jt&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[qt,Rt].indexOf(t)>=0?1:-1,i=[zt,Rt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function ni(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ee:l,h=Fe(n),d=h?a?te:te.filter((function(t){return Fe(t)===h})):Qt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ii(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[be(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const si={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=be(g),b=l||(_!==g&&p?function(t){if(be(t)===Kt)return[];var e=Ve(t);return[Qe(t),e,Qe(e)]}(g):[Ve(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(be(i)===Kt?ni(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?"width":"height",D=ii(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?qt:Vt:k?Rt:zt;y[S]>w[S]&&($=Ve($));var I=Ve($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==P(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function oi(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ri(t){return[zt,qt,Rt,Vt].some((function(e){return t[e]>=0}))}const ai={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ii(e,{elementContext:"reference"}),a=ii(e,{altBoundary:!0}),l=oi(r,n),c=oi(a,s,o),h=ri(l),d=ri(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},li={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ee.reduce((function(t,i){return t[i]=function(t,e,i){var n=be(t),s=[Vt,zt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Vt,qt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},ci={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ei({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},hi={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ii(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=be(e.placement),b=Fe(e.placement),v=!b,y=Ie(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?zt:Vt,D="y"===y?Rt:qt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],M=f?-T[$]/2:0,j=b===Xt?E[$]:T[$],F=b===Xt?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?Ce(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=Ne(0,E[$],W[$]),V=v?E[$]/2-M-q-z-O.mainAxis:j-q-z-O.mainAxis,K=v?-E[$]/2+M+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&$e(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=Ne(f?ye(N,I+V-Y-X):N,I,f?ve(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?zt:Vt,tt="x"===y?Rt:qt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[zt,Vt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=Ne(t,e,i);return n>i?i:n}(at,et,lt):Ne(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function di(t,e,i){void 0===i&&(i=!1);var n,s,o=me(e),r=me(e)&&function(t){var e=t.getBoundingClientRect(),i=we(e.width)/t.offsetWidth||1,n=we(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=Le(e),l=Te(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==ue(e)||Ue(a))&&(c=(n=e)!==fe(n)&&me(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Xe(n)),me(e)?((h=Te(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ye(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function ui(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var fi={placement:"bottom",modifiers:[],strategy:"absolute"};function pi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(F.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...g(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=z.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Ti,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=z.find(Ni);for(const i of e){const e=qi.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ei,Ti].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Ii)?this:z.prev(this,Ii)[0]||z.next(this,Ii)[0]||z.findOne(Ii,t.delegateTarget.parentNode),o=qi.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,Si,Ii,qi.dataApiKeydownHandler),N.on(document,Si,Pi,qi.dataApiKeydownHandler),N.on(document,Li,qi.clearMenus),N.on(document,Di,qi.clearMenus),N.on(document,Li,Ii,(function(t){t.preventDefault(),qi.getOrCreateInstance(this).toggle()})),m(qi);const Vi="backdrop",Ki="show",Qi=`mousedown.bs.${Vi}`,Xi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Yi={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ui extends H{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Xi}static get DefaultType(){return Yi}static get NAME(){return Vi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Ki),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Ki),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Qi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Qi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const Gi=".bs.focustrap",Ji=`focusin${Gi}`,Zi=`keydown.tab${Gi}`,tn="backward",en={autofocus:!0,trapElement:null},nn={autofocus:"boolean",trapElement:"element"};class sn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return en}static get DefaultType(){return nn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Gi),N.on(document,Ji,(t=>this._handleFocusin(t))),N.on(document,Zi,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Gi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===tn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?tn:"forward")}}const on=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",rn=".sticky-top",an="padding-right",ln="margin-right";class cn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,an,(e=>e+t)),this._setElementAttributes(on,an,(e=>e+t)),this._setElementAttributes(rn,ln,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,an),this._resetElementAttributes(on,an),this._resetElementAttributes(rn,ln)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const hn=".bs.modal",dn=`hide${hn}`,un=`hidePrevented${hn}`,fn=`hidden${hn}`,pn=`show${hn}`,mn=`shown${hn}`,gn=`resize${hn}`,_n=`click.dismiss${hn}`,bn=`mousedown.dismiss${hn}`,vn=`keydown.dismiss${hn}`,yn=`click${hn}.data-api`,wn="modal-open",An="show",En="modal-static",Tn={backdrop:!0,focus:!0,keyboard:!0},Cn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class On extends W{constructor(t,e){super(t,e),this._dialog=z.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new cn,this._addEventListeners()}static get Default(){return Tn}static get DefaultType(){return Cn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,pn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(wn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,dn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(An),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,hn),N.off(this._dialog,hn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ui({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=z.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(An),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,mn,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element,vn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,gn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,bn,(t=>{N.one(this._element,_n,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(wn),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,fn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(N.trigger(this._element,un).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(En)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(En),this._queueCallback((()=>{this._element.classList.remove(En),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=On.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}N.on(document,yn,'[data-bs-toggle="modal"]',(function(t){const e=z.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),N.one(e,pn,(t=>{t.defaultPrevented||N.one(e,fn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne(".modal.show");i&&On.getInstance(i).hide(),On.getOrCreateInstance(e).toggle(this)})),R(On),m(On);const xn=".bs.offcanvas",kn=".data-api",Ln=`load${xn}${kn}`,Sn="show",Dn="showing",$n="hiding",In=".offcanvas.show",Nn=`show${xn}`,Pn=`shown${xn}`,Mn=`hide${xn}`,jn=`hidePrevented${xn}`,Fn=`hidden${xn}`,Hn=`resize${xn}`,Wn=`click${xn}${kn}`,Bn=`keydown.dismiss${xn}`,zn={backdrop:!0,keyboard:!0,scroll:!1},Rn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class qn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return zn}static get DefaultType(){return Rn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,Nn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new cn).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Dn),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Sn),this._element.classList.remove(Dn),N.trigger(this._element,Pn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,Mn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add($n),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(Sn,$n),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new cn).reset(),N.trigger(this._element,Fn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ui({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():N.trigger(this._element,jn)}:null})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Bn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,jn))}))}static jQueryInterface(t){return this.each((function(){const e=qn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}N.on(document,Wn,'[data-bs-toggle="offcanvas"]',(function(t){const e=z.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Fn,(()=>{a(this)&&this.focus()}));const i=z.findOne(In);i&&i!==e&&qn.getInstance(i).hide(),qn.getOrCreateInstance(e).toggle(this)})),N.on(window,Ln,(()=>{for(const t of z.find(In))qn.getOrCreateInstance(t).show()})),N.on(window,Hn,(()=>{for(const t of z.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&qn.getOrCreateInstance(t).hide()})),R(qn),m(qn);const Vn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Kn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Qn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Xn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Kn.has(i)||Boolean(Qn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Yn={allowList:Vn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"

"},Un={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Gn={entry:"(string|element|function|null)",selector:"(string|element)"};class Jn extends H{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Yn}static get DefaultType(){return Un}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Gn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Xn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return g(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Zn=new Set(["sanitize","allowList","sanitizeFn"]),ts="fade",es="show",is=".modal",ns="hide.bs.modal",ss="hover",os="focus",rs={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},as={allowList:Vn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},ls={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class cs extends W{constructor(t,e){if(void 0===vi)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return as}static get DefaultType(){return ls}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(is),ns,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,"mouseover",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,"mouseover",h);this._activeTrigger.click=!1,this._activeTrigger[os]=!1,this._activeTrigger[ss]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),N.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ts,es),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(ts),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Jn({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ts)}_isShown(){return this.tip&&this.tip.classList.contains(es)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=rs[e.toUpperCase()];return bi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)N.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===ss?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ss?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?os:ss]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?os:ss]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(is),ns,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))Zn.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=cs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(cs);const hs={...cs.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},ds={...cs.DefaultType,content:"(null|string|element|function)"};class us extends cs{static get Default(){return hs}static get DefaultType(){return ds}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=us.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(us);const fs=".bs.scrollspy",ps=`activate${fs}`,ms=`click${fs}`,gs=`load${fs}.data-api`,_s="active",bs="[href]",vs=".nav-link",ys=`${vs}, .nav-item > ${vs}, .list-group-item`,ws={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},As={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Es extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ws}static get DefaultType(){return As}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ms),N.on(this._config.target,ms,bs,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(bs,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(_s),this._activateParents(t),N.trigger(this._element,ps,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))z.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(_s);else for(const e of z.parents(t,".nav, .list-group"))for(const t of z.prev(e,ys))t.classList.add(_s)}_clearActiveClass(t){t.classList.remove(_s);const e=z.find(`${bs}.${_s}`,t);for(const t of e)t.classList.remove(_s)}static jQueryInterface(t){return this.each((function(){const e=Es.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(window,gs,(()=>{for(const t of z.find('[data-bs-spy="scroll"]'))Es.getOrCreateInstance(t)})),m(Es);const Ts=".bs.tab",Cs=`hide${Ts}`,Os=`hidden${Ts}`,xs=`show${Ts}`,ks=`shown${Ts}`,Ls=`click${Ts}`,Ss=`keydown${Ts}`,Ds=`load${Ts}`,$s="ArrowLeft",Is="ArrowRight",Ns="ArrowUp",Ps="ArrowDown",Ms="Home",js="End",Fs="active",Hs="fade",Ws="show",Bs=":not(.dropdown-toggle)",zs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Rs=`.nav-link${Bs}, .list-group-item${Bs}, [role="tab"]${Bs}, ${zs}`,qs=`.${Fs}[data-bs-toggle="tab"], .${Fs}[data-bs-toggle="pill"], .${Fs}[data-bs-toggle="list"]`;class Vs extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,Ss,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Cs,{relatedTarget:t}):null;N.trigger(t,xs,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Fs),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),N.trigger(t,ks,{relatedTarget:e})):t.classList.add(Ws)}),t,t.classList.contains(Hs)))}_deactivate(t,e){t&&(t.classList.remove(Fs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),N.trigger(t,Os,{relatedTarget:e})):t.classList.remove(Ws)}),t,t.classList.contains(Hs)))}_keydown(t){if(![$s,Is,Ns,Ps,Ms,js].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([Ms,js].includes(t.key))i=e[t.key===Ms?0:e.length-1];else{const n=[Is,Ps].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Vs.getOrCreateInstance(i).show())}_getChildren(){return z.find(Rs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(".dropdown-toggle",Fs),n(".dropdown-menu",Ws),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Fs)}_getInnerElement(t){return t.matches(Rs)?t:z.findOne(Rs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Vs.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(document,Ls,zs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||Vs.getOrCreateInstance(this).show()})),N.on(window,Ds,(()=>{for(const t of z.find(qs))Vs.getOrCreateInstance(t)})),m(Vs);const Ks=".bs.toast",Qs=`mouseover${Ks}`,Xs=`mouseout${Ks}`,Ys=`focusin${Ks}`,Us=`focusout${Ks}`,Gs=`hide${Ks}`,Js=`hidden${Ks}`,Zs=`show${Ks}`,to=`shown${Ks}`,eo="hide",io="show",no="showing",so={animation:"boolean",autohide:"boolean",delay:"number"},oo={animation:!0,autohide:!0,delay:5e3};class ro extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return oo}static get DefaultType(){return so}static get NAME(){return"toast"}show(){N.trigger(this._element,Zs).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(eo),d(this._element),this._element.classList.add(io,no),this._queueCallback((()=>{this._element.classList.remove(no),N.trigger(this._element,to),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element,Gs).defaultPrevented||(this._element.classList.add(no),this._queueCallback((()=>{this._element.classList.add(eo),this._element.classList.remove(no,io),N.trigger(this._element,Js)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(io),super.dispose()}isShown(){return this._element.classList.contains(io)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,Qs,(t=>this._onInteraction(t,!0))),N.on(this._element,Xs,(t=>this._onInteraction(t,!1))),N.on(this._element,Ys,(t=>this._onInteraction(t,!0))),N.on(this._element,Us,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ro.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(ro),m(ro),{Alert:Q,Button:Y,Carousel:xt,Collapse:Bt,Dropdown:qi,Modal:On,Offcanvas:qn,Popover:us,ScrollSpy:Es,Tab:Vs,Toast:ro,Tooltip:cs}})); +//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/site_libs/clipboard/clipboard.min.js b/site_libs/clipboard/clipboard.min.js new file mode 100644 index 0000000..1103f81 --- /dev/null +++ b/site_libs/clipboard/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1.anchorjs-link,.anchorjs-link:focus{opacity:1}",A.sheet.cssRules.length),A.sheet.insertRule("[data-anchorjs-icon]::after{content:attr(data-anchorjs-icon)}",A.sheet.cssRules.length),A.sheet.insertRule('@font-face{font-family:anchorjs-icons;src:url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype")}',A.sheet.cssRules.length)),h=document.querySelectorAll("[id]"),t=[].map.call(h,function(A){return A.id}),i=0;i\]./()*\\\n\t\b\v\u00A0]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),A=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||A||!1}}}); +// @license-end \ No newline at end of file diff --git a/site_libs/quarto-html/popper.min.js b/site_libs/quarto-html/popper.min.js new file mode 100644 index 0000000..e3726d7 --- /dev/null +++ b/site_libs/quarto-html/popper.min.js @@ -0,0 +1,6 @@ +/** + * @popperjs/core v2.11.7 - MIT License + */ + +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Popper={})}(this,(function(e){"use strict";function t(e){if(null==e)return window;if("[object Window]"!==e.toString()){var t=e.ownerDocument;return t&&t.defaultView||window}return e}function n(e){return e instanceof t(e).Element||e instanceof Element}function r(e){return e instanceof t(e).HTMLElement||e instanceof HTMLElement}function o(e){return"undefined"!=typeof ShadowRoot&&(e instanceof t(e).ShadowRoot||e instanceof ShadowRoot)}var i=Math.max,a=Math.min,s=Math.round;function f(){var e=navigator.userAgentData;return null!=e&&e.brands&&Array.isArray(e.brands)?e.brands.map((function(e){return e.brand+"/"+e.version})).join(" "):navigator.userAgent}function c(){return!/^((?!chrome|android).)*safari/i.test(f())}function p(e,o,i){void 0===o&&(o=!1),void 0===i&&(i=!1);var a=e.getBoundingClientRect(),f=1,p=1;o&&r(e)&&(f=e.offsetWidth>0&&s(a.width)/e.offsetWidth||1,p=e.offsetHeight>0&&s(a.height)/e.offsetHeight||1);var u=(n(e)?t(e):window).visualViewport,l=!c()&&i,d=(a.left+(l&&u?u.offsetLeft:0))/f,h=(a.top+(l&&u?u.offsetTop:0))/p,m=a.width/f,v=a.height/p;return{width:m,height:v,top:h,right:d+m,bottom:h+v,left:d,x:d,y:h}}function u(e){var n=t(e);return{scrollLeft:n.pageXOffset,scrollTop:n.pageYOffset}}function l(e){return e?(e.nodeName||"").toLowerCase():null}function d(e){return((n(e)?e.ownerDocument:e.document)||window.document).documentElement}function h(e){return p(d(e)).left+u(e).scrollLeft}function m(e){return t(e).getComputedStyle(e)}function v(e){var t=m(e),n=t.overflow,r=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+r)}function y(e,n,o){void 0===o&&(o=!1);var i,a,f=r(n),c=r(n)&&function(e){var t=e.getBoundingClientRect(),n=s(t.width)/e.offsetWidth||1,r=s(t.height)/e.offsetHeight||1;return 1!==n||1!==r}(n),m=d(n),y=p(e,c,o),g={scrollLeft:0,scrollTop:0},b={x:0,y:0};return(f||!f&&!o)&&(("body"!==l(n)||v(m))&&(g=(i=n)!==t(i)&&r(i)?{scrollLeft:(a=i).scrollLeft,scrollTop:a.scrollTop}:u(i)),r(n)?((b=p(n,!0)).x+=n.clientLeft,b.y+=n.clientTop):m&&(b.x=h(m))),{x:y.left+g.scrollLeft-b.x,y:y.top+g.scrollTop-b.y,width:y.width,height:y.height}}function g(e){var t=p(e),n=e.offsetWidth,r=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-r)<=1&&(r=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:r}}function b(e){return"html"===l(e)?e:e.assignedSlot||e.parentNode||(o(e)?e.host:null)||d(e)}function x(e){return["html","body","#document"].indexOf(l(e))>=0?e.ownerDocument.body:r(e)&&v(e)?e:x(b(e))}function w(e,n){var r;void 0===n&&(n=[]);var o=x(e),i=o===(null==(r=e.ownerDocument)?void 0:r.body),a=t(o),s=i?[a].concat(a.visualViewport||[],v(o)?o:[]):o,f=n.concat(s);return i?f:f.concat(w(b(s)))}function O(e){return["table","td","th"].indexOf(l(e))>=0}function j(e){return r(e)&&"fixed"!==m(e).position?e.offsetParent:null}function E(e){for(var n=t(e),i=j(e);i&&O(i)&&"static"===m(i).position;)i=j(i);return i&&("html"===l(i)||"body"===l(i)&&"static"===m(i).position)?n:i||function(e){var t=/firefox/i.test(f());if(/Trident/i.test(f())&&r(e)&&"fixed"===m(e).position)return null;var n=b(e);for(o(n)&&(n=n.host);r(n)&&["html","body"].indexOf(l(n))<0;){var i=m(n);if("none"!==i.transform||"none"!==i.perspective||"paint"===i.contain||-1!==["transform","perspective"].indexOf(i.willChange)||t&&"filter"===i.willChange||t&&i.filter&&"none"!==i.filter)return n;n=n.parentNode}return null}(e)||n}var D="top",A="bottom",L="right",P="left",M="auto",k=[D,A,L,P],W="start",B="end",H="viewport",T="popper",R=k.reduce((function(e,t){return e.concat([t+"-"+W,t+"-"+B])}),[]),S=[].concat(k,[M]).reduce((function(e,t){return e.concat([t,t+"-"+W,t+"-"+B])}),[]),V=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function q(e){var t=new Map,n=new Set,r=[];function o(e){n.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){if(!n.has(e)){var r=t.get(e);r&&o(r)}})),r.push(e)}return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||o(e)})),r}function C(e){return e.split("-")[0]}function N(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&o(n)){var r=t;do{if(r&&e.isSameNode(r))return!0;r=r.parentNode||r.host}while(r)}return!1}function I(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function _(e,r,o){return r===H?I(function(e,n){var r=t(e),o=d(e),i=r.visualViewport,a=o.clientWidth,s=o.clientHeight,f=0,p=0;if(i){a=i.width,s=i.height;var u=c();(u||!u&&"fixed"===n)&&(f=i.offsetLeft,p=i.offsetTop)}return{width:a,height:s,x:f+h(e),y:p}}(e,o)):n(r)?function(e,t){var n=p(e,!1,"fixed"===t);return n.top=n.top+e.clientTop,n.left=n.left+e.clientLeft,n.bottom=n.top+e.clientHeight,n.right=n.left+e.clientWidth,n.width=e.clientWidth,n.height=e.clientHeight,n.x=n.left,n.y=n.top,n}(r,o):I(function(e){var t,n=d(e),r=u(e),o=null==(t=e.ownerDocument)?void 0:t.body,a=i(n.scrollWidth,n.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),s=i(n.scrollHeight,n.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),f=-r.scrollLeft+h(e),c=-r.scrollTop;return"rtl"===m(o||n).direction&&(f+=i(n.clientWidth,o?o.clientWidth:0)-a),{width:a,height:s,x:f,y:c}}(d(e)))}function F(e,t,o,s){var f="clippingParents"===t?function(e){var t=w(b(e)),o=["absolute","fixed"].indexOf(m(e).position)>=0&&r(e)?E(e):e;return n(o)?t.filter((function(e){return n(e)&&N(e,o)&&"body"!==l(e)})):[]}(e):[].concat(t),c=[].concat(f,[o]),p=c[0],u=c.reduce((function(t,n){var r=_(e,n,s);return t.top=i(r.top,t.top),t.right=a(r.right,t.right),t.bottom=a(r.bottom,t.bottom),t.left=i(r.left,t.left),t}),_(e,p,s));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u}function U(e){return e.split("-")[1]}function z(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function X(e){var t,n=e.reference,r=e.element,o=e.placement,i=o?C(o):null,a=o?U(o):null,s=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2;switch(i){case D:t={x:s,y:n.y-r.height};break;case A:t={x:s,y:n.y+n.height};break;case L:t={x:n.x+n.width,y:f};break;case P:t={x:n.x-r.width,y:f};break;default:t={x:n.x,y:n.y}}var c=i?z(i):null;if(null!=c){var p="y"===c?"height":"width";switch(a){case W:t[c]=t[c]-(n[p]/2-r[p]/2);break;case B:t[c]=t[c]+(n[p]/2-r[p]/2)}}return t}function Y(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function G(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function J(e,t){void 0===t&&(t={});var r=t,o=r.placement,i=void 0===o?e.placement:o,a=r.strategy,s=void 0===a?e.strategy:a,f=r.boundary,c=void 0===f?"clippingParents":f,u=r.rootBoundary,l=void 0===u?H:u,h=r.elementContext,m=void 0===h?T:h,v=r.altBoundary,y=void 0!==v&&v,g=r.padding,b=void 0===g?0:g,x=Y("number"!=typeof b?b:G(b,k)),w=m===T?"reference":T,O=e.rects.popper,j=e.elements[y?w:m],E=F(n(j)?j:j.contextElement||d(e.elements.popper),c,l,s),P=p(e.elements.reference),M=X({reference:P,element:O,strategy:"absolute",placement:i}),W=I(Object.assign({},O,M)),B=m===T?W:P,R={top:E.top-B.top+x.top,bottom:B.bottom-E.bottom+x.bottom,left:E.left-B.left+x.left,right:B.right-E.right+x.right},S=e.modifiersData.offset;if(m===T&&S){var V=S[i];Object.keys(R).forEach((function(e){var t=[L,A].indexOf(e)>=0?1:-1,n=[D,A].indexOf(e)>=0?"y":"x";R[e]+=V[n]*t}))}return R}var K={placement:"bottom",modifiers:[],strategy:"absolute"};function Q(){for(var e=arguments.length,t=new Array(e),n=0;n=0?-1:1,i="function"==typeof n?n(Object.assign({},t,{placement:e})):n,a=i[0],s=i[1];return a=a||0,s=(s||0)*o,[P,L].indexOf(r)>=0?{x:s,y:a}:{x:a,y:s}}(n,t.rects,i),e}),{}),s=a[t.placement],f=s.x,c=s.y;null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=f,t.modifiersData.popperOffsets.y+=c),t.modifiersData[r]=a}},se={left:"right",right:"left",bottom:"top",top:"bottom"};function fe(e){return e.replace(/left|right|bottom|top/g,(function(e){return se[e]}))}var ce={start:"end",end:"start"};function pe(e){return e.replace(/start|end/g,(function(e){return ce[e]}))}function ue(e,t){void 0===t&&(t={});var n=t,r=n.placement,o=n.boundary,i=n.rootBoundary,a=n.padding,s=n.flipVariations,f=n.allowedAutoPlacements,c=void 0===f?S:f,p=U(r),u=p?s?R:R.filter((function(e){return U(e)===p})):k,l=u.filter((function(e){return c.indexOf(e)>=0}));0===l.length&&(l=u);var d=l.reduce((function(t,n){return t[n]=J(e,{placement:n,boundary:o,rootBoundary:i,padding:a})[C(n)],t}),{});return Object.keys(d).sort((function(e,t){return d[e]-d[t]}))}var le={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name;if(!t.modifiersData[r]._skip){for(var o=n.mainAxis,i=void 0===o||o,a=n.altAxis,s=void 0===a||a,f=n.fallbackPlacements,c=n.padding,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.flipVariations,h=void 0===d||d,m=n.allowedAutoPlacements,v=t.options.placement,y=C(v),g=f||(y===v||!h?[fe(v)]:function(e){if(C(e)===M)return[];var t=fe(e);return[pe(e),t,pe(t)]}(v)),b=[v].concat(g).reduce((function(e,n){return e.concat(C(n)===M?ue(t,{placement:n,boundary:p,rootBoundary:u,padding:c,flipVariations:h,allowedAutoPlacements:m}):n)}),[]),x=t.rects.reference,w=t.rects.popper,O=new Map,j=!0,E=b[0],k=0;k=0,S=R?"width":"height",V=J(t,{placement:B,boundary:p,rootBoundary:u,altBoundary:l,padding:c}),q=R?T?L:P:T?A:D;x[S]>w[S]&&(q=fe(q));var N=fe(q),I=[];if(i&&I.push(V[H]<=0),s&&I.push(V[q]<=0,V[N]<=0),I.every((function(e){return e}))){E=B,j=!1;break}O.set(B,I)}if(j)for(var _=function(e){var t=b.find((function(t){var n=O.get(t);if(n)return n.slice(0,e).every((function(e){return e}))}));if(t)return E=t,"break"},F=h?3:1;F>0;F--){if("break"===_(F))break}t.placement!==E&&(t.modifiersData[r]._skip=!0,t.placement=E,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function de(e,t,n){return i(e,a(t,n))}var he={name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name,o=n.mainAxis,s=void 0===o||o,f=n.altAxis,c=void 0!==f&&f,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.padding,h=n.tether,m=void 0===h||h,v=n.tetherOffset,y=void 0===v?0:v,b=J(t,{boundary:p,rootBoundary:u,padding:d,altBoundary:l}),x=C(t.placement),w=U(t.placement),O=!w,j=z(x),M="x"===j?"y":"x",k=t.modifiersData.popperOffsets,B=t.rects.reference,H=t.rects.popper,T="function"==typeof y?y(Object.assign({},t.rects,{placement:t.placement})):y,R="number"==typeof T?{mainAxis:T,altAxis:T}:Object.assign({mainAxis:0,altAxis:0},T),S=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,V={x:0,y:0};if(k){if(s){var q,N="y"===j?D:P,I="y"===j?A:L,_="y"===j?"height":"width",F=k[j],X=F+b[N],Y=F-b[I],G=m?-H[_]/2:0,K=w===W?B[_]:H[_],Q=w===W?-H[_]:-B[_],Z=t.elements.arrow,$=m&&Z?g(Z):{width:0,height:0},ee=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},te=ee[N],ne=ee[I],re=de(0,B[_],$[_]),oe=O?B[_]/2-G-re-te-R.mainAxis:K-re-te-R.mainAxis,ie=O?-B[_]/2+G+re+ne+R.mainAxis:Q+re+ne+R.mainAxis,ae=t.elements.arrow&&E(t.elements.arrow),se=ae?"y"===j?ae.clientTop||0:ae.clientLeft||0:0,fe=null!=(q=null==S?void 0:S[j])?q:0,ce=F+ie-fe,pe=de(m?a(X,F+oe-fe-se):X,F,m?i(Y,ce):Y);k[j]=pe,V[j]=pe-F}if(c){var ue,le="x"===j?D:P,he="x"===j?A:L,me=k[M],ve="y"===M?"height":"width",ye=me+b[le],ge=me-b[he],be=-1!==[D,P].indexOf(x),xe=null!=(ue=null==S?void 0:S[M])?ue:0,we=be?ye:me-B[ve]-H[ve]-xe+R.altAxis,Oe=be?me+B[ve]+H[ve]-xe-R.altAxis:ge,je=m&&be?function(e,t,n){var r=de(e,t,n);return r>n?n:r}(we,me,Oe):de(m?we:ye,me,m?Oe:ge);k[M]=je,V[M]=je-me}t.modifiersData[r]=V}},requiresIfExists:["offset"]};var me={name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state,r=e.name,o=e.options,i=n.elements.arrow,a=n.modifiersData.popperOffsets,s=C(n.placement),f=z(s),c=[P,L].indexOf(s)>=0?"height":"width";if(i&&a){var p=function(e,t){return Y("number"!=typeof(e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e)?e:G(e,k))}(o.padding,n),u=g(i),l="y"===f?D:P,d="y"===f?A:L,h=n.rects.reference[c]+n.rects.reference[f]-a[f]-n.rects.popper[c],m=a[f]-n.rects.reference[f],v=E(i),y=v?"y"===f?v.clientHeight||0:v.clientWidth||0:0,b=h/2-m/2,x=p[l],w=y-u[c]-p[d],O=y/2-u[c]/2+b,j=de(x,O,w),M=f;n.modifiersData[r]=((t={})[M]=j,t.centerOffset=j-O,t)}},effect:function(e){var t=e.state,n=e.options.element,r=void 0===n?"[data-popper-arrow]":n;null!=r&&("string"!=typeof r||(r=t.elements.popper.querySelector(r)))&&N(t.elements.popper,r)&&(t.elements.arrow=r)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ve(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function ye(e){return[D,L,A,P].some((function(t){return e[t]>=0}))}var ge={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state,n=e.name,r=t.rects.reference,o=t.rects.popper,i=t.modifiersData.preventOverflow,a=J(t,{elementContext:"reference"}),s=J(t,{altBoundary:!0}),f=ve(a,r),c=ve(s,o,i),p=ye(f),u=ye(c);t.modifiersData[n]={referenceClippingOffsets:f,popperEscapeOffsets:c,isReferenceHidden:p,hasPopperEscaped:u},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":p,"data-popper-escaped":u})}},be=Z({defaultModifiers:[ee,te,oe,ie]}),xe=[ee,te,oe,ie,ae,le,he,me,ge],we=Z({defaultModifiers:xe});e.applyStyles=ie,e.arrow=me,e.computeStyles=oe,e.createPopper=we,e.createPopperLite=be,e.defaultModifiers=xe,e.detectOverflow=J,e.eventListeners=ee,e.flip=le,e.hide=ge,e.offset=ae,e.popperGenerator=Z,e.popperOffsets=te,e.preventOverflow=he,Object.defineProperty(e,"__esModule",{value:!0})})); + diff --git a/site_libs/quarto-html/quarto-syntax-highlighting.css b/site_libs/quarto-html/quarto-syntax-highlighting.css new file mode 100644 index 0000000..b30ce57 --- /dev/null +++ b/site_libs/quarto-html/quarto-syntax-highlighting.css @@ -0,0 +1,205 @@ +/* quarto syntax highlight colors */ +:root { + --quarto-hl-ot-color: #003B4F; + --quarto-hl-at-color: #657422; + --quarto-hl-ss-color: #20794D; + --quarto-hl-an-color: #5E5E5E; + --quarto-hl-fu-color: #4758AB; + --quarto-hl-st-color: #20794D; + --quarto-hl-cf-color: #003B4F; + --quarto-hl-op-color: #5E5E5E; + --quarto-hl-er-color: #AD0000; + --quarto-hl-bn-color: #AD0000; + --quarto-hl-al-color: #AD0000; + --quarto-hl-va-color: #111111; + --quarto-hl-bu-color: inherit; + --quarto-hl-ex-color: inherit; + --quarto-hl-pp-color: #AD0000; + --quarto-hl-in-color: #5E5E5E; + --quarto-hl-vs-color: #20794D; + --quarto-hl-wa-color: #5E5E5E; + --quarto-hl-do-color: #5E5E5E; + --quarto-hl-im-color: #00769E; + --quarto-hl-ch-color: #20794D; + --quarto-hl-dt-color: #AD0000; + --quarto-hl-fl-color: #AD0000; + --quarto-hl-co-color: #5E5E5E; + --quarto-hl-cv-color: #5E5E5E; + --quarto-hl-cn-color: #8f5902; + --quarto-hl-sc-color: #5E5E5E; + --quarto-hl-dv-color: #AD0000; + --quarto-hl-kw-color: #003B4F; +} + +/* other quarto variables */ +:root { + --quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} + +pre > code.sourceCode > span { + color: #003B4F; +} + +code span { + color: #003B4F; +} + +code.sourceCode > span { + color: #003B4F; +} + +div.sourceCode, +div.sourceCode pre.sourceCode { + color: #003B4F; +} + +code span.ot { + color: #003B4F; + font-style: inherit; +} + +code span.at { + color: #657422; + font-style: inherit; +} + +code span.ss { + color: #20794D; + font-style: inherit; +} + +code span.an { + color: #5E5E5E; + font-style: inherit; +} + +code span.fu { + color: #4758AB; + font-style: inherit; +} + +code span.st { + color: #20794D; + font-style: inherit; +} + +code span.cf { + color: #003B4F; + font-weight: bold; + font-style: inherit; +} + +code span.op { + color: #5E5E5E; + font-style: inherit; +} + +code span.er { + color: #AD0000; + font-style: inherit; +} + +code span.bn { + color: #AD0000; + font-style: inherit; +} + +code span.al { + color: #AD0000; + font-style: inherit; +} + +code span.va { + color: #111111; + font-style: inherit; +} + +code span.bu { + font-style: inherit; +} + +code span.ex { + font-style: inherit; +} + +code span.pp { + color: #AD0000; + font-style: inherit; +} + +code span.in { + color: #5E5E5E; + font-style: inherit; +} + +code span.vs { + color: #20794D; + font-style: inherit; +} + +code span.wa { + color: #5E5E5E; + font-style: italic; +} + +code span.do { + color: #5E5E5E; + font-style: italic; +} + +code span.im { + color: #00769E; + font-style: inherit; +} + +code span.ch { + color: #20794D; + font-style: inherit; +} + +code span.dt { + color: #AD0000; + font-style: inherit; +} + +code span.fl { + color: #AD0000; + font-style: inherit; +} + +code span.co { + color: #5E5E5E; + font-style: inherit; +} + +code span.cv { + color: #5E5E5E; + font-style: italic; +} + +code span.cn { + color: #8f5902; + font-style: inherit; +} + +code span.sc { + color: #5E5E5E; + font-style: inherit; +} + +code span.dv { + color: #AD0000; + font-style: inherit; +} + +code span.kw { + color: #003B4F; + font-weight: bold; + font-style: inherit; +} + +.prevent-inlining { + content: " { + // Find any conflicting margin elements and add margins to the + // top to prevent overlap + const marginChildren = window.document.querySelectorAll( + ".column-margin.column-container > *, .margin-caption, .aside" + ); + + let lastBottom = 0; + for (const marginChild of marginChildren) { + if (marginChild.offsetParent !== null) { + // clear the top margin so we recompute it + marginChild.style.marginTop = null; + const top = marginChild.getBoundingClientRect().top + window.scrollY; + if (top < lastBottom) { + const marginChildStyle = window.getComputedStyle(marginChild); + const marginBottom = parseFloat(marginChildStyle["marginBottom"]); + const margin = lastBottom - top + marginBottom; + marginChild.style.marginTop = `${margin}px`; + } + const styles = window.getComputedStyle(marginChild); + const marginTop = parseFloat(styles["marginTop"]); + lastBottom = top + marginChild.getBoundingClientRect().height + marginTop; + } + } +}; + +window.document.addEventListener("DOMContentLoaded", function (_event) { + // Recompute the position of margin elements anytime the body size changes + if (window.ResizeObserver) { + const resizeObserver = new window.ResizeObserver( + throttle(() => { + layoutMarginEls(); + if ( + window.document.body.getBoundingClientRect().width < 990 && + isReaderMode() + ) { + quartoToggleReader(); + } + }, 50) + ); + resizeObserver.observe(window.document.body); + } + + const tocEl = window.document.querySelector('nav.toc-active[role="doc-toc"]'); + const sidebarEl = window.document.getElementById("quarto-sidebar"); + const leftTocEl = window.document.getElementById("quarto-sidebar-toc-left"); + const marginSidebarEl = window.document.getElementById( + "quarto-margin-sidebar" + ); + // function to determine whether the element has a previous sibling that is active + const prevSiblingIsActiveLink = (el) => { + const sibling = el.previousElementSibling; + if (sibling && sibling.tagName === "A") { + return sibling.classList.contains("active"); + } else { + return false; + } + }; + + // fire slideEnter for bootstrap tab activations (for htmlwidget resize behavior) + function fireSlideEnter(e) { + const event = window.document.createEvent("Event"); + event.initEvent("slideenter", true, true); + window.document.dispatchEvent(event); + } + const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]'); + tabs.forEach((tab) => { + tab.addEventListener("shown.bs.tab", fireSlideEnter); + }); + + // fire slideEnter for tabby tab activations (for htmlwidget resize behavior) + document.addEventListener("tabby", fireSlideEnter, false); + + // Track scrolling and mark TOC links as active + // get table of contents and sidebar (bail if we don't have at least one) + const tocLinks = tocEl + ? [...tocEl.querySelectorAll("a[data-scroll-target]")] + : []; + const makeActive = (link) => tocLinks[link].classList.add("active"); + const removeActive = (link) => tocLinks[link].classList.remove("active"); + const removeAllActive = () => + [...Array(tocLinks.length).keys()].forEach((link) => removeActive(link)); + + // activate the anchor for a section associated with this TOC entry + tocLinks.forEach((link) => { + link.addEventListener("click", () => { + if (link.href.indexOf("#") !== -1) { + const anchor = link.href.split("#")[1]; + const heading = window.document.querySelector( + `[data-anchor-id="${anchor}"]` + ); + if (heading) { + // Add the class + heading.classList.add("reveal-anchorjs-link"); + + // function to show the anchor + const handleMouseout = () => { + heading.classList.remove("reveal-anchorjs-link"); + heading.removeEventListener("mouseout", handleMouseout); + }; + + // add a function to clear the anchor when the user mouses out of it + heading.addEventListener("mouseout", handleMouseout); + } + } + }); + }); + + const sections = tocLinks.map((link) => { + const target = link.getAttribute("data-scroll-target"); + if (target.startsWith("#")) { + return window.document.getElementById(decodeURI(`${target.slice(1)}`)); + } else { + return window.document.querySelector(decodeURI(`${target}`)); + } + }); + + const sectionMargin = 200; + let currentActive = 0; + // track whether we've initialized state the first time + let init = false; + + const updateActiveLink = () => { + // The index from bottom to top (e.g. reversed list) + let sectionIndex = -1; + if ( + window.innerHeight + window.pageYOffset >= + window.document.body.offsetHeight + ) { + // This is the no-scroll case where last section should be the active one + sectionIndex = 0; + } else { + // This finds the last section visible on screen that should be made active + sectionIndex = [...sections].reverse().findIndex((section) => { + if (section) { + return window.pageYOffset >= section.offsetTop - sectionMargin; + } else { + return false; + } + }); + } + if (sectionIndex > -1) { + const current = sections.length - sectionIndex - 1; + if (current !== currentActive) { + removeAllActive(); + currentActive = current; + makeActive(current); + if (init) { + window.dispatchEvent(sectionChanged); + } + init = true; + } + } + }; + + const inHiddenRegion = (top, bottom, hiddenRegions) => { + for (const region of hiddenRegions) { + if (top <= region.bottom && bottom >= region.top) { + return true; + } + } + return false; + }; + + const categorySelector = "header.quarto-title-block .quarto-category"; + const activateCategories = (href) => { + // Find any categories + // Surround them with a link pointing back to: + // #category=Authoring + try { + const categoryEls = window.document.querySelectorAll(categorySelector); + for (const categoryEl of categoryEls) { + const categoryText = categoryEl.textContent; + if (categoryText) { + const link = `${href}#category=${encodeURIComponent(categoryText)}`; + const linkEl = window.document.createElement("a"); + linkEl.setAttribute("href", link); + for (const child of categoryEl.childNodes) { + linkEl.append(child); + } + categoryEl.appendChild(linkEl); + } + } + } catch { + // Ignore errors + } + }; + function hasTitleCategories() { + return window.document.querySelector(categorySelector) !== null; + } + + function offsetRelativeUrl(url) { + const offset = getMeta("quarto:offset"); + return offset ? offset + url : url; + } + + function offsetAbsoluteUrl(url) { + const offset = getMeta("quarto:offset"); + const baseUrl = new URL(offset, window.location); + + const projRelativeUrl = url.replace(baseUrl, ""); + if (projRelativeUrl.startsWith("/")) { + return projRelativeUrl; + } else { + return "/" + projRelativeUrl; + } + } + + // read a meta tag value + function getMeta(metaName) { + const metas = window.document.getElementsByTagName("meta"); + for (let i = 0; i < metas.length; i++) { + if (metas[i].getAttribute("name") === metaName) { + return metas[i].getAttribute("content"); + } + } + return ""; + } + + async function findAndActivateCategories() { + const currentPagePath = offsetAbsoluteUrl(window.location.href); + const response = await fetch(offsetRelativeUrl("listings.json")); + if (response.status == 200) { + return response.json().then(function (listingPaths) { + const listingHrefs = []; + for (const listingPath of listingPaths) { + const pathWithoutLeadingSlash = listingPath.listing.substring(1); + for (const item of listingPath.items) { + if ( + item === currentPagePath || + item === currentPagePath + "index.html" + ) { + // Resolve this path against the offset to be sure + // we already are using the correct path to the listing + // (this adjusts the listing urls to be rooted against + // whatever root the page is actually running against) + const relative = offsetRelativeUrl(pathWithoutLeadingSlash); + const baseUrl = window.location; + const resolvedPath = new URL(relative, baseUrl); + listingHrefs.push(resolvedPath.pathname); + break; + } + } + } + + // Look up the tree for a nearby linting and use that if we find one + const nearestListing = findNearestParentListing( + offsetAbsoluteUrl(window.location.pathname), + listingHrefs + ); + if (nearestListing) { + activateCategories(nearestListing); + } else { + // See if the referrer is a listing page for this item + const referredRelativePath = offsetAbsoluteUrl(document.referrer); + const referrerListing = listingHrefs.find((listingHref) => { + const isListingReferrer = + listingHref === referredRelativePath || + listingHref === referredRelativePath + "index.html"; + return isListingReferrer; + }); + + if (referrerListing) { + // Try to use the referrer if possible + activateCategories(referrerListing); + } else if (listingHrefs.length > 0) { + // Otherwise, just fall back to the first listing + activateCategories(listingHrefs[0]); + } + } + }); + } + } + if (hasTitleCategories()) { + findAndActivateCategories(); + } + + const findNearestParentListing = (href, listingHrefs) => { + if (!href || !listingHrefs) { + return undefined; + } + // Look up the tree for a nearby linting and use that if we find one + const relativeParts = href.substring(1).split("/"); + while (relativeParts.length > 0) { + const path = relativeParts.join("/"); + for (const listingHref of listingHrefs) { + if (listingHref.startsWith(path)) { + return listingHref; + } + } + relativeParts.pop(); + } + + return undefined; + }; + + const manageSidebarVisiblity = (el, placeholderDescriptor) => { + let isVisible = true; + let elRect; + + return (hiddenRegions) => { + if (el === null) { + return; + } + + // Find the last element of the TOC + const lastChildEl = el.lastElementChild; + + if (lastChildEl) { + // Converts the sidebar to a menu + const convertToMenu = () => { + for (const child of el.children) { + child.style.opacity = 0; + child.style.overflow = "hidden"; + child.style.pointerEvents = "none"; + } + + nexttick(() => { + const toggleContainer = window.document.createElement("div"); + toggleContainer.style.width = "100%"; + toggleContainer.classList.add("zindex-over-content"); + toggleContainer.classList.add("quarto-sidebar-toggle"); + toggleContainer.classList.add("headroom-target"); // Marks this to be managed by headeroom + toggleContainer.id = placeholderDescriptor.id; + toggleContainer.style.position = "fixed"; + + const toggleIcon = window.document.createElement("i"); + toggleIcon.classList.add("quarto-sidebar-toggle-icon"); + toggleIcon.classList.add("bi"); + toggleIcon.classList.add("bi-caret-down-fill"); + + const toggleTitle = window.document.createElement("div"); + const titleEl = window.document.body.querySelector( + placeholderDescriptor.titleSelector + ); + if (titleEl) { + toggleTitle.append( + titleEl.textContent || titleEl.innerText, + toggleIcon + ); + } + toggleTitle.classList.add("zindex-over-content"); + toggleTitle.classList.add("quarto-sidebar-toggle-title"); + toggleContainer.append(toggleTitle); + + const toggleContents = window.document.createElement("div"); + toggleContents.classList = el.classList; + toggleContents.classList.add("zindex-over-content"); + toggleContents.classList.add("quarto-sidebar-toggle-contents"); + for (const child of el.children) { + if (child.id === "toc-title") { + continue; + } + + const clone = child.cloneNode(true); + clone.style.opacity = 1; + clone.style.pointerEvents = null; + clone.style.display = null; + toggleContents.append(clone); + } + toggleContents.style.height = "0px"; + const positionToggle = () => { + // position the element (top left of parent, same width as parent) + if (!elRect) { + elRect = el.getBoundingClientRect(); + } + toggleContainer.style.left = `${elRect.left}px`; + toggleContainer.style.top = `${elRect.top}px`; + toggleContainer.style.width = `${elRect.width}px`; + }; + positionToggle(); + + toggleContainer.append(toggleContents); + el.parentElement.prepend(toggleContainer); + + // Process clicks + let tocShowing = false; + // Allow the caller to control whether this is dismissed + // when it is clicked (e.g. sidebar navigation supports + // opening and closing the nav tree, so don't dismiss on click) + const clickEl = placeholderDescriptor.dismissOnClick + ? toggleContainer + : toggleTitle; + + const closeToggle = () => { + if (tocShowing) { + toggleContainer.classList.remove("expanded"); + toggleContents.style.height = "0px"; + tocShowing = false; + } + }; + + // Get rid of any expanded toggle if the user scrolls + window.document.addEventListener( + "scroll", + throttle(() => { + closeToggle(); + }, 50) + ); + + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + positionToggle(); + }, 50) + ); + + window.addEventListener("quarto-hrChanged", () => { + elRect = undefined; + }); + + // Process the click + clickEl.onclick = () => { + if (!tocShowing) { + toggleContainer.classList.add("expanded"); + toggleContents.style.height = null; + tocShowing = true; + } else { + closeToggle(); + } + }; + }); + }; + + // Converts a sidebar from a menu back to a sidebar + const convertToSidebar = () => { + for (const child of el.children) { + child.style.opacity = 1; + child.style.overflow = null; + child.style.pointerEvents = null; + } + + const placeholderEl = window.document.getElementById( + placeholderDescriptor.id + ); + if (placeholderEl) { + placeholderEl.remove(); + } + + el.classList.remove("rollup"); + }; + + if (isReaderMode()) { + convertToMenu(); + isVisible = false; + } else { + // Find the top and bottom o the element that is being managed + const elTop = el.offsetTop; + const elBottom = + elTop + lastChildEl.offsetTop + lastChildEl.offsetHeight; + + if (!isVisible) { + // If the element is current not visible reveal if there are + // no conflicts with overlay regions + if (!inHiddenRegion(elTop, elBottom, hiddenRegions)) { + convertToSidebar(); + isVisible = true; + } + } else { + // If the element is visible, hide it if it conflicts with overlay regions + // and insert a placeholder toggle (or if we're in reader mode) + if (inHiddenRegion(elTop, elBottom, hiddenRegions)) { + convertToMenu(); + isVisible = false; + } + } + } + } + }; + }; + + const tabEls = document.querySelectorAll('a[data-bs-toggle="tab"]'); + for (const tabEl of tabEls) { + const id = tabEl.getAttribute("data-bs-target"); + if (id) { + const columnEl = document.querySelector( + `${id} .column-margin, .tabset-margin-content` + ); + if (columnEl) + tabEl.addEventListener("shown.bs.tab", function (event) { + const el = event.srcElement; + if (el) { + const visibleCls = `${el.id}-margin-content`; + // walk up until we find a parent tabset + let panelTabsetEl = el.parentElement; + while (panelTabsetEl) { + if (panelTabsetEl.classList.contains("panel-tabset")) { + break; + } + panelTabsetEl = panelTabsetEl.parentElement; + } + + if (panelTabsetEl) { + const prevSib = panelTabsetEl.previousElementSibling; + if ( + prevSib && + prevSib.classList.contains("tabset-margin-container") + ) { + const childNodes = prevSib.querySelectorAll( + ".tabset-margin-content" + ); + for (const childEl of childNodes) { + if (childEl.classList.contains(visibleCls)) { + childEl.classList.remove("collapse"); + } else { + childEl.classList.add("collapse"); + } + } + } + } + } + + layoutMarginEls(); + }); + } + } + + // Manage the visibility of the toc and the sidebar + const marginScrollVisibility = manageSidebarVisiblity(marginSidebarEl, { + id: "quarto-toc-toggle", + titleSelector: "#toc-title", + dismissOnClick: true, + }); + const sidebarScrollVisiblity = manageSidebarVisiblity(sidebarEl, { + id: "quarto-sidebarnav-toggle", + titleSelector: ".title", + dismissOnClick: false, + }); + let tocLeftScrollVisibility; + if (leftTocEl) { + tocLeftScrollVisibility = manageSidebarVisiblity(leftTocEl, { + id: "quarto-lefttoc-toggle", + titleSelector: "#toc-title", + dismissOnClick: true, + }); + } + + // Find the first element that uses formatting in special columns + const conflictingEls = window.document.body.querySelectorAll( + '[class^="column-"], [class*=" column-"], aside, [class*="margin-caption"], [class*=" margin-caption"], [class*="margin-ref"], [class*=" margin-ref"]' + ); + + // Filter all the possibly conflicting elements into ones + // the do conflict on the left or ride side + const arrConflictingEls = Array.from(conflictingEls); + const leftSideConflictEls = arrConflictingEls.filter((el) => { + if (el.tagName === "ASIDE") { + return false; + } + return Array.from(el.classList).find((className) => { + return ( + className !== "column-body" && + className.startsWith("column-") && + !className.endsWith("right") && + !className.endsWith("container") && + className !== "column-margin" + ); + }); + }); + const rightSideConflictEls = arrConflictingEls.filter((el) => { + if (el.tagName === "ASIDE") { + return true; + } + + const hasMarginCaption = Array.from(el.classList).find((className) => { + return className == "margin-caption"; + }); + if (hasMarginCaption) { + return true; + } + + return Array.from(el.classList).find((className) => { + return ( + className !== "column-body" && + !className.endsWith("container") && + className.startsWith("column-") && + !className.endsWith("left") + ); + }); + }); + + const kOverlapPaddingSize = 10; + function toRegions(els) { + return els.map((el) => { + const boundRect = el.getBoundingClientRect(); + const top = + boundRect.top + + document.documentElement.scrollTop - + kOverlapPaddingSize; + return { + top, + bottom: top + el.scrollHeight + 2 * kOverlapPaddingSize, + }; + }); + } + + let hasObserved = false; + const visibleItemObserver = (els) => { + let visibleElements = [...els]; + const intersectionObserver = new IntersectionObserver( + (entries, _observer) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + if (visibleElements.indexOf(entry.target) === -1) { + visibleElements.push(entry.target); + } + } else { + visibleElements = visibleElements.filter((visibleEntry) => { + return visibleEntry !== entry; + }); + } + }); + + if (!hasObserved) { + hideOverlappedSidebars(); + } + hasObserved = true; + }, + {} + ); + els.forEach((el) => { + intersectionObserver.observe(el); + }); + + return { + getVisibleEntries: () => { + return visibleElements; + }, + }; + }; + + const rightElementObserver = visibleItemObserver(rightSideConflictEls); + const leftElementObserver = visibleItemObserver(leftSideConflictEls); + + const hideOverlappedSidebars = () => { + marginScrollVisibility(toRegions(rightElementObserver.getVisibleEntries())); + sidebarScrollVisiblity(toRegions(leftElementObserver.getVisibleEntries())); + if (tocLeftScrollVisibility) { + tocLeftScrollVisibility( + toRegions(leftElementObserver.getVisibleEntries()) + ); + } + }; + + window.quartoToggleReader = () => { + // Applies a slow class (or removes it) + // to update the transition speed + const slowTransition = (slow) => { + const manageTransition = (id, slow) => { + const el = document.getElementById(id); + if (el) { + if (slow) { + el.classList.add("slow"); + } else { + el.classList.remove("slow"); + } + } + }; + + manageTransition("TOC", slow); + manageTransition("quarto-sidebar", slow); + }; + const readerMode = !isReaderMode(); + setReaderModeValue(readerMode); + + // If we're entering reader mode, slow the transition + if (readerMode) { + slowTransition(readerMode); + } + highlightReaderToggle(readerMode); + hideOverlappedSidebars(); + + // If we're exiting reader mode, restore the non-slow transition + if (!readerMode) { + slowTransition(!readerMode); + } + }; + + const highlightReaderToggle = (readerMode) => { + const els = document.querySelectorAll(".quarto-reader-toggle"); + if (els) { + els.forEach((el) => { + if (readerMode) { + el.classList.add("reader"); + } else { + el.classList.remove("reader"); + } + }); + } + }; + + const setReaderModeValue = (val) => { + if (window.location.protocol !== "file:") { + window.localStorage.setItem("quarto-reader-mode", val); + } else { + localReaderMode = val; + } + }; + + const isReaderMode = () => { + if (window.location.protocol !== "file:") { + return window.localStorage.getItem("quarto-reader-mode") === "true"; + } else { + return localReaderMode; + } + }; + let localReaderMode = null; + + const tocOpenDepthStr = tocEl?.getAttribute("data-toc-expanded"); + const tocOpenDepth = tocOpenDepthStr ? Number(tocOpenDepthStr) : 1; + + // Walk the TOC and collapse/expand nodes + // Nodes are expanded if: + // - they are top level + // - they have children that are 'active' links + // - they are directly below an link that is 'active' + const walk = (el, depth) => { + // Tick depth when we enter a UL + if (el.tagName === "UL") { + depth = depth + 1; + } + + // It this is active link + let isActiveNode = false; + if (el.tagName === "A" && el.classList.contains("active")) { + isActiveNode = true; + } + + // See if there is an active child to this element + let hasActiveChild = false; + for (child of el.children) { + hasActiveChild = walk(child, depth) || hasActiveChild; + } + + // Process the collapse state if this is an UL + if (el.tagName === "UL") { + if (tocOpenDepth === -1 && depth > 1) { + // toc-expand: false + el.classList.add("collapse"); + } else if ( + depth <= tocOpenDepth || + hasActiveChild || + prevSiblingIsActiveLink(el) + ) { + el.classList.remove("collapse"); + } else { + el.classList.add("collapse"); + } + + // untick depth when we leave a UL + depth = depth - 1; + } + return hasActiveChild || isActiveNode; + }; + + // walk the TOC and expand / collapse any items that should be shown + if (tocEl) { + updateActiveLink(); + walk(tocEl, 0); + } + + // Throttle the scroll event and walk peridiocally + window.document.addEventListener( + "scroll", + throttle(() => { + if (tocEl) { + updateActiveLink(); + walk(tocEl, 0); + } + if (!isReaderMode()) { + hideOverlappedSidebars(); + } + }, 5) + ); + window.addEventListener( + "resize", + throttle(() => { + if (tocEl) { + updateActiveLink(); + walk(tocEl, 0); + } + if (!isReaderMode()) { + hideOverlappedSidebars(); + } + }, 10) + ); + hideOverlappedSidebars(); + highlightReaderToggle(isReaderMode()); +}); + +// grouped tabsets +window.addEventListener("pageshow", (_event) => { + function getTabSettings() { + const data = localStorage.getItem("quarto-persistent-tabsets-data"); + if (!data) { + localStorage.setItem("quarto-persistent-tabsets-data", "{}"); + return {}; + } + if (data) { + return JSON.parse(data); + } + } + + function setTabSettings(data) { + localStorage.setItem( + "quarto-persistent-tabsets-data", + JSON.stringify(data) + ); + } + + function setTabState(groupName, groupValue) { + const data = getTabSettings(); + data[groupName] = groupValue; + setTabSettings(data); + } + + function toggleTab(tab, active) { + const tabPanelId = tab.getAttribute("aria-controls"); + const tabPanel = document.getElementById(tabPanelId); + if (active) { + tab.classList.add("active"); + tabPanel.classList.add("active"); + } else { + tab.classList.remove("active"); + tabPanel.classList.remove("active"); + } + } + + function toggleAll(selectedGroup, selectorsToSync) { + for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) { + const active = selectedGroup === thisGroup; + for (const tab of tabs) { + toggleTab(tab, active); + } + } + } + + function findSelectorsToSyncByLanguage() { + const result = {}; + const tabs = Array.from( + document.querySelectorAll(`div[data-group] a[id^='tabset-']`) + ); + for (const item of tabs) { + const div = item.parentElement.parentElement.parentElement; + const group = div.getAttribute("data-group"); + if (!result[group]) { + result[group] = {}; + } + const selectorsToSync = result[group]; + const value = item.innerHTML; + if (!selectorsToSync[value]) { + selectorsToSync[value] = []; + } + selectorsToSync[value].push(item); + } + return result; + } + + function setupSelectorSync() { + const selectorsToSync = findSelectorsToSyncByLanguage(); + Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => { + Object.entries(tabSetsByValue).forEach(([value, items]) => { + items.forEach((item) => { + item.addEventListener("click", (_event) => { + setTabState(group, value); + toggleAll(value, selectorsToSync[group]); + }); + }); + }); + }); + return selectorsToSync; + } + + const selectorsToSync = setupSelectorSync(); + for (const [group, selectedName] of Object.entries(getTabSettings())) { + const selectors = selectorsToSync[group]; + // it's possible that stale state gives us empty selections, so we explicitly check here. + if (selectors) { + toggleAll(selectedName, selectors); + } + } +}); + +function throttle(func, wait) { + let waiting = false; + return function () { + if (!waiting) { + func.apply(this, arguments); + waiting = true; + setTimeout(function () { + waiting = false; + }, wait); + } + }; +} + +function nexttick(func) { + return setTimeout(func, 0); +} diff --git a/site_libs/quarto-html/tippy.css b/site_libs/quarto-html/tippy.css new file mode 100644 index 0000000..e6ae635 --- /dev/null +++ b/site_libs/quarto-html/tippy.css @@ -0,0 +1 @@ +.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1} \ No newline at end of file diff --git a/site_libs/quarto-html/tippy.umd.min.js b/site_libs/quarto-html/tippy.umd.min.js new file mode 100644 index 0000000..ca292be --- /dev/null +++ b/site_libs/quarto-html/tippy.umd.min.js @@ -0,0 +1,2 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],t):(e=e||self).tippy=t(e.Popper)}(this,(function(e){"use strict";var t={passive:!0,capture:!0},n=function(){return document.body};function r(e,t,n){if(Array.isArray(e)){var r=e[t];return null==r?Array.isArray(n)?n[t]:n:r}return e}function o(e,t){var n={}.toString.call(e);return 0===n.indexOf("[object")&&n.indexOf(t+"]")>-1}function i(e,t){return"function"==typeof e?e.apply(void 0,t):e}function a(e,t){return 0===t?e:function(r){clearTimeout(n),n=setTimeout((function(){e(r)}),t)};var n}function s(e,t){var n=Object.assign({},e);return t.forEach((function(e){delete n[e]})),n}function u(e){return[].concat(e)}function c(e,t){-1===e.indexOf(t)&&e.push(t)}function p(e){return e.split("-")[0]}function f(e){return[].slice.call(e)}function l(e){return Object.keys(e).reduce((function(t,n){return void 0!==e[n]&&(t[n]=e[n]),t}),{})}function d(){return document.createElement("div")}function v(e){return["Element","Fragment"].some((function(t){return o(e,t)}))}function m(e){return o(e,"MouseEvent")}function g(e){return!(!e||!e._tippy||e._tippy.reference!==e)}function h(e){return v(e)?[e]:function(e){return o(e,"NodeList")}(e)?f(e):Array.isArray(e)?e:f(document.querySelectorAll(e))}function b(e,t){e.forEach((function(e){e&&(e.style.transitionDuration=t+"ms")}))}function y(e,t){e.forEach((function(e){e&&e.setAttribute("data-state",t)}))}function w(e){var t,n=u(e)[0];return null!=n&&null!=(t=n.ownerDocument)&&t.body?n.ownerDocument:document}function E(e,t,n){var r=t+"EventListener";["transitionend","webkitTransitionEnd"].forEach((function(t){e[r](t,n)}))}function O(e,t){for(var n=t;n;){var r;if(e.contains(n))return!0;n=null==n.getRootNode||null==(r=n.getRootNode())?void 0:r.host}return!1}var x={isTouch:!1},C=0;function T(){x.isTouch||(x.isTouch=!0,window.performance&&document.addEventListener("mousemove",A))}function A(){var e=performance.now();e-C<20&&(x.isTouch=!1,document.removeEventListener("mousemove",A)),C=e}function L(){var e=document.activeElement;if(g(e)){var t=e._tippy;e.blur&&!t.state.isVisible&&e.blur()}}var D=!!("undefined"!=typeof window&&"undefined"!=typeof document)&&!!window.msCrypto,R=Object.assign({appendTo:n,aria:{content:"auto",expanded:"auto"},delay:0,duration:[300,250],getReferenceClientRect:null,hideOnClick:!0,ignoreAttributes:!1,interactive:!1,interactiveBorder:2,interactiveDebounce:0,moveTransition:"",offset:[0,10],onAfterUpdate:function(){},onBeforeUpdate:function(){},onCreate:function(){},onDestroy:function(){},onHidden:function(){},onHide:function(){},onMount:function(){},onShow:function(){},onShown:function(){},onTrigger:function(){},onUntrigger:function(){},onClickOutside:function(){},placement:"top",plugins:[],popperOptions:{},render:null,showOnCreate:!1,touch:!0,trigger:"mouseenter focus",triggerTarget:null},{animateFill:!1,followCursor:!1,inlinePositioning:!1,sticky:!1},{allowHTML:!1,animation:"fade",arrow:!0,content:"",inertia:!1,maxWidth:350,role:"tooltip",theme:"",zIndex:9999}),k=Object.keys(R);function P(e){var t=(e.plugins||[]).reduce((function(t,n){var r,o=n.name,i=n.defaultValue;o&&(t[o]=void 0!==e[o]?e[o]:null!=(r=R[o])?r:i);return t}),{});return Object.assign({},e,t)}function j(e,t){var n=Object.assign({},t,{content:i(t.content,[e])},t.ignoreAttributes?{}:function(e,t){return(t?Object.keys(P(Object.assign({},R,{plugins:t}))):k).reduce((function(t,n){var r=(e.getAttribute("data-tippy-"+n)||"").trim();if(!r)return t;if("content"===n)t[n]=r;else try{t[n]=JSON.parse(r)}catch(e){t[n]=r}return t}),{})}(e,t.plugins));return n.aria=Object.assign({},R.aria,n.aria),n.aria={expanded:"auto"===n.aria.expanded?t.interactive:n.aria.expanded,content:"auto"===n.aria.content?t.interactive?null:"describedby":n.aria.content},n}function M(e,t){e.innerHTML=t}function V(e){var t=d();return!0===e?t.className="tippy-arrow":(t.className="tippy-svg-arrow",v(e)?t.appendChild(e):M(t,e)),t}function I(e,t){v(t.content)?(M(e,""),e.appendChild(t.content)):"function"!=typeof t.content&&(t.allowHTML?M(e,t.content):e.textContent=t.content)}function S(e){var t=e.firstElementChild,n=f(t.children);return{box:t,content:n.find((function(e){return e.classList.contains("tippy-content")})),arrow:n.find((function(e){return e.classList.contains("tippy-arrow")||e.classList.contains("tippy-svg-arrow")})),backdrop:n.find((function(e){return e.classList.contains("tippy-backdrop")}))}}function N(e){var t=d(),n=d();n.className="tippy-box",n.setAttribute("data-state","hidden"),n.setAttribute("tabindex","-1");var r=d();function o(n,r){var o=S(t),i=o.box,a=o.content,s=o.arrow;r.theme?i.setAttribute("data-theme",r.theme):i.removeAttribute("data-theme"),"string"==typeof r.animation?i.setAttribute("data-animation",r.animation):i.removeAttribute("data-animation"),r.inertia?i.setAttribute("data-inertia",""):i.removeAttribute("data-inertia"),i.style.maxWidth="number"==typeof r.maxWidth?r.maxWidth+"px":r.maxWidth,r.role?i.setAttribute("role",r.role):i.removeAttribute("role"),n.content===r.content&&n.allowHTML===r.allowHTML||I(a,e.props),r.arrow?s?n.arrow!==r.arrow&&(i.removeChild(s),i.appendChild(V(r.arrow))):i.appendChild(V(r.arrow)):s&&i.removeChild(s)}return r.className="tippy-content",r.setAttribute("data-state","hidden"),I(r,e.props),t.appendChild(n),n.appendChild(r),o(e.props,e.props),{popper:t,onUpdate:o}}N.$$tippy=!0;var B=1,H=[],U=[];function _(o,s){var v,g,h,C,T,A,L,k,M=j(o,Object.assign({},R,P(l(s)))),V=!1,I=!1,N=!1,_=!1,F=[],W=a(we,M.interactiveDebounce),X=B++,Y=(k=M.plugins).filter((function(e,t){return k.indexOf(e)===t})),$={id:X,reference:o,popper:d(),popperInstance:null,props:M,state:{isEnabled:!0,isVisible:!1,isDestroyed:!1,isMounted:!1,isShown:!1},plugins:Y,clearDelayTimeouts:function(){clearTimeout(v),clearTimeout(g),cancelAnimationFrame(h)},setProps:function(e){if($.state.isDestroyed)return;ae("onBeforeUpdate",[$,e]),be();var t=$.props,n=j(o,Object.assign({},t,l(e),{ignoreAttributes:!0}));$.props=n,he(),t.interactiveDebounce!==n.interactiveDebounce&&(ce(),W=a(we,n.interactiveDebounce));t.triggerTarget&&!n.triggerTarget?u(t.triggerTarget).forEach((function(e){e.removeAttribute("aria-expanded")})):n.triggerTarget&&o.removeAttribute("aria-expanded");ue(),ie(),J&&J(t,n);$.popperInstance&&(Ce(),Ae().forEach((function(e){requestAnimationFrame(e._tippy.popperInstance.forceUpdate)})));ae("onAfterUpdate",[$,e])},setContent:function(e){$.setProps({content:e})},show:function(){var e=$.state.isVisible,t=$.state.isDestroyed,o=!$.state.isEnabled,a=x.isTouch&&!$.props.touch,s=r($.props.duration,0,R.duration);if(e||t||o||a)return;if(te().hasAttribute("disabled"))return;if(ae("onShow",[$],!1),!1===$.props.onShow($))return;$.state.isVisible=!0,ee()&&(z.style.visibility="visible");ie(),de(),$.state.isMounted||(z.style.transition="none");if(ee()){var u=re(),p=u.box,f=u.content;b([p,f],0)}A=function(){var e;if($.state.isVisible&&!_){if(_=!0,z.offsetHeight,z.style.transition=$.props.moveTransition,ee()&&$.props.animation){var t=re(),n=t.box,r=t.content;b([n,r],s),y([n,r],"visible")}se(),ue(),c(U,$),null==(e=$.popperInstance)||e.forceUpdate(),ae("onMount",[$]),$.props.animation&&ee()&&function(e,t){me(e,t)}(s,(function(){$.state.isShown=!0,ae("onShown",[$])}))}},function(){var e,t=$.props.appendTo,r=te();e=$.props.interactive&&t===n||"parent"===t?r.parentNode:i(t,[r]);e.contains(z)||e.appendChild(z);$.state.isMounted=!0,Ce()}()},hide:function(){var e=!$.state.isVisible,t=$.state.isDestroyed,n=!$.state.isEnabled,o=r($.props.duration,1,R.duration);if(e||t||n)return;if(ae("onHide",[$],!1),!1===$.props.onHide($))return;$.state.isVisible=!1,$.state.isShown=!1,_=!1,V=!1,ee()&&(z.style.visibility="hidden");if(ce(),ve(),ie(!0),ee()){var i=re(),a=i.box,s=i.content;$.props.animation&&(b([a,s],o),y([a,s],"hidden"))}se(),ue(),$.props.animation?ee()&&function(e,t){me(e,(function(){!$.state.isVisible&&z.parentNode&&z.parentNode.contains(z)&&t()}))}(o,$.unmount):$.unmount()},hideWithInteractivity:function(e){ne().addEventListener("mousemove",W),c(H,W),W(e)},enable:function(){$.state.isEnabled=!0},disable:function(){$.hide(),$.state.isEnabled=!1},unmount:function(){$.state.isVisible&&$.hide();if(!$.state.isMounted)return;Te(),Ae().forEach((function(e){e._tippy.unmount()})),z.parentNode&&z.parentNode.removeChild(z);U=U.filter((function(e){return e!==$})),$.state.isMounted=!1,ae("onHidden",[$])},destroy:function(){if($.state.isDestroyed)return;$.clearDelayTimeouts(),$.unmount(),be(),delete o._tippy,$.state.isDestroyed=!0,ae("onDestroy",[$])}};if(!M.render)return $;var q=M.render($),z=q.popper,J=q.onUpdate;z.setAttribute("data-tippy-root",""),z.id="tippy-"+$.id,$.popper=z,o._tippy=$,z._tippy=$;var G=Y.map((function(e){return e.fn($)})),K=o.hasAttribute("aria-expanded");return he(),ue(),ie(),ae("onCreate",[$]),M.showOnCreate&&Le(),z.addEventListener("mouseenter",(function(){$.props.interactive&&$.state.isVisible&&$.clearDelayTimeouts()})),z.addEventListener("mouseleave",(function(){$.props.interactive&&$.props.trigger.indexOf("mouseenter")>=0&&ne().addEventListener("mousemove",W)})),$;function Q(){var e=$.props.touch;return Array.isArray(e)?e:[e,0]}function Z(){return"hold"===Q()[0]}function ee(){var e;return!(null==(e=$.props.render)||!e.$$tippy)}function te(){return L||o}function ne(){var e=te().parentNode;return e?w(e):document}function re(){return S(z)}function oe(e){return $.state.isMounted&&!$.state.isVisible||x.isTouch||C&&"focus"===C.type?0:r($.props.delay,e?0:1,R.delay)}function ie(e){void 0===e&&(e=!1),z.style.pointerEvents=$.props.interactive&&!e?"":"none",z.style.zIndex=""+$.props.zIndex}function ae(e,t,n){var r;(void 0===n&&(n=!0),G.forEach((function(n){n[e]&&n[e].apply(n,t)})),n)&&(r=$.props)[e].apply(r,t)}function se(){var e=$.props.aria;if(e.content){var t="aria-"+e.content,n=z.id;u($.props.triggerTarget||o).forEach((function(e){var r=e.getAttribute(t);if($.state.isVisible)e.setAttribute(t,r?r+" "+n:n);else{var o=r&&r.replace(n,"").trim();o?e.setAttribute(t,o):e.removeAttribute(t)}}))}}function ue(){!K&&$.props.aria.expanded&&u($.props.triggerTarget||o).forEach((function(e){$.props.interactive?e.setAttribute("aria-expanded",$.state.isVisible&&e===te()?"true":"false"):e.removeAttribute("aria-expanded")}))}function ce(){ne().removeEventListener("mousemove",W),H=H.filter((function(e){return e!==W}))}function pe(e){if(!x.isTouch||!N&&"mousedown"!==e.type){var t=e.composedPath&&e.composedPath()[0]||e.target;if(!$.props.interactive||!O(z,t)){if(u($.props.triggerTarget||o).some((function(e){return O(e,t)}))){if(x.isTouch)return;if($.state.isVisible&&$.props.trigger.indexOf("click")>=0)return}else ae("onClickOutside",[$,e]);!0===$.props.hideOnClick&&($.clearDelayTimeouts(),$.hide(),I=!0,setTimeout((function(){I=!1})),$.state.isMounted||ve())}}}function fe(){N=!0}function le(){N=!1}function de(){var e=ne();e.addEventListener("mousedown",pe,!0),e.addEventListener("touchend",pe,t),e.addEventListener("touchstart",le,t),e.addEventListener("touchmove",fe,t)}function ve(){var e=ne();e.removeEventListener("mousedown",pe,!0),e.removeEventListener("touchend",pe,t),e.removeEventListener("touchstart",le,t),e.removeEventListener("touchmove",fe,t)}function me(e,t){var n=re().box;function r(e){e.target===n&&(E(n,"remove",r),t())}if(0===e)return t();E(n,"remove",T),E(n,"add",r),T=r}function ge(e,t,n){void 0===n&&(n=!1),u($.props.triggerTarget||o).forEach((function(r){r.addEventListener(e,t,n),F.push({node:r,eventType:e,handler:t,options:n})}))}function he(){var e;Z()&&(ge("touchstart",ye,{passive:!0}),ge("touchend",Ee,{passive:!0})),(e=$.props.trigger,e.split(/\s+/).filter(Boolean)).forEach((function(e){if("manual"!==e)switch(ge(e,ye),e){case"mouseenter":ge("mouseleave",Ee);break;case"focus":ge(D?"focusout":"blur",Oe);break;case"focusin":ge("focusout",Oe)}}))}function be(){F.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),F=[]}function ye(e){var t,n=!1;if($.state.isEnabled&&!xe(e)&&!I){var r="focus"===(null==(t=C)?void 0:t.type);C=e,L=e.currentTarget,ue(),!$.state.isVisible&&m(e)&&H.forEach((function(t){return t(e)})),"click"===e.type&&($.props.trigger.indexOf("mouseenter")<0||V)&&!1!==$.props.hideOnClick&&$.state.isVisible?n=!0:Le(e),"click"===e.type&&(V=!n),n&&!r&&De(e)}}function we(e){var t=e.target,n=te().contains(t)||z.contains(t);"mousemove"===e.type&&n||function(e,t){var n=t.clientX,r=t.clientY;return e.every((function(e){var t=e.popperRect,o=e.popperState,i=e.props.interactiveBorder,a=p(o.placement),s=o.modifiersData.offset;if(!s)return!0;var u="bottom"===a?s.top.y:0,c="top"===a?s.bottom.y:0,f="right"===a?s.left.x:0,l="left"===a?s.right.x:0,d=t.top-r+u>i,v=r-t.bottom-c>i,m=t.left-n+f>i,g=n-t.right-l>i;return d||v||m||g}))}(Ae().concat(z).map((function(e){var t,n=null==(t=e._tippy.popperInstance)?void 0:t.state;return n?{popperRect:e.getBoundingClientRect(),popperState:n,props:M}:null})).filter(Boolean),e)&&(ce(),De(e))}function Ee(e){xe(e)||$.props.trigger.indexOf("click")>=0&&V||($.props.interactive?$.hideWithInteractivity(e):De(e))}function Oe(e){$.props.trigger.indexOf("focusin")<0&&e.target!==te()||$.props.interactive&&e.relatedTarget&&z.contains(e.relatedTarget)||De(e)}function xe(e){return!!x.isTouch&&Z()!==e.type.indexOf("touch")>=0}function Ce(){Te();var t=$.props,n=t.popperOptions,r=t.placement,i=t.offset,a=t.getReferenceClientRect,s=t.moveTransition,u=ee()?S(z).arrow:null,c=a?{getBoundingClientRect:a,contextElement:a.contextElement||te()}:o,p=[{name:"offset",options:{offset:i}},{name:"preventOverflow",options:{padding:{top:2,bottom:2,left:5,right:5}}},{name:"flip",options:{padding:5}},{name:"computeStyles",options:{adaptive:!s}},{name:"$$tippy",enabled:!0,phase:"beforeWrite",requires:["computeStyles"],fn:function(e){var t=e.state;if(ee()){var n=re().box;["placement","reference-hidden","escaped"].forEach((function(e){"placement"===e?n.setAttribute("data-placement",t.placement):t.attributes.popper["data-popper-"+e]?n.setAttribute("data-"+e,""):n.removeAttribute("data-"+e)})),t.attributes.popper={}}}}];ee()&&u&&p.push({name:"arrow",options:{element:u,padding:3}}),p.push.apply(p,(null==n?void 0:n.modifiers)||[]),$.popperInstance=e.createPopper(c,z,Object.assign({},n,{placement:r,onFirstUpdate:A,modifiers:p}))}function Te(){$.popperInstance&&($.popperInstance.destroy(),$.popperInstance=null)}function Ae(){return f(z.querySelectorAll("[data-tippy-root]"))}function Le(e){$.clearDelayTimeouts(),e&&ae("onTrigger",[$,e]),de();var t=oe(!0),n=Q(),r=n[0],o=n[1];x.isTouch&&"hold"===r&&o&&(t=o),t?v=setTimeout((function(){$.show()}),t):$.show()}function De(e){if($.clearDelayTimeouts(),ae("onUntrigger",[$,e]),$.state.isVisible){if(!($.props.trigger.indexOf("mouseenter")>=0&&$.props.trigger.indexOf("click")>=0&&["mouseleave","mousemove"].indexOf(e.type)>=0&&V)){var t=oe(!1);t?g=setTimeout((function(){$.state.isVisible&&$.hide()}),t):h=requestAnimationFrame((function(){$.hide()}))}}else ve()}}function F(e,n){void 0===n&&(n={});var r=R.plugins.concat(n.plugins||[]);document.addEventListener("touchstart",T,t),window.addEventListener("blur",L);var o=Object.assign({},n,{plugins:r}),i=h(e).reduce((function(e,t){var n=t&&_(t,o);return n&&e.push(n),e}),[]);return v(e)?i[0]:i}F.defaultProps=R,F.setDefaultProps=function(e){Object.keys(e).forEach((function(t){R[t]=e[t]}))},F.currentInput=x;var W=Object.assign({},e.applyStyles,{effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow)}}),X={mouseover:"mouseenter",focusin:"focus",click:"click"};var Y={name:"animateFill",defaultValue:!1,fn:function(e){var t;if(null==(t=e.props.render)||!t.$$tippy)return{};var n=S(e.popper),r=n.box,o=n.content,i=e.props.animateFill?function(){var e=d();return e.className="tippy-backdrop",y([e],"hidden"),e}():null;return{onCreate:function(){i&&(r.insertBefore(i,r.firstElementChild),r.setAttribute("data-animatefill",""),r.style.overflow="hidden",e.setProps({arrow:!1,animation:"shift-away"}))},onMount:function(){if(i){var e=r.style.transitionDuration,t=Number(e.replace("ms",""));o.style.transitionDelay=Math.round(t/10)+"ms",i.style.transitionDuration=e,y([i],"visible")}},onShow:function(){i&&(i.style.transitionDuration="0ms")},onHide:function(){i&&y([i],"hidden")}}}};var $={clientX:0,clientY:0},q=[];function z(e){var t=e.clientX,n=e.clientY;$={clientX:t,clientY:n}}var J={name:"followCursor",defaultValue:!1,fn:function(e){var t=e.reference,n=w(e.props.triggerTarget||t),r=!1,o=!1,i=!0,a=e.props;function s(){return"initial"===e.props.followCursor&&e.state.isVisible}function u(){n.addEventListener("mousemove",f)}function c(){n.removeEventListener("mousemove",f)}function p(){r=!0,e.setProps({getReferenceClientRect:null}),r=!1}function f(n){var r=!n.target||t.contains(n.target),o=e.props.followCursor,i=n.clientX,a=n.clientY,s=t.getBoundingClientRect(),u=i-s.left,c=a-s.top;!r&&e.props.interactive||e.setProps({getReferenceClientRect:function(){var e=t.getBoundingClientRect(),n=i,r=a;"initial"===o&&(n=e.left+u,r=e.top+c);var s="horizontal"===o?e.top:r,p="vertical"===o?e.right:n,f="horizontal"===o?e.bottom:r,l="vertical"===o?e.left:n;return{width:p-l,height:f-s,top:s,right:p,bottom:f,left:l}}})}function l(){e.props.followCursor&&(q.push({instance:e,doc:n}),function(e){e.addEventListener("mousemove",z)}(n))}function d(){0===(q=q.filter((function(t){return t.instance!==e}))).filter((function(e){return e.doc===n})).length&&function(e){e.removeEventListener("mousemove",z)}(n)}return{onCreate:l,onDestroy:d,onBeforeUpdate:function(){a=e.props},onAfterUpdate:function(t,n){var i=n.followCursor;r||void 0!==i&&a.followCursor!==i&&(d(),i?(l(),!e.state.isMounted||o||s()||u()):(c(),p()))},onMount:function(){e.props.followCursor&&!o&&(i&&(f($),i=!1),s()||u())},onTrigger:function(e,t){m(t)&&($={clientX:t.clientX,clientY:t.clientY}),o="focus"===t.type},onHidden:function(){e.props.followCursor&&(p(),c(),i=!0)}}}};var G={name:"inlinePositioning",defaultValue:!1,fn:function(e){var t,n=e.reference;var r=-1,o=!1,i=[],a={name:"tippyInlinePositioning",enabled:!0,phase:"afterWrite",fn:function(o){var a=o.state;e.props.inlinePositioning&&(-1!==i.indexOf(a.placement)&&(i=[]),t!==a.placement&&-1===i.indexOf(a.placement)&&(i.push(a.placement),e.setProps({getReferenceClientRect:function(){return function(e){return function(e,t,n,r){if(n.length<2||null===e)return t;if(2===n.length&&r>=0&&n[0].left>n[1].right)return n[r]||t;switch(e){case"top":case"bottom":var o=n[0],i=n[n.length-1],a="top"===e,s=o.top,u=i.bottom,c=a?o.left:i.left,p=a?o.right:i.right;return{top:s,bottom:u,left:c,right:p,width:p-c,height:u-s};case"left":case"right":var f=Math.min.apply(Math,n.map((function(e){return e.left}))),l=Math.max.apply(Math,n.map((function(e){return e.right}))),d=n.filter((function(t){return"left"===e?t.left===f:t.right===l})),v=d[0].top,m=d[d.length-1].bottom;return{top:v,bottom:m,left:f,right:l,width:l-f,height:m-v};default:return t}}(p(e),n.getBoundingClientRect(),f(n.getClientRects()),r)}(a.placement)}})),t=a.placement)}};function s(){var t;o||(t=function(e,t){var n;return{popperOptions:Object.assign({},e.popperOptions,{modifiers:[].concat(((null==(n=e.popperOptions)?void 0:n.modifiers)||[]).filter((function(e){return e.name!==t.name})),[t])})}}(e.props,a),o=!0,e.setProps(t),o=!1)}return{onCreate:s,onAfterUpdate:s,onTrigger:function(t,n){if(m(n)){var o=f(e.reference.getClientRects()),i=o.find((function(e){return e.left-2<=n.clientX&&e.right+2>=n.clientX&&e.top-2<=n.clientY&&e.bottom+2>=n.clientY})),a=o.indexOf(i);r=a>-1?a:r}},onHidden:function(){r=-1}}}};var K={name:"sticky",defaultValue:!1,fn:function(e){var t=e.reference,n=e.popper;function r(t){return!0===e.props.sticky||e.props.sticky===t}var o=null,i=null;function a(){var s=r("reference")?(e.popperInstance?e.popperInstance.state.elements.reference:t).getBoundingClientRect():null,u=r("popper")?n.getBoundingClientRect():null;(s&&Q(o,s)||u&&Q(i,u))&&e.popperInstance&&e.popperInstance.update(),o=s,i=u,e.state.isMounted&&requestAnimationFrame(a)}return{onMount:function(){e.props.sticky&&a()}}}};function Q(e,t){return!e||!t||(e.top!==t.top||e.right!==t.right||e.bottom!==t.bottom||e.left!==t.left)}return F.setDefaultProps({plugins:[Y,J,G,K],render:N}),F.createSingleton=function(e,t){var n;void 0===t&&(t={});var r,o=e,i=[],a=[],c=t.overrides,p=[],f=!1;function l(){a=o.map((function(e){return u(e.props.triggerTarget||e.reference)})).reduce((function(e,t){return e.concat(t)}),[])}function v(){i=o.map((function(e){return e.reference}))}function m(e){o.forEach((function(t){e?t.enable():t.disable()}))}function g(e){return o.map((function(t){var n=t.setProps;return t.setProps=function(o){n(o),t.reference===r&&e.setProps(o)},function(){t.setProps=n}}))}function h(e,t){var n=a.indexOf(t);if(t!==r){r=t;var s=(c||[]).concat("content").reduce((function(e,t){return e[t]=o[n].props[t],e}),{});e.setProps(Object.assign({},s,{getReferenceClientRect:"function"==typeof s.getReferenceClientRect?s.getReferenceClientRect:function(){var e;return null==(e=i[n])?void 0:e.getBoundingClientRect()}}))}}m(!1),v(),l();var b={fn:function(){return{onDestroy:function(){m(!0)},onHidden:function(){r=null},onClickOutside:function(e){e.props.showOnCreate&&!f&&(f=!0,r=null)},onShow:function(e){e.props.showOnCreate&&!f&&(f=!0,h(e,i[0]))},onTrigger:function(e,t){h(e,t.currentTarget)}}}},y=F(d(),Object.assign({},s(t,["overrides"]),{plugins:[b].concat(t.plugins||[]),triggerTarget:a,popperOptions:Object.assign({},t.popperOptions,{modifiers:[].concat((null==(n=t.popperOptions)?void 0:n.modifiers)||[],[W])})})),w=y.show;y.show=function(e){if(w(),!r&&null==e)return h(y,i[0]);if(!r||null!=e){if("number"==typeof e)return i[e]&&h(y,i[e]);if(o.indexOf(e)>=0){var t=e.reference;return h(y,t)}return i.indexOf(e)>=0?h(y,e):void 0}},y.showNext=function(){var e=i[0];if(!r)return y.show(0);var t=i.indexOf(r);y.show(i[t+1]||e)},y.showPrevious=function(){var e=i[i.length-1];if(!r)return y.show(e);var t=i.indexOf(r),n=i[t-1]||e;y.show(n)};var E=y.setProps;return y.setProps=function(e){c=e.overrides||c,E(e)},y.setInstances=function(e){m(!0),p.forEach((function(e){return e()})),o=e,m(!1),v(),l(),p=g(y),y.setProps({triggerTarget:a})},p=g(y),y},F.delegate=function(e,n){var r=[],o=[],i=!1,a=n.target,c=s(n,["target"]),p=Object.assign({},c,{trigger:"manual",touch:!1}),f=Object.assign({touch:R.touch},c,{showOnCreate:!0}),l=F(e,p);function d(e){if(e.target&&!i){var t=e.target.closest(a);if(t){var r=t.getAttribute("data-tippy-trigger")||n.trigger||R.trigger;if(!t._tippy&&!("touchstart"===e.type&&"boolean"==typeof f.touch||"touchstart"!==e.type&&r.indexOf(X[e.type])<0)){var s=F(t,f);s&&(o=o.concat(s))}}}}function v(e,t,n,o){void 0===o&&(o=!1),e.addEventListener(t,n,o),r.push({node:e,eventType:t,handler:n,options:o})}return u(l).forEach((function(e){var n=e.destroy,a=e.enable,s=e.disable;e.destroy=function(e){void 0===e&&(e=!0),e&&o.forEach((function(e){e.destroy()})),o=[],r.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),r=[],n()},e.enable=function(){a(),o.forEach((function(e){return e.enable()})),i=!1},e.disable=function(){s(),o.forEach((function(e){return e.disable()})),i=!0},function(e){var n=e.reference;v(n,"touchstart",d,t),v(n,"mouseover",d),v(n,"focusin",d),v(n,"click",d)}(e)})),l},F.hideAll=function(e){var t=void 0===e?{}:e,n=t.exclude,r=t.duration;U.forEach((function(e){var t=!1;if(n&&(t=g(n)?e.reference===n:e.popper===n.popper),!t){var o=e.props.duration;e.setProps({duration:r}),e.hide(),e.state.isDestroyed||e.setProps({duration:o})}}))},F.roundArrow='',F})); + diff --git a/site_libs/quarto-nav/headroom.min.js b/site_libs/quarto-nav/headroom.min.js new file mode 100644 index 0000000..b08f1df --- /dev/null +++ b/site_libs/quarto-nav/headroom.min.js @@ -0,0 +1,7 @@ +/*! + * headroom.js v0.12.0 - Give your page some headroom. Hide your header until you need it + * Copyright (c) 2020 Nick Williams - http://wicky.nillia.ms/headroom.js + * License: MIT + */ + +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t=t||self).Headroom=n()}(this,function(){"use strict";function t(){return"undefined"!=typeof window}function d(t){return function(t){return t&&t.document&&function(t){return 9===t.nodeType}(t.document)}(t)?function(t){var n=t.document,o=n.body,s=n.documentElement;return{scrollHeight:function(){return Math.max(o.scrollHeight,s.scrollHeight,o.offsetHeight,s.offsetHeight,o.clientHeight,s.clientHeight)},height:function(){return t.innerHeight||s.clientHeight||o.clientHeight},scrollY:function(){return void 0!==t.pageYOffset?t.pageYOffset:(s||o.parentNode||o).scrollTop}}}(t):function(t){return{scrollHeight:function(){return Math.max(t.scrollHeight,t.offsetHeight,t.clientHeight)},height:function(){return Math.max(t.offsetHeight,t.clientHeight)},scrollY:function(){return t.scrollTop}}}(t)}function n(t,s,e){var n,o=function(){var n=!1;try{var t={get passive(){n=!0}};window.addEventListener("test",t,t),window.removeEventListener("test",t,t)}catch(t){n=!1}return n}(),i=!1,r=d(t),l=r.scrollY(),a={};function c(){var t=Math.round(r.scrollY()),n=r.height(),o=r.scrollHeight();a.scrollY=t,a.lastScrollY=l,a.direction=ls.tolerance[a.direction],e(a),l=t,i=!1}function h(){i||(i=!0,n=requestAnimationFrame(c))}var u=!!o&&{passive:!0,capture:!1};return t.addEventListener("scroll",h,u),c(),{destroy:function(){cancelAnimationFrame(n),t.removeEventListener("scroll",h,u)}}}function o(t){return t===Object(t)?t:{down:t,up:t}}function s(t,n){n=n||{},Object.assign(this,s.options,n),this.classes=Object.assign({},s.options.classes,n.classes),this.elem=t,this.tolerance=o(this.tolerance),this.offset=o(this.offset),this.initialised=!1,this.frozen=!1}return s.prototype={constructor:s,init:function(){return s.cutsTheMustard&&!this.initialised&&(this.addClass("initial"),this.initialised=!0,setTimeout(function(t){t.scrollTracker=n(t.scroller,{offset:t.offset,tolerance:t.tolerance},t.update.bind(t))},100,this)),this},destroy:function(){this.initialised=!1,Object.keys(this.classes).forEach(this.removeClass,this),this.scrollTracker.destroy()},unpin:function(){!this.hasClass("pinned")&&this.hasClass("unpinned")||(this.addClass("unpinned"),this.removeClass("pinned"),this.onUnpin&&this.onUnpin.call(this))},pin:function(){this.hasClass("unpinned")&&(this.addClass("pinned"),this.removeClass("unpinned"),this.onPin&&this.onPin.call(this))},freeze:function(){this.frozen=!0,this.addClass("frozen")},unfreeze:function(){this.frozen=!1,this.removeClass("frozen")},top:function(){this.hasClass("top")||(this.addClass("top"),this.removeClass("notTop"),this.onTop&&this.onTop.call(this))},notTop:function(){this.hasClass("notTop")||(this.addClass("notTop"),this.removeClass("top"),this.onNotTop&&this.onNotTop.call(this))},bottom:function(){this.hasClass("bottom")||(this.addClass("bottom"),this.removeClass("notBottom"),this.onBottom&&this.onBottom.call(this))},notBottom:function(){this.hasClass("notBottom")||(this.addClass("notBottom"),this.removeClass("bottom"),this.onNotBottom&&this.onNotBottom.call(this))},shouldUnpin:function(t){return"down"===t.direction&&!t.top&&t.toleranceExceeded},shouldPin:function(t){return"up"===t.direction&&t.toleranceExceeded||t.top},addClass:function(t){this.elem.classList.add.apply(this.elem.classList,this.classes[t].split(" "))},removeClass:function(t){this.elem.classList.remove.apply(this.elem.classList,this.classes[t].split(" "))},hasClass:function(t){return this.classes[t].split(" ").every(function(t){return this.classList.contains(t)},this.elem)},update:function(t){t.isOutOfBounds||!0!==this.frozen&&(t.top?this.top():this.notTop(),t.bottom?this.bottom():this.notBottom(),this.shouldUnpin(t)?this.unpin():this.shouldPin(t)&&this.pin())}},s.options={tolerance:{up:0,down:0},offset:0,scroller:t()?window:null,classes:{frozen:"headroom--frozen",pinned:"headroom--pinned",unpinned:"headroom--unpinned",top:"headroom--top",notTop:"headroom--not-top",bottom:"headroom--bottom",notBottom:"headroom--not-bottom",initial:"headroom"}},s.cutsTheMustard=!!(t()&&function(){}.bind&&"classList"in document.documentElement&&Object.assign&&Object.keys&&requestAnimationFrame),s}); diff --git a/site_libs/quarto-nav/quarto-nav.js b/site_libs/quarto-nav/quarto-nav.js new file mode 100644 index 0000000..38cc430 --- /dev/null +++ b/site_libs/quarto-nav/quarto-nav.js @@ -0,0 +1,325 @@ +const headroomChanged = new CustomEvent("quarto-hrChanged", { + detail: {}, + bubbles: true, + cancelable: false, + composed: false, +}); + +const announceDismiss = () => { + const annEl = window.document.getElementById("quarto-announcement"); + if (annEl) { + annEl.remove(); + + const annId = annEl.getAttribute("data-announcement-id"); + window.localStorage.setItem(`quarto-announce-${annId}`, "true"); + } +}; + +const announceRegister = () => { + const annEl = window.document.getElementById("quarto-announcement"); + if (annEl) { + const annId = annEl.getAttribute("data-announcement-id"); + const isDismissed = + window.localStorage.getItem(`quarto-announce-${annId}`) || false; + if (isDismissed) { + announceDismiss(); + return; + } else { + annEl.classList.remove("hidden"); + } + + const actionEl = annEl.querySelector(".quarto-announcement-action"); + if (actionEl) { + actionEl.addEventListener("click", function (e) { + e.preventDefault(); + // Hide the bar immediately + announceDismiss(); + }); + } + } +}; + +window.document.addEventListener("DOMContentLoaded", function () { + let init = false; + + announceRegister(); + + // Manage the back to top button, if one is present. + let lastScrollTop = window.pageYOffset || document.documentElement.scrollTop; + const scrollDownBuffer = 5; + const scrollUpBuffer = 35; + const btn = document.getElementById("quarto-back-to-top"); + const hideBackToTop = () => { + btn.style.display = "none"; + }; + const showBackToTop = () => { + btn.style.display = "inline-block"; + }; + if (btn) { + window.document.addEventListener( + "scroll", + function () { + const currentScrollTop = + window.pageYOffset || document.documentElement.scrollTop; + + // Shows and hides the button 'intelligently' as the user scrolls + if (currentScrollTop - scrollDownBuffer > lastScrollTop) { + hideBackToTop(); + lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop; + } else if (currentScrollTop < lastScrollTop - scrollUpBuffer) { + showBackToTop(); + lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop; + } + + // Show the button at the bottom, hides it at the top + if (currentScrollTop <= 0) { + hideBackToTop(); + } else if ( + window.innerHeight + currentScrollTop >= + document.body.offsetHeight + ) { + showBackToTop(); + } + }, + false + ); + } + + function throttle(func, wait) { + var timeout; + return function () { + const context = this; + const args = arguments; + const later = function () { + clearTimeout(timeout); + timeout = null; + func.apply(context, args); + }; + + if (!timeout) { + timeout = setTimeout(later, wait); + } + }; + } + + function headerOffset() { + // Set an offset if there is are fixed top navbar + const headerEl = window.document.querySelector("header.fixed-top"); + if (headerEl) { + return headerEl.clientHeight; + } else { + return 0; + } + } + + function footerOffset() { + const footerEl = window.document.querySelector("footer.footer"); + if (footerEl) { + return footerEl.clientHeight; + } else { + return 0; + } + } + + function dashboardOffset() { + const dashboardNavEl = window.document.getElementById( + "quarto-dashboard-header" + ); + if (dashboardNavEl !== null) { + return dashboardNavEl.clientHeight; + } else { + return 0; + } + } + + function updateDocumentOffsetWithoutAnimation() { + updateDocumentOffset(false); + } + + function updateDocumentOffset(animated) { + // set body offset + const topOffset = headerOffset(); + const bodyOffset = topOffset + footerOffset() + dashboardOffset(); + const bodyEl = window.document.body; + bodyEl.setAttribute("data-bs-offset", topOffset); + bodyEl.style.paddingTop = topOffset + "px"; + + // deal with sidebar offsets + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + if (!animated) { + sidebar.classList.add("notransition"); + // Remove the no transition class after the animation has time to complete + setTimeout(function () { + sidebar.classList.remove("notransition"); + }, 201); + } + + if (window.Headroom && sidebar.classList.contains("sidebar-unpinned")) { + sidebar.style.top = "0"; + sidebar.style.maxHeight = "100vh"; + } else { + sidebar.style.top = topOffset + "px"; + sidebar.style.maxHeight = "calc(100vh - " + topOffset + "px)"; + } + }); + + // allow space for footer + const mainContainer = window.document.querySelector(".quarto-container"); + if (mainContainer) { + mainContainer.style.minHeight = "calc(100vh - " + bodyOffset + "px)"; + } + + // link offset + let linkStyle = window.document.querySelector("#quarto-target-style"); + if (!linkStyle) { + linkStyle = window.document.createElement("style"); + linkStyle.setAttribute("id", "quarto-target-style"); + window.document.head.appendChild(linkStyle); + } + while (linkStyle.firstChild) { + linkStyle.removeChild(linkStyle.firstChild); + } + if (topOffset > 0) { + linkStyle.appendChild( + window.document.createTextNode(` + section:target::before { + content: ""; + display: block; + height: ${topOffset}px; + margin: -${topOffset}px 0 0; + }`) + ); + } + if (init) { + window.dispatchEvent(headroomChanged); + } + init = true; + } + + // initialize headroom + var header = window.document.querySelector("#quarto-header"); + if (header && window.Headroom) { + const headroom = new window.Headroom(header, { + tolerance: 5, + onPin: function () { + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + sidebar.classList.remove("sidebar-unpinned"); + }); + updateDocumentOffset(); + }, + onUnpin: function () { + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + sidebar.classList.add("sidebar-unpinned"); + }); + updateDocumentOffset(); + }, + }); + headroom.init(); + + let frozen = false; + window.quartoToggleHeadroom = function () { + if (frozen) { + headroom.unfreeze(); + frozen = false; + } else { + headroom.freeze(); + frozen = true; + } + }; + } + + window.addEventListener( + "hashchange", + function (e) { + if ( + getComputedStyle(document.documentElement).scrollBehavior !== "smooth" + ) { + window.scrollTo(0, window.pageYOffset - headerOffset()); + } + }, + false + ); + + // Observe size changed for the header + const headerEl = window.document.querySelector("header.fixed-top"); + if (headerEl && window.ResizeObserver) { + const observer = new window.ResizeObserver(() => { + setTimeout(updateDocumentOffsetWithoutAnimation, 0); + }); + observer.observe(headerEl, { + attributes: true, + childList: true, + characterData: true, + }); + } else { + window.addEventListener( + "resize", + throttle(updateDocumentOffsetWithoutAnimation, 50) + ); + } + setTimeout(updateDocumentOffsetWithoutAnimation, 250); + + // fixup index.html links if we aren't on the filesystem + if (window.location.protocol !== "file:") { + const links = window.document.querySelectorAll("a"); + for (let i = 0; i < links.length; i++) { + if (links[i].href) { + links[i].dataset.originalHref = links[i].href; + links[i].href = links[i].href.replace(/\/index\.html/, "/"); + } + } + + // Fixup any sharing links that require urls + // Append url to any sharing urls + const sharingLinks = window.document.querySelectorAll( + "a.sidebar-tools-main-item, a.quarto-navigation-tool, a.quarto-navbar-tools, a.quarto-navbar-tools-item" + ); + for (let i = 0; i < sharingLinks.length; i++) { + const sharingLink = sharingLinks[i]; + const href = sharingLink.getAttribute("href"); + if (href) { + sharingLink.setAttribute( + "href", + href.replace("|url|", window.location.href) + ); + } + } + + // Scroll the active navigation item into view, if necessary + const navSidebar = window.document.querySelector("nav#quarto-sidebar"); + if (navSidebar) { + // Find the active item + const activeItem = navSidebar.querySelector("li.sidebar-item a.active"); + if (activeItem) { + // Wait for the scroll height and height to resolve by observing size changes on the + // nav element that is scrollable + const resizeObserver = new ResizeObserver((_entries) => { + // The bottom of the element + const elBottom = activeItem.offsetTop; + const viewBottom = navSidebar.scrollTop + navSidebar.clientHeight; + + // The element height and scroll height are the same, then we are still loading + if (viewBottom !== navSidebar.scrollHeight) { + // Determine if the item isn't visible and scroll to it + if (elBottom >= viewBottom) { + navSidebar.scrollTop = elBottom; + } + + // stop observing now since we've completed the scroll + resizeObserver.unobserve(navSidebar); + } + }); + resizeObserver.observe(navSidebar); + } + } + } +}); diff --git a/site_libs/quarto-search/autocomplete.umd.js b/site_libs/quarto-search/autocomplete.umd.js new file mode 100644 index 0000000..ae0063a --- /dev/null +++ b/site_libs/quarto-search/autocomplete.umd.js @@ -0,0 +1,3 @@ +/*! @algolia/autocomplete-js 1.11.1 | MIT License | © Algolia, Inc. and contributors | https://github.com/algolia/autocomplete */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self)["@algolia/autocomplete-js"]={})}(this,(function(e){"use strict";function t(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function n(e){for(var n=1;n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function a(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,o,i,u,a=[],l=!0,c=!1;try{if(i=(n=n.call(e)).next,0===t){if(Object(n)!==n)return;l=!1}else for(;!(l=(r=i.call(n)).done)&&(a.push(r.value),a.length!==t);l=!0);}catch(e){c=!0,o=e}finally{try{if(!l&&null!=n.return&&(u=n.return(),Object(u)!==u))return}finally{if(c)throw o}}return a}}(e,t)||c(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function l(e){return function(e){if(Array.isArray(e))return s(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||c(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function c(e,t){if(e){if("string"==typeof e)return s(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?s(e,t):void 0}}function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function x(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function N(e){for(var t=1;t1&&void 0!==arguments[1]?arguments[1]:20,n=[],r=0;r=3||2===n&&r>=4||1===n&&r>=10);function i(t,n,r){if(o&&void 0!==r){var i=r[0].__autocomplete_algoliaCredentials,u={"X-Algolia-Application-Id":i.appId,"X-Algolia-API-Key":i.apiKey};e.apply(void 0,[t].concat(D(n),[{headers:u}]))}else e.apply(void 0,[t].concat(D(n)))}return{init:function(t,n){e("init",{appId:t,apiKey:n})},setUserToken:function(t){e("setUserToken",t)},clickedObjectIDsAfterSearch:function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&i("clickedObjectIDsAfterSearch",B(t),t[0].items)},clickedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&i("clickedObjectIDs",B(t),t[0].items)},clickedFilters:function(){for(var t=arguments.length,n=new Array(t),r=0;r0&&e.apply(void 0,["clickedFilters"].concat(n))},convertedObjectIDsAfterSearch:function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&i("convertedObjectIDsAfterSearch",B(t),t[0].items)},convertedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&i("convertedObjectIDs",B(t),t[0].items)},convertedFilters:function(){for(var t=arguments.length,n=new Array(t),r=0;r0&&e.apply(void 0,["convertedFilters"].concat(n))},viewedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&t.reduce((function(e,t){var n=t.items,r=k(t,A);return[].concat(D(e),D(q(N(N({},r),{},{objectIDs:(null==n?void 0:n.map((function(e){return e.objectID})))||r.objectIDs})).map((function(e){return{items:n,payload:e}}))))}),[]).forEach((function(e){var t=e.items;return i("viewedObjectIDs",[e.payload],t)}))},viewedFilters:function(){for(var t=arguments.length,n=new Array(t),r=0;r0&&e.apply(void 0,["viewedFilters"].concat(n))}}}function F(e){var t=e.items.reduce((function(e,t){var n;return e[t.__autocomplete_indexName]=(null!==(n=e[t.__autocomplete_indexName])&&void 0!==n?n:[]).concat(t),e}),{});return Object.keys(t).map((function(e){return{index:e,items:t[e],algoliaSource:["autocomplete"]}}))}function L(e){return e.objectID&&e.__autocomplete_indexName&&e.__autocomplete_queryID}function U(e){return U="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},U(e)}function M(e){return function(e){if(Array.isArray(e))return H(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return H(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return H(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function H(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&z({onItemsChange:r,items:n,insights:a,state:t}))}}),0);return{name:"aa.algoliaInsightsPlugin",subscribe:function(e){var t=e.setContext,n=e.onSelect,r=e.onActive;function l(e){t({algoliaInsightsPlugin:{__algoliaSearchParameters:W({clickAnalytics:!0},e?{userToken:e}:{}),insights:a}})}u("addAlgoliaAgent","insights-plugin"),l(),u("onUserTokenChange",l),u("getUserToken",null,(function(e,t){l(t)})),n((function(e){var t=e.item,n=e.state,r=e.event,i=e.source;L(t)&&o({state:n,event:r,insights:a,item:t,insightsEvents:[W({eventName:"Item Selected"},j({item:t,items:i.getItems().filter(L)}))]})})),r((function(e){var t=e.item,n=e.source,r=e.state,o=e.event;L(t)&&i({state:r,event:o,insights:a,item:t,insightsEvents:[W({eventName:"Item Active"},j({item:t,items:n.getItems().filter(L)}))]})}))},onStateChange:function(e){var t=e.state;c({state:t})},__autocomplete_pluginOptions:e}}function J(e,t){var n=t;return{then:function(t,r){return J(e.then(Y(t,n,e),Y(r,n,e)),n)},catch:function(t){return J(e.catch(Y(t,n,e)),n)},finally:function(t){return t&&n.onCancelList.push(t),J(e.finally(Y(t&&function(){return n.onCancelList=[],t()},n,e)),n)},cancel:function(){n.isCanceled=!0;var e=n.onCancelList;n.onCancelList=[],e.forEach((function(e){e()}))},isCanceled:function(){return!0===n.isCanceled}}}function X(e){return J(e,{isCanceled:!1,onCancelList:[]})}function Y(e,t,n){return e?function(n){return t.isCanceled?n:e(n)}:n}function Z(e,t,n,r){if(!n)return null;if(e<0&&(null===t||null!==r&&0===t))return n+e;var o=(null===t?-1:t)+e;return o<=-1||o>=n?null===r?null:0:o}function ee(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function te(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n0},reshape:function(e){return e.sources}},e),{},{id:null!==(n=e.id)&&void 0!==n?n:d(),plugins:o,initialState:he({activeItemId:null,query:"",completion:null,collections:[],isOpen:!1,status:"idle",context:{}},e.initialState),onStateChange:function(t){var n;null===(n=e.onStateChange)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onStateChange)||void 0===n?void 0:n.call(e,t)}))},onSubmit:function(t){var n;null===(n=e.onSubmit)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onSubmit)||void 0===n?void 0:n.call(e,t)}))},onReset:function(t){var n;null===(n=e.onReset)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onReset)||void 0===n?void 0:n.call(e,t)}))},getSources:function(n){return Promise.all([].concat(ye(o.map((function(e){return e.getSources}))),[e.getSources]).filter(Boolean).map((function(e){return function(e,t){var n=[];return Promise.resolve(e(t)).then((function(e){return Promise.all(e.filter((function(e){return Boolean(e)})).map((function(e){if(e.sourceId,n.includes(e.sourceId))throw new Error("[Autocomplete] The `sourceId` ".concat(JSON.stringify(e.sourceId)," is not unique."));n.push(e.sourceId);var t={getItemInputValue:function(e){return e.state.query},getItemUrl:function(){},onSelect:function(e){(0,e.setIsOpen)(!1)},onActive:O,onResolve:O};Object.keys(t).forEach((function(e){t[e].__default=!0}));var r=te(te({},t),e);return Promise.resolve(r)})))}))}(e,n)}))).then((function(e){return m(e)})).then((function(e){return e.map((function(e){return he(he({},e),{},{onSelect:function(n){e.onSelect(n),t.forEach((function(e){var t;return null===(t=e.onSelect)||void 0===t?void 0:t.call(e,n)}))},onActive:function(n){e.onActive(n),t.forEach((function(e){var t;return null===(t=e.onActive)||void 0===t?void 0:t.call(e,n)}))},onResolve:function(n){e.onResolve(n),t.forEach((function(e){var t;return null===(t=e.onResolve)||void 0===t?void 0:t.call(e,n)}))}})}))}))},navigator:he({navigate:function(e){var t=e.itemUrl;r.location.assign(t)},navigateNewTab:function(e){var t=e.itemUrl,n=r.open(t,"_blank","noopener");null==n||n.focus()},navigateNewWindow:function(e){var t=e.itemUrl;r.open(t,"_blank","noopener")}},e.navigator)})}function Se(e){return Se="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Se(e)}function je(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Pe(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var He,Ve,We,Ke=null,Qe=(He=-1,Ve=-1,We=void 0,function(e){var t=++He;return Promise.resolve(e).then((function(e){return We&&t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function et(e){return et="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},et(e)}var tt=["props","refresh","store"],nt=["inputElement","formElement","panelElement"],rt=["inputElement"],ot=["inputElement","maxLength"],it=["source"],ut=["item","source"];function at(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function lt(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function ft(e){var t=e.props,n=e.refresh,r=e.store,o=st(e,tt);return{getEnvironmentProps:function(e){var n=e.inputElement,o=e.formElement,i=e.panelElement;function u(e){!r.getState().isOpen&&r.pendingRequests.isEmpty()||e.target===n||!1===[o,i].some((function(t){return n=t,r=e.target,n===r||n.contains(r);var n,r}))&&(r.dispatch("blur",null),t.debug||r.pendingRequests.cancelAll())}return lt({onTouchStart:u,onMouseDown:u,onTouchMove:function(e){!1!==r.getState().isOpen&&n===t.environment.document.activeElement&&e.target!==n&&n.blur()}},st(e,nt))},getRootProps:function(e){return lt({role:"combobox","aria-expanded":r.getState().isOpen,"aria-haspopup":"listbox","aria-owns":r.getState().isOpen?r.getState().collections.map((function(e){var n=e.source;return ie(t.id,"list",n)})).join(" "):void 0,"aria-labelledby":ie(t.id,"label")},e)},getFormProps:function(e){return e.inputElement,lt({action:"",noValidate:!0,role:"search",onSubmit:function(i){var u;i.preventDefault(),t.onSubmit(lt({event:i,refresh:n,state:r.getState()},o)),r.dispatch("submit",null),null===(u=e.inputElement)||void 0===u||u.blur()},onReset:function(i){var u;i.preventDefault(),t.onReset(lt({event:i,refresh:n,state:r.getState()},o)),r.dispatch("reset",null),null===(u=e.inputElement)||void 0===u||u.focus()}},st(e,rt))},getLabelProps:function(e){return lt({htmlFor:ie(t.id,"input"),id:ie(t.id,"label")},e)},getInputProps:function(e){var i;function u(e){(t.openOnFocus||Boolean(r.getState().query))&&$e(lt({event:e,props:t,query:r.getState().completion||r.getState().query,refresh:n,store:r},o)),r.dispatch("focus",null)}var a=e||{};a.inputElement;var l=a.maxLength,c=void 0===l?512:l,s=st(a,ot),f=oe(r.getState()),p=function(e){return Boolean(e&&e.match(ue))}((null===(i=t.environment.navigator)||void 0===i?void 0:i.userAgent)||""),m=t.enterKeyHint||(null!=f&&f.itemUrl&&!p?"go":"search");return lt({"aria-autocomplete":"both","aria-activedescendant":r.getState().isOpen&&null!==r.getState().activeItemId?ie(t.id,"item-".concat(r.getState().activeItemId),null==f?void 0:f.source):void 0,"aria-controls":r.getState().isOpen?r.getState().collections.map((function(e){var n=e.source;return ie(t.id,"list",n)})).join(" "):void 0,"aria-labelledby":ie(t.id,"label"),value:r.getState().completion||r.getState().query,id:ie(t.id,"input"),autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",enterKeyHint:m,spellCheck:"false",autoFocus:t.autoFocus,placeholder:t.placeholder,maxLength:c,type:"search",onChange:function(e){$e(lt({event:e,props:t,query:e.currentTarget.value.slice(0,c),refresh:n,store:r},o))},onKeyDown:function(e){!function(e){var t=e.event,n=e.props,r=e.refresh,o=e.store,i=Ze(e,Ge);if("ArrowUp"===t.key||"ArrowDown"===t.key){var u=function(){var e=oe(o.getState()),t=n.environment.document.getElementById(ie(n.id,"item-".concat(o.getState().activeItemId),null==e?void 0:e.source));t&&(t.scrollIntoViewIfNeeded?t.scrollIntoViewIfNeeded(!1):t.scrollIntoView(!1))},a=function(){var e=oe(o.getState());if(null!==o.getState().activeItemId&&e){var n=e.item,u=e.itemInputValue,a=e.itemUrl,l=e.source;l.onActive(Xe({event:t,item:n,itemInputValue:u,itemUrl:a,refresh:r,source:l,state:o.getState()},i))}};t.preventDefault(),!1===o.getState().isOpen&&(n.openOnFocus||Boolean(o.getState().query))?$e(Xe({event:t,props:n,query:o.getState().query,refresh:r,store:o},i)).then((function(){o.dispatch(t.key,{nextActiveItemId:n.defaultActiveItemId}),a(),setTimeout(u,0)})):(o.dispatch(t.key,{}),a(),u())}else if("Escape"===t.key)t.preventDefault(),o.dispatch(t.key,null),o.pendingRequests.cancelAll();else if("Tab"===t.key)o.dispatch("blur",null),o.pendingRequests.cancelAll();else if("Enter"===t.key){if(null===o.getState().activeItemId||o.getState().collections.every((function(e){return 0===e.items.length})))return void(n.debug||o.pendingRequests.cancelAll());t.preventDefault();var l=oe(o.getState()),c=l.item,s=l.itemInputValue,f=l.itemUrl,p=l.source;if(t.metaKey||t.ctrlKey)void 0!==f&&(p.onSelect(Xe({event:t,item:c,itemInputValue:s,itemUrl:f,refresh:r,source:p,state:o.getState()},i)),n.navigator.navigateNewTab({itemUrl:f,item:c,state:o.getState()}));else if(t.shiftKey)void 0!==f&&(p.onSelect(Xe({event:t,item:c,itemInputValue:s,itemUrl:f,refresh:r,source:p,state:o.getState()},i)),n.navigator.navigateNewWindow({itemUrl:f,item:c,state:o.getState()}));else if(t.altKey);else{if(void 0!==f)return p.onSelect(Xe({event:t,item:c,itemInputValue:s,itemUrl:f,refresh:r,source:p,state:o.getState()},i)),void n.navigator.navigate({itemUrl:f,item:c,state:o.getState()});$e(Xe({event:t,nextState:{isOpen:!1},props:n,query:s,refresh:r,store:o},i)).then((function(){p.onSelect(Xe({event:t,item:c,itemInputValue:s,itemUrl:f,refresh:r,source:p,state:o.getState()},i))}))}}}(lt({event:e,props:t,refresh:n,store:r},o))},onFocus:u,onBlur:O,onClick:function(n){e.inputElement!==t.environment.document.activeElement||r.getState().isOpen||u(n)}},s)},getPanelProps:function(e){return lt({onMouseDown:function(e){e.preventDefault()},onMouseLeave:function(){r.dispatch("mouseleave",null)}},e)},getListProps:function(e){var n=e||{},r=n.source,o=st(n,it);return lt({role:"listbox","aria-labelledby":ie(t.id,"label"),id:ie(t.id,"list",r)},o)},getItemProps:function(e){var i=e.item,u=e.source,a=st(e,ut);return lt({id:ie(t.id,"item-".concat(i.__autocomplete_id),u),role:"option","aria-selected":r.getState().activeItemId===i.__autocomplete_id,onMouseMove:function(e){if(i.__autocomplete_id!==r.getState().activeItemId){r.dispatch("mousemove",i.__autocomplete_id);var t=oe(r.getState());if(null!==r.getState().activeItemId&&t){var u=t.item,a=t.itemInputValue,l=t.itemUrl,c=t.source;c.onActive(lt({event:e,item:u,itemInputValue:a,itemUrl:l,refresh:n,source:c,state:r.getState()},o))}}},onMouseDown:function(e){e.preventDefault()},onClick:function(e){var a=u.getItemInputValue({item:i,state:r.getState()}),l=u.getItemUrl({item:i,state:r.getState()});(l?Promise.resolve():$e(lt({event:e,nextState:{isOpen:!1},props:t,query:a,refresh:n,store:r},o))).then((function(){u.onSelect(lt({event:e,item:i,itemInputValue:a,itemUrl:l,refresh:n,source:u,state:r.getState()},o))}))}},a)}}}function pt(e){return pt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},pt(e)}function mt(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function vt(e){for(var t=1;t=5&&((o||!e&&5===r)&&(u.push(r,0,o,n),r=6),e&&(u.push(r,e,0,n),r=6)),o=""},l=0;l"===t?(r=1,o=""):o=t+o[0]:i?t===i?i="":o+=t:'"'===t||"'"===t?i=t:">"===t?(a(),r=1):r&&("="===t?(r=5,n=o,o=""):"/"===t&&(r<5||">"===e[l][c+1])?(a(),3===r&&(u=u[0]),r=u,(u=u[0]).push(2,0,r),r=0):" "===t||"\t"===t||"\n"===t||"\r"===t?(a(),r=2):o+=t),3===r&&"!--"===o&&(r=4,u=u[0])}return a(),u}(e)),t),arguments,[])).length>1?t:t[0]}var kt=function(e){var t=e.environment,n=t.document.createElementNS("http://www.w3.org/2000/svg","svg");n.setAttribute("class","aa-ClearIcon"),n.setAttribute("viewBox","0 0 24 24"),n.setAttribute("width","18"),n.setAttribute("height","18"),n.setAttribute("fill","currentColor");var r=t.document.createElementNS("http://www.w3.org/2000/svg","path");return r.setAttribute("d","M5.293 6.707l5.293 5.293-5.293 5.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l5.293-5.293 5.293 5.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-5.293-5.293 5.293-5.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-5.293 5.293-5.293-5.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z"),n.appendChild(r),n};function xt(e,t){if("string"==typeof t){var n=e.document.querySelector(t);return"The element ".concat(JSON.stringify(t)," is not in the document."),n}return t}function Nt(){for(var e=arguments.length,t=new Array(e),n=0;n2&&(u.children=arguments.length>3?Jt.call(arguments,2):n),"function"==typeof e&&null!=e.defaultProps)for(i in e.defaultProps)void 0===u[i]&&(u[i]=e.defaultProps[i]);return sn(e,u,r,o,null)}function sn(e,t,n,r,o){var i={type:e,props:t,key:n,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:null==o?++Yt:o};return null==o&&null!=Xt.vnode&&Xt.vnode(i),i}function fn(e){return e.children}function pn(e,t){this.props=e,this.context=t}function mn(e,t){if(null==t)return e.__?mn(e.__,e.__.__k.indexOf(e)+1):null;for(var n;tt&&Zt.sort(nn));yn.__r=0}function bn(e,t,n,r,o,i,u,a,l,c){var s,f,p,m,v,d,y,b=r&&r.__k||on,g=b.length;for(n.__k=[],s=0;s0?sn(m.type,m.props,m.key,m.ref?m.ref:null,m.__v):m)){if(m.__=n,m.__b=n.__b+1,null===(p=b[s])||p&&m.key==p.key&&m.type===p.type)b[s]=void 0;else for(f=0;f=0;t--)if((n=e.__k[t])&&(r=On(n)))return r;return null}function _n(e,t,n){"-"===t[0]?e.setProperty(t,null==n?"":n):e[t]=null==n?"":"number"!=typeof n||un.test(t)?n:n+"px"}function Sn(e,t,n,r,o){var i;e:if("style"===t)if("string"==typeof n)e.style.cssText=n;else{if("string"==typeof r&&(e.style.cssText=r=""),r)for(t in r)n&&t in n||_n(e.style,t,"");if(n)for(t in n)r&&n[t]===r[t]||_n(e.style,t,n[t])}else if("o"===t[0]&&"n"===t[1])i=t!==(t=t.replace(/Capture$/,"")),t=t.toLowerCase()in e?t.toLowerCase().slice(2):t.slice(2),e.l||(e.l={}),e.l[t+i]=n,n?r||e.addEventListener(t,i?Pn:jn,i):e.removeEventListener(t,i?Pn:jn,i);else if("dangerouslySetInnerHTML"!==t){if(o)t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if("width"!==t&&"height"!==t&&"href"!==t&&"list"!==t&&"form"!==t&&"tabIndex"!==t&&"download"!==t&&t in e)try{e[t]=null==n?"":n;break e}catch(e){}"function"==typeof n||(null==n||!1===n&&"-"!==t[4]?e.removeAttribute(t):e.setAttribute(t,n))}}function jn(e){return this.l[e.type+!1](Xt.event?Xt.event(e):e)}function Pn(e){return this.l[e.type+!0](Xt.event?Xt.event(e):e)}function wn(e,t,n,r,o,i,u,a,l){var c,s,f,p,m,v,d,y,b,g,h,O,_,S,j,P=t.type;if(void 0!==t.constructor)return null;null!=n.__h&&(l=n.__h,a=t.__e=n.__e,t.__h=null,i=[a]),(c=Xt.__b)&&c(t);try{e:if("function"==typeof P){if(y=t.props,b=(c=P.contextType)&&r[c.__c],g=c?b?b.props.value:c.__:r,n.__c?d=(s=t.__c=n.__c).__=s.__E:("prototype"in P&&P.prototype.render?t.__c=s=new P(y,g):(t.__c=s=new pn(y,g),s.constructor=P,s.render=Cn),b&&b.sub(s),s.props=y,s.state||(s.state={}),s.context=g,s.__n=r,f=s.__d=!0,s.__h=[],s._sb=[]),null==s.__s&&(s.__s=s.state),null!=P.getDerivedStateFromProps&&(s.__s==s.state&&(s.__s=an({},s.__s)),an(s.__s,P.getDerivedStateFromProps(y,s.__s))),p=s.props,m=s.state,s.__v=t,f)null==P.getDerivedStateFromProps&&null!=s.componentWillMount&&s.componentWillMount(),null!=s.componentDidMount&&s.__h.push(s.componentDidMount);else{if(null==P.getDerivedStateFromProps&&y!==p&&null!=s.componentWillReceiveProps&&s.componentWillReceiveProps(y,g),!s.__e&&null!=s.shouldComponentUpdate&&!1===s.shouldComponentUpdate(y,s.__s,g)||t.__v===n.__v){for(t.__v!==n.__v&&(s.props=y,s.state=s.__s,s.__d=!1),s.__e=!1,t.__e=n.__e,t.__k=n.__k,t.__k.forEach((function(e){e&&(e.__=t)})),h=0;h0&&void 0!==arguments[0]?arguments[0]:[];return{get:function(){return e},add:function(t){var n=e[e.length-1];(null==n?void 0:n.isHighlighted)===t.isHighlighted?e[e.length-1]={value:n.value+t.value,isHighlighted:n.isHighlighted}:e.push(t)}}}(n?[{value:n,isHighlighted:!1}]:[]);return t.forEach((function(e){var t=e.split(xn);r.add({value:t[0],isHighlighted:!0}),""!==t[1]&&r.add({value:t[1],isHighlighted:!1})})),r.get()}function Tn(e){return function(e){if(Array.isArray(e))return qn(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return qn(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return qn(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function qn(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n",""":'"',"'":"'"},Fn=new RegExp(/\w/i),Ln=/&(amp|quot|lt|gt|#39);/g,Un=RegExp(Ln.source);function Mn(e,t){var n,r,o,i=e[t],u=(null===(n=e[t+1])||void 0===n?void 0:n.isHighlighted)||!0,a=(null===(r=e[t-1])||void 0===r?void 0:r.isHighlighted)||!0;return Fn.test((o=i.value)&&Un.test(o)?o.replace(Ln,(function(e){return Rn[e]})):o)||a!==u?i.isHighlighted:a}function Hn(e){return Hn="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Hn(e)}function Vn(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Wn(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function ur(e){return function(e){if(Array.isArray(e))return ar(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return ar(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ar(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function ar(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0;if(!O.value.core.openOnFocus&&!t.query)return n;var r=Boolean(y.current||O.value.renderer.renderNoResults);return!n&&r||n},__autocomplete_metadata:{userAgents:br,options:e}}))})),j=f(n({collections:[],completion:null,context:{},isOpen:!1,query:"",activeItemId:null,status:"idle"},O.value.core.initialState)),P={getEnvironmentProps:O.value.renderer.getEnvironmentProps,getFormProps:O.value.renderer.getFormProps,getInputProps:O.value.renderer.getInputProps,getItemProps:O.value.renderer.getItemProps,getLabelProps:O.value.renderer.getLabelProps,getListProps:O.value.renderer.getListProps,getPanelProps:O.value.renderer.getPanelProps,getRootProps:O.value.renderer.getRootProps},w={setActiveItemId:S.value.setActiveItemId,setQuery:S.value.setQuery,setCollections:S.value.setCollections,setIsOpen:S.value.setIsOpen,setStatus:S.value.setStatus,setContext:S.value.setContext,refresh:S.value.refresh,navigator:S.value.navigator},I=m((function(){return Ct.bind(O.value.renderer.renderer.createElement)})),A=m((function(){return Gt({autocomplete:S.value,autocompleteScopeApi:w,classNames:O.value.renderer.classNames,environment:O.value.core.environment,isDetached:_.value,placeholder:O.value.core.placeholder,propGetters:P,setIsModalOpen:k,state:j.current,translations:O.value.renderer.translations})}));function E(){Ht(A.value.panel,{style:_.value?{}:yr({panelPlacement:O.value.renderer.panelPlacement,container:A.value.root,form:A.value.form,environment:O.value.core.environment})})}function D(e){j.current=e;var t={autocomplete:S.value,autocompleteScopeApi:w,classNames:O.value.renderer.classNames,components:O.value.renderer.components,container:O.value.renderer.container,html:I.value,dom:A.value,panelContainer:_.value?A.value.detachedContainer:O.value.renderer.panelContainer,propGetters:P,state:j.current,renderer:O.value.renderer.renderer},r=!b(e)&&!y.current&&O.value.renderer.renderNoResults||O.value.renderer.render;!function(e){var t=e.autocomplete,r=e.autocompleteScopeApi,o=e.dom,i=e.propGetters,u=e.state;Vt(o.root,i.getRootProps(n({state:u,props:t.getRootProps({})},r))),Vt(o.input,i.getInputProps(n({state:u,props:t.getInputProps({inputElement:o.input}),inputElement:o.input},r))),Ht(o.label,{hidden:"stalled"===u.status}),Ht(o.loadingIndicator,{hidden:"stalled"!==u.status}),Ht(o.clearButton,{hidden:!u.query}),Ht(o.detachedSearchButtonQuery,{textContent:u.query}),Ht(o.detachedSearchButtonPlaceholder,{hidden:Boolean(u.query)})}(t),function(e,t){var r=t.autocomplete,o=t.autocompleteScopeApi,u=t.classNames,a=t.html,l=t.dom,c=t.panelContainer,s=t.propGetters,f=t.state,p=t.components,m=t.renderer;if(f.isOpen){c.contains(l.panel)||"loading"===f.status||c.appendChild(l.panel),l.panel.classList.toggle("aa-Panel--stalled","stalled"===f.status);var v=f.collections.filter((function(e){var t=e.source,n=e.items;return t.templates.noResults||n.length>0})).map((function(e,t){var l=e.source,c=e.items;return m.createElement("section",{key:t,className:u.source,"data-autocomplete-source-id":l.sourceId},l.templates.header&&m.createElement("div",{className:u.sourceHeader},l.templates.header({components:p,createElement:m.createElement,Fragment:m.Fragment,items:c,source:l,state:f,html:a})),l.templates.noResults&&0===c.length?m.createElement("div",{className:u.sourceNoResults},l.templates.noResults({components:p,createElement:m.createElement,Fragment:m.Fragment,source:l,state:f,html:a})):m.createElement("ul",i({className:u.list},s.getListProps(n({state:f,props:r.getListProps({source:l})},o))),c.map((function(e){var t=r.getItemProps({item:e,source:l});return m.createElement("li",i({key:t.id,className:u.item},s.getItemProps(n({state:f,props:t},o))),l.templates.item({components:p,createElement:m.createElement,Fragment:m.Fragment,item:e,state:f,html:a}))}))),l.templates.footer&&m.createElement("div",{className:u.sourceFooter},l.templates.footer({components:p,createElement:m.createElement,Fragment:m.Fragment,items:c,source:l,state:f,html:a})))})),d=m.createElement(m.Fragment,null,m.createElement("div",{className:u.panelLayout},v),m.createElement("div",{className:"aa-GradientBottom"})),y=v.reduce((function(e,t){return e[t.props["data-autocomplete-source-id"]]=t,e}),{});e(n(n({children:d,state:f,sections:v,elements:y},m),{},{components:p,html:a},o),l.panel)}else c.contains(l.panel)&&c.removeChild(l.panel)}(r,t)}function C(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};l();var t=O.value.renderer,n=t.components,r=u(t,gr);g.current=qt(r,O.value.core,{components:Bt(n,(function(e){return!e.value.hasOwnProperty("__autocomplete_componentName")})),initialState:j.current},e),v(),c(),S.value.refresh().then((function(){D(j.current)}))}function k(e){requestAnimationFrame((function(){var t=O.value.core.environment.document.body.contains(A.value.detachedOverlay);e!==t&&(e?(O.value.core.environment.document.body.appendChild(A.value.detachedOverlay),O.value.core.environment.document.body.classList.add("aa-Detached"),A.value.input.focus()):(O.value.core.environment.document.body.removeChild(A.value.detachedOverlay),O.value.core.environment.document.body.classList.remove("aa-Detached")))}))}return a((function(){var e=S.value.getEnvironmentProps({formElement:A.value.form,panelElement:A.value.panel,inputElement:A.value.input});return Ht(O.value.core.environment,e),function(){Ht(O.value.core.environment,Object.keys(e).reduce((function(e,t){return n(n({},e),{},o({},t,void 0))}),{}))}})),a((function(){var e=_.value?O.value.core.environment.document.body:O.value.renderer.panelContainer,t=_.value?A.value.detachedOverlay:A.value.panel;return _.value&&j.current.isOpen&&k(!0),D(j.current),function(){e.contains(t)&&e.removeChild(t)}})),a((function(){var e=O.value.renderer.container;return e.appendChild(A.value.root),function(){e.removeChild(A.value.root)}})),a((function(){var e=p((function(e){D(e.state)}),0);return h.current=function(t){var n=t.state,r=t.prevState;(_.value&&r.isOpen!==n.isOpen&&k(n.isOpen),_.value||!n.isOpen||r.isOpen||E(),n.query!==r.query)&&O.value.core.environment.document.querySelectorAll(".aa-Panel--scrollable").forEach((function(e){0!==e.scrollTop&&(e.scrollTop=0)}));e({state:n})},function(){h.current=void 0}})),a((function(){var e=p((function(){var e=_.value;_.value=O.value.core.environment.matchMedia(O.value.renderer.detachedMediaQuery).matches,e!==_.value?C({}):requestAnimationFrame(E)}),20);return O.value.core.environment.addEventListener("resize",e),function(){O.value.core.environment.removeEventListener("resize",e)}})),a((function(){if(!_.value)return function(){};function e(e){A.value.detachedContainer.classList.toggle("aa-DetachedContainer--modal",e)}function t(t){e(t.matches)}var n=O.value.core.environment.matchMedia(getComputedStyle(O.value.core.environment.document.documentElement).getPropertyValue("--aa-detached-modal-media-query"));e(n.matches);var r=Boolean(n.addEventListener);return r?n.addEventListener("change",t):n.addListener(t),function(){r?n.removeEventListener("change",t):n.removeListener(t)}})),a((function(){return requestAnimationFrame(E),function(){}})),n(n({},w),{},{update:C,destroy:function(){l()}})},e.getAlgoliaFacets=function(e){var t=hr({transformResponse:function(e){return e.facetHits}}),r=e.queries.map((function(e){return n(n({},e),{},{type:"facet"})}));return t(n(n({},e),{},{queries:r}))},e.getAlgoliaResults=Or,Object.defineProperty(e,"__esModule",{value:!0})})); + diff --git a/site_libs/quarto-search/fuse.min.js b/site_libs/quarto-search/fuse.min.js new file mode 100644 index 0000000..adc2835 --- /dev/null +++ b/site_libs/quarto-search/fuse.min.js @@ -0,0 +1,9 @@ +/** + * Fuse.js v6.6.2 - Lightweight fuzzy-search (http://fusejs.io) + * + * Copyright (c) 2022 Kiro Risk (http://kiro.me) + * All Rights Reserved. Apache Software License 2.0 + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +var e,t;e=this,t=function(){"use strict";function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function t(t){for(var n=1;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:1,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:3,n=new Map,r=Math.pow(10,t);return{get:function(t){var i=t.match(C).length;if(n.has(i))return n.get(i);var o=1/Math.pow(i,.5*e),c=parseFloat(Math.round(o*r)/r);return n.set(i,c),c},clear:function(){n.clear()}}}var $=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.getFn,i=void 0===n?I.getFn:n,o=t.fieldNormWeight,c=void 0===o?I.fieldNormWeight:o;r(this,e),this.norm=E(c,3),this.getFn=i,this.isCreated=!1,this.setIndexRecords()}return o(e,[{key:"setSources",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.docs=e}},{key:"setIndexRecords",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.records=e}},{key:"setKeys",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.keys=t,this._keysMap={},t.forEach((function(t,n){e._keysMap[t.id]=n}))}},{key:"create",value:function(){var e=this;!this.isCreated&&this.docs.length&&(this.isCreated=!0,g(this.docs[0])?this.docs.forEach((function(t,n){e._addString(t,n)})):this.docs.forEach((function(t,n){e._addObject(t,n)})),this.norm.clear())}},{key:"add",value:function(e){var t=this.size();g(e)?this._addString(e,t):this._addObject(e,t)}},{key:"removeAt",value:function(e){this.records.splice(e,1);for(var t=e,n=this.size();t2&&void 0!==arguments[2]?arguments[2]:{},r=n.getFn,i=void 0===r?I.getFn:r,o=n.fieldNormWeight,c=void 0===o?I.fieldNormWeight:o,a=new $({getFn:i,fieldNormWeight:c});return a.setKeys(e.map(_)),a.setSources(t),a.create(),a}function R(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.errors,r=void 0===n?0:n,i=t.currentLocation,o=void 0===i?0:i,c=t.expectedLocation,a=void 0===c?0:c,s=t.distance,u=void 0===s?I.distance:s,h=t.ignoreLocation,l=void 0===h?I.ignoreLocation:h,f=r/e.length;if(l)return f;var d=Math.abs(a-o);return u?f+d/u:d?1:f}function N(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:I.minMatchCharLength,n=[],r=-1,i=-1,o=0,c=e.length;o=t&&n.push([r,i]),r=-1)}return e[o-1]&&o-r>=t&&n.push([r,o-1]),n}var P=32;function W(e){for(var t={},n=0,r=e.length;n1&&void 0!==arguments[1]?arguments[1]:{},o=i.location,c=void 0===o?I.location:o,a=i.threshold,s=void 0===a?I.threshold:a,u=i.distance,h=void 0===u?I.distance:u,l=i.includeMatches,f=void 0===l?I.includeMatches:l,d=i.findAllMatches,v=void 0===d?I.findAllMatches:d,g=i.minMatchCharLength,y=void 0===g?I.minMatchCharLength:g,p=i.isCaseSensitive,m=void 0===p?I.isCaseSensitive:p,k=i.ignoreLocation,M=void 0===k?I.ignoreLocation:k;if(r(this,e),this.options={location:c,threshold:s,distance:h,includeMatches:f,findAllMatches:v,minMatchCharLength:y,isCaseSensitive:m,ignoreLocation:M},this.pattern=m?t:t.toLowerCase(),this.chunks=[],this.pattern.length){var b=function(e,t){n.chunks.push({pattern:e,alphabet:W(e),startIndex:t})},x=this.pattern.length;if(x>P){for(var w=0,L=x%P,S=x-L;w3&&void 0!==arguments[3]?arguments[3]:{},i=r.location,o=void 0===i?I.location:i,c=r.distance,a=void 0===c?I.distance:c,s=r.threshold,u=void 0===s?I.threshold:s,h=r.findAllMatches,l=void 0===h?I.findAllMatches:h,f=r.minMatchCharLength,d=void 0===f?I.minMatchCharLength:f,v=r.includeMatches,g=void 0===v?I.includeMatches:v,y=r.ignoreLocation,p=void 0===y?I.ignoreLocation:y;if(t.length>P)throw new Error(w(P));for(var m,k=t.length,M=e.length,b=Math.max(0,Math.min(o,M)),x=u,L=b,S=d>1||g,_=S?Array(M):[];(m=e.indexOf(t,L))>-1;){var O=R(t,{currentLocation:m,expectedLocation:b,distance:a,ignoreLocation:p});if(x=Math.min(O,x),L=m+k,S)for(var j=0;j=z;q-=1){var B=q-1,J=n[e.charAt(B)];if(S&&(_[B]=+!!J),K[q]=(K[q+1]<<1|1)&J,F&&(K[q]|=(A[q+1]|A[q])<<1|1|A[q+1]),K[q]&$&&(C=R(t,{errors:F,currentLocation:B,expectedLocation:b,distance:a,ignoreLocation:p}))<=x){if(x=C,(L=B)<=b)break;z=Math.max(1,2*b-L)}}if(R(t,{errors:F+1,currentLocation:b,expectedLocation:b,distance:a,ignoreLocation:p})>x)break;A=K}var U={isMatch:L>=0,score:Math.max(.001,C)};if(S){var V=N(_,d);V.length?g&&(U.indices=V):U.isMatch=!1}return U}(e,n,i,{location:c+o,distance:a,threshold:s,findAllMatches:u,minMatchCharLength:h,includeMatches:r,ignoreLocation:l}),p=y.isMatch,m=y.score,k=y.indices;p&&(g=!0),v+=m,p&&k&&(d=[].concat(f(d),f(k)))}));var y={isMatch:g,score:g?v/this.chunks.length:1};return g&&r&&(y.indices=d),y}}]),e}(),z=function(){function e(t){r(this,e),this.pattern=t}return o(e,[{key:"search",value:function(){}}],[{key:"isMultiMatch",value:function(e){return D(e,this.multiRegex)}},{key:"isSingleMatch",value:function(e){return D(e,this.singleRegex)}}]),e}();function D(e,t){var n=e.match(t);return n?n[1]:null}var K=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e===this.pattern;return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}}],[{key:"type",get:function(){return"exact"}},{key:"multiRegex",get:function(){return/^="(.*)"$/}},{key:"singleRegex",get:function(){return/^=(.*)$/}}]),n}(z),q=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=-1===e.indexOf(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-exact"}},{key:"multiRegex",get:function(){return/^!"(.*)"$/}},{key:"singleRegex",get:function(){return/^!(.*)$/}}]),n}(z),B=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}}],[{key:"type",get:function(){return"prefix-exact"}},{key:"multiRegex",get:function(){return/^\^"(.*)"$/}},{key:"singleRegex",get:function(){return/^\^(.*)$/}}]),n}(z),J=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=!e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-prefix-exact"}},{key:"multiRegex",get:function(){return/^!\^"(.*)"$/}},{key:"singleRegex",get:function(){return/^!\^(.*)$/}}]),n}(z),U=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[e.length-this.pattern.length,e.length-1]}}}],[{key:"type",get:function(){return"suffix-exact"}},{key:"multiRegex",get:function(){return/^"(.*)"\$$/}},{key:"singleRegex",get:function(){return/^(.*)\$$/}}]),n}(z),V=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=!e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-suffix-exact"}},{key:"multiRegex",get:function(){return/^!"(.*)"\$$/}},{key:"singleRegex",get:function(){return/^!(.*)\$$/}}]),n}(z),G=function(e){a(n,e);var t=l(n);function n(e){var i,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},c=o.location,a=void 0===c?I.location:c,s=o.threshold,u=void 0===s?I.threshold:s,h=o.distance,l=void 0===h?I.distance:h,f=o.includeMatches,d=void 0===f?I.includeMatches:f,v=o.findAllMatches,g=void 0===v?I.findAllMatches:v,y=o.minMatchCharLength,p=void 0===y?I.minMatchCharLength:y,m=o.isCaseSensitive,k=void 0===m?I.isCaseSensitive:m,M=o.ignoreLocation,b=void 0===M?I.ignoreLocation:M;return r(this,n),(i=t.call(this,e))._bitapSearch=new T(e,{location:a,threshold:u,distance:l,includeMatches:d,findAllMatches:g,minMatchCharLength:p,isCaseSensitive:k,ignoreLocation:b}),i}return o(n,[{key:"search",value:function(e){return this._bitapSearch.searchIn(e)}}],[{key:"type",get:function(){return"fuzzy"}},{key:"multiRegex",get:function(){return/^"(.*)"$/}},{key:"singleRegex",get:function(){return/^(.*)$/}}]),n}(z),H=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){for(var t,n=0,r=[],i=this.pattern.length;(t=e.indexOf(this.pattern,n))>-1;)n=t+i,r.push([t,n-1]);var o=!!r.length;return{isMatch:o,score:o?0:1,indices:r}}}],[{key:"type",get:function(){return"include"}},{key:"multiRegex",get:function(){return/^'"(.*)"$/}},{key:"singleRegex",get:function(){return/^'(.*)$/}}]),n}(z),Q=[K,H,B,J,V,U,q,G],X=Q.length,Y=/ +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/;function Z(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.split("|").map((function(e){for(var n=e.trim().split(Y).filter((function(e){return e&&!!e.trim()})),r=[],i=0,o=n.length;i1&&void 0!==arguments[1]?arguments[1]:{},i=n.isCaseSensitive,o=void 0===i?I.isCaseSensitive:i,c=n.includeMatches,a=void 0===c?I.includeMatches:c,s=n.minMatchCharLength,u=void 0===s?I.minMatchCharLength:s,h=n.ignoreLocation,l=void 0===h?I.ignoreLocation:h,f=n.findAllMatches,d=void 0===f?I.findAllMatches:f,v=n.location,g=void 0===v?I.location:v,y=n.threshold,p=void 0===y?I.threshold:y,m=n.distance,k=void 0===m?I.distance:m;r(this,e),this.query=null,this.options={isCaseSensitive:o,includeMatches:a,minMatchCharLength:u,findAllMatches:d,ignoreLocation:l,location:g,threshold:p,distance:k},this.pattern=o?t:t.toLowerCase(),this.query=Z(this.pattern,this.options)}return o(e,[{key:"searchIn",value:function(e){var t=this.query;if(!t)return{isMatch:!1,score:1};var n=this.options,r=n.includeMatches;e=n.isCaseSensitive?e:e.toLowerCase();for(var i=0,o=[],c=0,a=0,s=t.length;a-1&&(n.refIndex=e.idx),t.matches.push(n)}}))}function ve(e,t){t.score=e.score}function ge(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.includeMatches,i=void 0===r?I.includeMatches:r,o=n.includeScore,c=void 0===o?I.includeScore:o,a=[];return i&&a.push(de),c&&a.push(ve),e.map((function(e){var n=e.idx,r={item:t[n],refIndex:n};return a.length&&a.forEach((function(t){t(e,r)})),r}))}var ye=function(){function e(n){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=arguments.length>2?arguments[2]:void 0;r(this,e),this.options=t(t({},I),i),this.options.useExtendedSearch,this._keyStore=new S(this.options.keys),this.setCollection(n,o)}return o(e,[{key:"setCollection",value:function(e,t){if(this._docs=e,t&&!(t instanceof $))throw new Error("Incorrect 'index' type");this._myIndex=t||F(this.options.keys,this._docs,{getFn:this.options.getFn,fieldNormWeight:this.options.fieldNormWeight})}},{key:"add",value:function(e){k(e)&&(this._docs.push(e),this._myIndex.add(e))}},{key:"remove",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!1},t=[],n=0,r=this._docs.length;n1&&void 0!==arguments[1]?arguments[1]:{},n=t.limit,r=void 0===n?-1:n,i=this.options,o=i.includeMatches,c=i.includeScore,a=i.shouldSort,s=i.sortFn,u=i.ignoreFieldNorm,h=g(e)?g(this._docs[0])?this._searchStringList(e):this._searchObjectList(e):this._searchLogical(e);return fe(h,{ignoreFieldNorm:u}),a&&h.sort(s),y(r)&&r>-1&&(h=h.slice(0,r)),ge(h,this._docs,{includeMatches:o,includeScore:c})}},{key:"_searchStringList",value:function(e){var t=re(e,this.options),n=this._myIndex.records,r=[];return n.forEach((function(e){var n=e.v,i=e.i,o=e.n;if(k(n)){var c=t.searchIn(n),a=c.isMatch,s=c.score,u=c.indices;a&&r.push({item:n,idx:i,matches:[{score:s,value:n,norm:o,indices:u}]})}})),r}},{key:"_searchLogical",value:function(e){var t=this,n=function(e,t){var n=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).auto,r=void 0===n||n,i=function e(n){var i=Object.keys(n),o=ue(n);if(!o&&i.length>1&&!se(n))return e(le(n));if(he(n)){var c=o?n[ce]:i[0],a=o?n[ae]:n[c];if(!g(a))throw new Error(x(c));var s={keyId:j(c),pattern:a};return r&&(s.searcher=re(a,t)),s}var u={children:[],operator:i[0]};return i.forEach((function(t){var r=n[t];v(r)&&r.forEach((function(t){u.children.push(e(t))}))})),u};return se(e)||(e=le(e)),i(e)}(e,this.options),r=function e(n,r,i){if(!n.children){var o=n.keyId,c=n.searcher,a=t._findMatches({key:t._keyStore.get(o),value:t._myIndex.getValueForItemAtKeyId(r,o),searcher:c});return a&&a.length?[{idx:i,item:r,matches:a}]:[]}for(var s=[],u=0,h=n.children.length;u1&&void 0!==arguments[1]?arguments[1]:{},n=t.getFn,r=void 0===n?I.getFn:n,i=t.fieldNormWeight,o=void 0===i?I.fieldNormWeight:i,c=e.keys,a=e.records,s=new $({getFn:r,fieldNormWeight:o});return s.setKeys(c),s.setIndexRecords(a),s},ye.config=I,function(){ne.push.apply(ne,arguments)}(te),ye},"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Fuse=t(); \ No newline at end of file diff --git a/site_libs/quarto-search/quarto-search.js b/site_libs/quarto-search/quarto-search.js new file mode 100644 index 0000000..d788a95 --- /dev/null +++ b/site_libs/quarto-search/quarto-search.js @@ -0,0 +1,1290 @@ +const kQueryArg = "q"; +const kResultsArg = "show-results"; + +// If items don't provide a URL, then both the navigator and the onSelect +// function aren't called (and therefore, the default implementation is used) +// +// We're using this sentinel URL to signal to those handlers that this +// item is a more item (along with the type) and can be handled appropriately +const kItemTypeMoreHref = "0767FDFD-0422-4E5A-BC8A-3BE11E5BBA05"; + +window.document.addEventListener("DOMContentLoaded", function (_event) { + // Ensure that search is available on this page. If it isn't, + // should return early and not do anything + var searchEl = window.document.getElementById("quarto-search"); + if (!searchEl) return; + + const { autocomplete } = window["@algolia/autocomplete-js"]; + + let quartoSearchOptions = {}; + let language = {}; + const searchOptionEl = window.document.getElementById( + "quarto-search-options" + ); + if (searchOptionEl) { + const jsonStr = searchOptionEl.textContent; + quartoSearchOptions = JSON.parse(jsonStr); + language = quartoSearchOptions.language; + } + + // note the search mode + if (quartoSearchOptions.type === "overlay") { + searchEl.classList.add("type-overlay"); + } else { + searchEl.classList.add("type-textbox"); + } + + // Used to determine highlighting behavior for this page + // A `q` query param is expected when the user follows a search + // to this page + const currentUrl = new URL(window.location); + const query = currentUrl.searchParams.get(kQueryArg); + const showSearchResults = currentUrl.searchParams.get(kResultsArg); + const mainEl = window.document.querySelector("main"); + + // highlight matches on the page + if (query && mainEl) { + // perform any highlighting + highlight(escapeRegExp(query), mainEl); + + // fix up the URL to remove the q query param + const replacementUrl = new URL(window.location); + replacementUrl.searchParams.delete(kQueryArg); + window.history.replaceState({}, "", replacementUrl); + } + + // function to clear highlighting on the page when the search query changes + // (e.g. if the user edits the query or clears it) + let highlighting = true; + const resetHighlighting = (searchTerm) => { + if (mainEl && highlighting && query && searchTerm !== query) { + clearHighlight(query, mainEl); + highlighting = false; + } + }; + + // Clear search highlighting when the user scrolls sufficiently + const resetFn = () => { + resetHighlighting(""); + window.removeEventListener("quarto-hrChanged", resetFn); + window.removeEventListener("quarto-sectionChanged", resetFn); + }; + + // Register this event after the initial scrolling and settling of events + // on the page + window.addEventListener("quarto-hrChanged", resetFn); + window.addEventListener("quarto-sectionChanged", resetFn); + + // Responsively switch to overlay mode if the search is present on the navbar + // Note that switching the sidebar to overlay mode requires more coordinate (not just + // the media query since we generate different HTML for sidebar overlays than we do + // for sidebar input UI) + const detachedMediaQuery = + quartoSearchOptions.type === "overlay" ? "all" : "(max-width: 991px)"; + + // If configured, include the analytics client to send insights + const plugins = configurePlugins(quartoSearchOptions); + + let lastState = null; + const { setIsOpen, setQuery, setCollections } = autocomplete({ + container: searchEl, + detachedMediaQuery: detachedMediaQuery, + defaultActiveItemId: 0, + panelContainer: "#quarto-search-results", + panelPlacement: quartoSearchOptions["panel-placement"], + debug: false, + openOnFocus: true, + plugins, + classNames: { + form: "d-flex", + }, + placeholder: language["search-text-placeholder"], + translations: { + clearButtonTitle: language["search-clear-button-title"], + detachedCancelButtonText: language["search-detached-cancel-button-title"], + submitButtonTitle: language["search-submit-button-title"], + }, + initialState: { + query, + }, + getItemUrl({ item }) { + return item.href; + }, + onStateChange({ state }) { + // If this is a file URL, note that + + // Perhaps reset highlighting + resetHighlighting(state.query); + + // If the panel just opened, ensure the panel is positioned properly + if (state.isOpen) { + if (lastState && !lastState.isOpen) { + setTimeout(() => { + positionPanel(quartoSearchOptions["panel-placement"]); + }, 150); + } + } + + // Perhaps show the copy link + showCopyLink(state.query, quartoSearchOptions); + + lastState = state; + }, + reshape({ sources, state }) { + return sources.map((source) => { + try { + const items = source.getItems(); + + // Validate the items + validateItems(items); + + // group the items by document + const groupedItems = new Map(); + items.forEach((item) => { + const hrefParts = item.href.split("#"); + const baseHref = hrefParts[0]; + const isDocumentItem = hrefParts.length === 1; + + const items = groupedItems.get(baseHref); + if (!items) { + groupedItems.set(baseHref, [item]); + } else { + // If the href for this item matches the document + // exactly, place this item first as it is the item that represents + // the document itself + if (isDocumentItem) { + items.unshift(item); + } else { + items.push(item); + } + groupedItems.set(baseHref, items); + } + }); + + const reshapedItems = []; + let count = 1; + for (const [_key, value] of groupedItems) { + const firstItem = value[0]; + reshapedItems.push({ + ...firstItem, + type: kItemTypeDoc, + }); + + const collapseMatches = quartoSearchOptions["collapse-after"]; + const collapseCount = + typeof collapseMatches === "number" ? collapseMatches : 1; + + if (value.length > 1) { + const target = `search-more-${count}`; + const isExpanded = + state.context.expanded && + state.context.expanded.includes(target); + + const remainingCount = value.length - collapseCount; + + for (let i = 1; i < value.length; i++) { + if (collapseMatches && i === collapseCount) { + reshapedItems.push({ + target, + title: isExpanded + ? language["search-hide-matches-text"] + : remainingCount === 1 + ? `${remainingCount} ${language["search-more-match-text"]}` + : `${remainingCount} ${language["search-more-matches-text"]}`, + type: kItemTypeMore, + href: kItemTypeMoreHref, + }); + } + + if (isExpanded || !collapseMatches || i < collapseCount) { + reshapedItems.push({ + ...value[i], + type: kItemTypeItem, + target, + }); + } + } + } + count += 1; + } + + return { + ...source, + getItems() { + return reshapedItems; + }, + }; + } catch (error) { + // Some form of error occurred + return { + ...source, + getItems() { + return [ + { + title: error.name || "An Error Occurred While Searching", + text: + error.message || + "An unknown error occurred while attempting to perform the requested search.", + type: kItemTypeError, + }, + ]; + }, + }; + } + }); + }, + navigator: { + navigate({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + window.location.assign(itemUrl); + } + }, + navigateNewTab({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + const windowReference = window.open(itemUrl, "_blank", "noopener"); + if (windowReference) { + windowReference.focus(); + } + } + }, + navigateNewWindow({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + window.open(itemUrl, "_blank", "noopener"); + } + }, + }, + getSources({ state, setContext, setActiveItemId, refresh }) { + return [ + { + sourceId: "documents", + getItemUrl({ item }) { + if (item.href) { + return offsetURL(item.href); + } else { + return undefined; + } + }, + onSelect({ + item, + state, + setContext, + setIsOpen, + setActiveItemId, + refresh, + }) { + if (item.type === kItemTypeMore) { + toggleExpanded(item, state, setContext, setActiveItemId, refresh); + + // Toggle more + setIsOpen(true); + } + }, + getItems({ query }) { + if (query === null || query === "") { + return []; + } + + const limit = quartoSearchOptions.limit; + if (quartoSearchOptions.algolia) { + return algoliaSearch(query, limit, quartoSearchOptions.algolia); + } else { + // Fuse search options + const fuseSearchOptions = { + isCaseSensitive: false, + shouldSort: true, + minMatchCharLength: 2, + limit: limit, + }; + + return readSearchData().then(function (fuse) { + return fuseSearch(query, fuse, fuseSearchOptions); + }); + } + }, + templates: { + noResults({ createElement }) { + const hasQuery = lastState.query; + + return createElement( + "div", + { + class: `quarto-search-no-results${ + hasQuery ? "" : " no-query" + }`, + }, + language["search-no-results-text"] + ); + }, + header({ items, createElement }) { + // count the documents + const count = items.filter((item) => { + return item.type === kItemTypeDoc; + }).length; + + if (count > 0) { + return createElement( + "div", + { class: "search-result-header" }, + `${count} ${language["search-matching-documents-text"]}` + ); + } else { + return createElement( + "div", + { class: "search-result-header-no-results" }, + `` + ); + } + }, + footer({ _items, createElement }) { + if ( + quartoSearchOptions.algolia && + quartoSearchOptions.algolia["show-logo"] + ) { + const libDir = quartoSearchOptions.algolia["libDir"]; + const logo = createElement("img", { + src: offsetURL( + `${libDir}/quarto-search/search-by-algolia.svg` + ), + class: "algolia-search-logo", + }); + return createElement( + "a", + { href: "http://www.algolia.com/" }, + logo + ); + } + }, + + item({ item, createElement }) { + return renderItem( + item, + createElement, + state, + setActiveItemId, + setContext, + refresh, + quartoSearchOptions + ); + }, + }, + }, + ]; + }, + }); + + window.quartoOpenSearch = () => { + setIsOpen(false); + setIsOpen(true); + focusSearchInput(); + }; + + document.addEventListener("keyup", (event) => { + const { key } = event; + const kbds = quartoSearchOptions["keyboard-shortcut"]; + const focusedEl = document.activeElement; + + const isFormElFocused = [ + "input", + "select", + "textarea", + "button", + "option", + ].find((tag) => { + return focusedEl.tagName.toLowerCase() === tag; + }); + + if ( + kbds && + kbds.includes(key) && + !isFormElFocused && + !document.activeElement.isContentEditable + ) { + event.preventDefault(); + window.quartoOpenSearch(); + } + }); + + // Remove the labeleledby attribute since it is pointing + // to a non-existent label + if (quartoSearchOptions.type === "overlay") { + const inputEl = window.document.querySelector( + "#quarto-search .aa-Autocomplete" + ); + if (inputEl) { + inputEl.removeAttribute("aria-labelledby"); + } + } + + function throttle(func, wait) { + let waiting = false; + return function () { + if (!waiting) { + func.apply(this, arguments); + waiting = true; + setTimeout(function () { + waiting = false; + }, wait); + } + }; + } + + // If the main document scrolls dismiss the search results + // (otherwise, since they're floating in the document they can scroll with the document) + window.document.body.onscroll = throttle(() => { + // Only do this if we're not detached + // Bug #7117 + // This will happen when the keyboard is shown on ios (resulting in a scroll) + // which then closed the search UI + if (!window.matchMedia(detachedMediaQuery).matches) { + setIsOpen(false); + } + }, 50); + + if (showSearchResults) { + setIsOpen(true); + focusSearchInput(); + } +}); + +function configurePlugins(quartoSearchOptions) { + const autocompletePlugins = []; + const algoliaOptions = quartoSearchOptions.algolia; + if ( + algoliaOptions && + algoliaOptions["analytics-events"] && + algoliaOptions["search-only-api-key"] && + algoliaOptions["application-id"] + ) { + const apiKey = algoliaOptions["search-only-api-key"]; + const appId = algoliaOptions["application-id"]; + + // Aloglia insights may not be loaded because they require cookie consent + // Use deferred loading so events will start being recorded when/if consent + // is granted. + const algoliaInsightsDeferredPlugin = deferredLoadPlugin(() => { + if ( + window.aa && + window["@algolia/autocomplete-plugin-algolia-insights"] + ) { + window.aa("init", { + appId, + apiKey, + useCookie: true, + }); + + const { createAlgoliaInsightsPlugin } = + window["@algolia/autocomplete-plugin-algolia-insights"]; + // Register the insights client + const algoliaInsightsPlugin = createAlgoliaInsightsPlugin({ + insightsClient: window.aa, + onItemsChange({ insights, insightsEvents }) { + const events = insightsEvents.flatMap((event) => { + // This API limits the number of items per event to 20 + const chunkSize = 20; + const itemChunks = []; + const eventItems = event.items; + for (let i = 0; i < eventItems.length; i += chunkSize) { + itemChunks.push(eventItems.slice(i, i + chunkSize)); + } + // Split the items into multiple events that can be sent + const events = itemChunks.map((items) => { + return { + ...event, + items, + }; + }); + return events; + }); + + for (const event of events) { + insights.viewedObjectIDs(event); + } + }, + }); + return algoliaInsightsPlugin; + } + }); + + // Add the plugin + autocompletePlugins.push(algoliaInsightsDeferredPlugin); + return autocompletePlugins; + } +} + +// For plugins that may not load immediately, create a wrapper +// plugin and forward events and plugin data once the plugin +// is initialized. This is useful for cases like cookie consent +// which may prevent the analytics insights event plugin from initializing +// immediately. +function deferredLoadPlugin(createPlugin) { + let plugin = undefined; + let subscribeObj = undefined; + const wrappedPlugin = () => { + if (!plugin && subscribeObj) { + plugin = createPlugin(); + if (plugin && plugin.subscribe) { + plugin.subscribe(subscribeObj); + } + } + return plugin; + }; + + return { + subscribe: (obj) => { + subscribeObj = obj; + }, + onStateChange: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onStateChange) { + plugin.onStateChange(obj); + } + }, + onSubmit: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onSubmit) { + plugin.onSubmit(obj); + } + }, + onReset: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onReset) { + plugin.onReset(obj); + } + }, + getSources: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.getSources) { + return plugin.getSources(obj); + } else { + return Promise.resolve([]); + } + }, + data: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.data) { + plugin.data(obj); + } + }, + }; +} + +function validateItems(items) { + // Validate the first item + if (items.length > 0) { + const item = items[0]; + const missingFields = []; + if (item.href == undefined) { + missingFields.push("href"); + } + if (!item.title == undefined) { + missingFields.push("title"); + } + if (!item.text == undefined) { + missingFields.push("text"); + } + + if (missingFields.length === 1) { + throw { + name: `Error: Search index is missing the ${missingFields[0]} field.`, + message: `The items being returned for this search do not include all the required fields. Please ensure that your index items include the ${missingFields[0]} field or use index-fields in your _quarto.yml file to specify the field names.`, + }; + } else if (missingFields.length > 1) { + const missingFieldList = missingFields + .map((field) => { + return `${field}`; + }) + .join(", "); + + throw { + name: `Error: Search index is missing the following fields: ${missingFieldList}.`, + message: `The items being returned for this search do not include all the required fields. Please ensure that your index items includes the following fields: ${missingFieldList}, or use index-fields in your _quarto.yml file to specify the field names.`, + }; + } + } +} + +let lastQuery = null; +function showCopyLink(query, options) { + const language = options.language; + lastQuery = query; + // Insert share icon + const inputSuffixEl = window.document.body.querySelector( + ".aa-Form .aa-InputWrapperSuffix" + ); + + if (inputSuffixEl) { + let copyButtonEl = window.document.body.querySelector( + ".aa-Form .aa-InputWrapperSuffix .aa-CopyButton" + ); + + if (copyButtonEl === null) { + copyButtonEl = window.document.createElement("button"); + copyButtonEl.setAttribute("class", "aa-CopyButton"); + copyButtonEl.setAttribute("type", "button"); + copyButtonEl.setAttribute("title", language["search-copy-link-title"]); + copyButtonEl.onmousedown = (e) => { + e.preventDefault(); + e.stopPropagation(); + }; + + const linkIcon = "bi-clipboard"; + const checkIcon = "bi-check2"; + + const shareIconEl = window.document.createElement("i"); + shareIconEl.setAttribute("class", `bi ${linkIcon}`); + copyButtonEl.appendChild(shareIconEl); + inputSuffixEl.prepend(copyButtonEl); + + const clipboard = new window.ClipboardJS(".aa-CopyButton", { + text: function (_trigger) { + const copyUrl = new URL(window.location); + copyUrl.searchParams.set(kQueryArg, lastQuery); + copyUrl.searchParams.set(kResultsArg, "1"); + return copyUrl.toString(); + }, + }); + clipboard.on("success", function (e) { + // Focus the input + + // button target + const button = e.trigger; + const icon = button.querySelector("i.bi"); + + // flash "checked" + icon.classList.add(checkIcon); + icon.classList.remove(linkIcon); + setTimeout(function () { + icon.classList.remove(checkIcon); + icon.classList.add(linkIcon); + }, 1000); + }); + } + + // If there is a query, show the link icon + if (copyButtonEl) { + if (lastQuery && options["copy-button"]) { + copyButtonEl.style.display = "flex"; + } else { + copyButtonEl.style.display = "none"; + } + } + } +} + +/* Search Index Handling */ +// create the index +var fuseIndex = undefined; +var shownWarning = false; + +// fuse index options +const kFuseIndexOptions = { + keys: [ + { name: "title", weight: 20 }, + { name: "section", weight: 20 }, + { name: "text", weight: 10 }, + ], + ignoreLocation: true, + threshold: 0.1, +}; + +async function readSearchData() { + // Initialize the search index on demand + if (fuseIndex === undefined) { + if (window.location.protocol === "file:" && !shownWarning) { + window.alert( + "Search requires JavaScript features disabled when running in file://... URLs. In order to use search, please run this document in a web server." + ); + shownWarning = true; + return; + } + const fuse = new window.Fuse([], kFuseIndexOptions); + + // fetch the main search.json + const response = await fetch(offsetURL("search.json")); + if (response.status == 200) { + return response.json().then(function (searchDocs) { + searchDocs.forEach(function (searchDoc) { + fuse.add(searchDoc); + }); + fuseIndex = fuse; + return fuseIndex; + }); + } else { + return Promise.reject( + new Error( + "Unexpected status from search index request: " + response.status + ) + ); + } + } + + return fuseIndex; +} + +function inputElement() { + return window.document.body.querySelector(".aa-Form .aa-Input"); +} + +function focusSearchInput() { + setTimeout(() => { + const inputEl = inputElement(); + if (inputEl) { + inputEl.focus(); + } + }, 50); +} + +/* Panels */ +const kItemTypeDoc = "document"; +const kItemTypeMore = "document-more"; +const kItemTypeItem = "document-item"; +const kItemTypeError = "error"; + +function renderItem( + item, + createElement, + state, + setActiveItemId, + setContext, + refresh, + quartoSearchOptions +) { + switch (item.type) { + case kItemTypeDoc: + return createDocumentCard( + createElement, + "file-richtext", + item.title, + item.section, + item.text, + item.href, + item.crumbs, + quartoSearchOptions + ); + case kItemTypeMore: + return createMoreCard( + createElement, + item, + state, + setActiveItemId, + setContext, + refresh + ); + case kItemTypeItem: + return createSectionCard( + createElement, + item.section, + item.text, + item.href + ); + case kItemTypeError: + return createErrorCard(createElement, item.title, item.text); + default: + return undefined; + } +} + +function createDocumentCard( + createElement, + icon, + title, + section, + text, + href, + crumbs, + quartoSearchOptions +) { + const iconEl = createElement("i", { + class: `bi bi-${icon} search-result-icon`, + }); + const titleEl = createElement("p", { class: "search-result-title" }, title); + const titleContents = [iconEl, titleEl]; + const showParent = quartoSearchOptions["show-item-context"]; + if (crumbs && showParent) { + let crumbsOut = undefined; + const crumbClz = ["search-result-crumbs"]; + if (showParent === "root") { + crumbsOut = crumbs.length > 1 ? crumbs[0] : undefined; + } else if (showParent === "parent") { + crumbsOut = crumbs.length > 1 ? crumbs[crumbs.length - 2] : undefined; + } else { + crumbsOut = crumbs.length > 1 ? crumbs.join(" > ") : undefined; + crumbClz.push("search-result-crumbs-wrap"); + } + + const crumbEl = createElement( + "p", + { class: crumbClz.join(" ") }, + crumbsOut + ); + titleContents.push(crumbEl); + } + + const titleContainerEl = createElement( + "div", + { class: "search-result-title-container" }, + titleContents + ); + + const textEls = []; + if (section) { + const sectionEl = createElement( + "p", + { class: "search-result-section" }, + section + ); + textEls.push(sectionEl); + } + const descEl = createElement("p", { + class: "search-result-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + textEls.push(descEl); + + const textContainerEl = createElement( + "div", + { class: "search-result-text-container" }, + textEls + ); + + const containerEl = createElement( + "div", + { + class: "search-result-container", + }, + [titleContainerEl, textContainerEl] + ); + + const linkEl = createElement( + "a", + { + href: offsetURL(href), + class: "search-result-link", + }, + containerEl + ); + + const classes = ["search-result-doc", "search-item"]; + if (!section) { + classes.push("document-selectable"); + } + + return createElement( + "div", + { + class: classes.join(" "), + }, + linkEl + ); +} + +function createMoreCard( + createElement, + item, + state, + setActiveItemId, + setContext, + refresh +) { + const moreCardEl = createElement( + "div", + { + class: "search-result-more search-item", + onClick: (e) => { + // Handle expanding the sections by adding the expanded + // section to the list of expanded sections + toggleExpanded(item, state, setContext, setActiveItemId, refresh); + e.stopPropagation(); + }, + }, + item.title + ); + + return moreCardEl; +} + +function toggleExpanded(item, state, setContext, setActiveItemId, refresh) { + const expanded = state.context.expanded || []; + if (expanded.includes(item.target)) { + setContext({ + expanded: expanded.filter((target) => target !== item.target), + }); + } else { + setContext({ expanded: [...expanded, item.target] }); + } + + refresh(); + setActiveItemId(item.__autocomplete_id); +} + +function createSectionCard(createElement, section, text, href) { + const sectionEl = createSection(createElement, section, text, href); + return createElement( + "div", + { + class: "search-result-doc-section search-item", + }, + sectionEl + ); +} + +function createSection(createElement, title, text, href) { + const descEl = createElement("p", { + class: "search-result-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + + const titleEl = createElement("p", { class: "search-result-section" }, title); + const linkEl = createElement( + "a", + { + href: offsetURL(href), + class: "search-result-link", + }, + [titleEl, descEl] + ); + return linkEl; +} + +function createErrorCard(createElement, title, text) { + const descEl = createElement("p", { + class: "search-error-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + + const titleEl = createElement("p", { + class: "search-error-title", + dangerouslySetInnerHTML: { + __html: ` ${title}`, + }, + }); + const errorEl = createElement("div", { class: "search-error" }, [ + titleEl, + descEl, + ]); + return errorEl; +} + +function positionPanel(pos) { + const panelEl = window.document.querySelector( + "#quarto-search-results .aa-Panel" + ); + const inputEl = window.document.querySelector( + "#quarto-search .aa-Autocomplete" + ); + + if (panelEl && inputEl) { + panelEl.style.top = `${Math.round(panelEl.offsetTop)}px`; + if (pos === "start") { + panelEl.style.left = `${Math.round(inputEl.left)}px`; + } else { + panelEl.style.right = `${Math.round(inputEl.offsetRight)}px`; + } + } +} + +/* Highlighting */ +// highlighting functions +function highlightMatch(query, text) { + if (text) { + const start = text.toLowerCase().indexOf(query.toLowerCase()); + if (start !== -1) { + const startMark = ""; + const endMark = ""; + + const end = start + query.length; + text = + text.slice(0, start) + + startMark + + text.slice(start, end) + + endMark + + text.slice(end); + const startInfo = clipStart(text, start); + const endInfo = clipEnd( + text, + startInfo.position + startMark.length + endMark.length + ); + text = + startInfo.prefix + + text.slice(startInfo.position, endInfo.position) + + endInfo.suffix; + + return text; + } else { + return text; + } + } else { + return text; + } +} + +function clipStart(text, pos) { + const clipStart = pos - 50; + if (clipStart < 0) { + // This will just return the start of the string + return { + position: 0, + prefix: "", + }; + } else { + // We're clipping before the start of the string, walk backwards to the first space. + const spacePos = findSpace(text, pos, -1); + return { + position: spacePos.position, + prefix: "", + }; + } +} + +function clipEnd(text, pos) { + const clipEnd = pos + 200; + if (clipEnd > text.length) { + return { + position: text.length, + suffix: "", + }; + } else { + const spacePos = findSpace(text, clipEnd, 1); + return { + position: spacePos.position, + suffix: spacePos.clipped ? "…" : "", + }; + } +} + +function findSpace(text, start, step) { + let stepPos = start; + while (stepPos > -1 && stepPos < text.length) { + const char = text[stepPos]; + if (char === " " || char === "," || char === ":") { + return { + position: step === 1 ? stepPos : stepPos - step, + clipped: stepPos > 1 && stepPos < text.length, + }; + } + stepPos = stepPos + step; + } + + return { + position: stepPos - step, + clipped: false, + }; +} + +// removes highlighting as implemented by the mark tag +function clearHighlight(searchterm, el) { + const childNodes = el.childNodes; + for (let i = childNodes.length - 1; i >= 0; i--) { + const node = childNodes[i]; + if (node.nodeType === Node.ELEMENT_NODE) { + if ( + node.tagName === "MARK" && + node.innerText.toLowerCase() === searchterm.toLowerCase() + ) { + el.replaceChild(document.createTextNode(node.innerText), node); + } else { + clearHighlight(searchterm, node); + } + } + } +} + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string +} + +// highlight matches +function highlight(term, el) { + const termRegex = new RegExp(term, "ig"); + const childNodes = el.childNodes; + + // walk back to front avoid mutating elements in front of us + for (let i = childNodes.length - 1; i >= 0; i--) { + const node = childNodes[i]; + + if (node.nodeType === Node.TEXT_NODE) { + // Search text nodes for text to highlight + const text = node.nodeValue; + + let startIndex = 0; + let matchIndex = text.search(termRegex); + if (matchIndex > -1) { + const markFragment = document.createDocumentFragment(); + while (matchIndex > -1) { + const prefix = text.slice(startIndex, matchIndex); + markFragment.appendChild(document.createTextNode(prefix)); + + const mark = document.createElement("mark"); + mark.appendChild( + document.createTextNode( + text.slice(matchIndex, matchIndex + term.length) + ) + ); + markFragment.appendChild(mark); + + startIndex = matchIndex + term.length; + matchIndex = text.slice(startIndex).search(new RegExp(term, "ig")); + if (matchIndex > -1) { + matchIndex = startIndex + matchIndex; + } + } + if (startIndex < text.length) { + markFragment.appendChild( + document.createTextNode(text.slice(startIndex, text.length)) + ); + } + + el.replaceChild(markFragment, node); + } + } else if (node.nodeType === Node.ELEMENT_NODE) { + // recurse through elements + highlight(term, node); + } + } +} + +/* Link Handling */ +// get the offset from this page for a given site root relative url +function offsetURL(url) { + var offset = getMeta("quarto:offset"); + return offset ? offset + url : url; +} + +// read a meta tag value +function getMeta(metaName) { + var metas = window.document.getElementsByTagName("meta"); + for (let i = 0; i < metas.length; i++) { + if (metas[i].getAttribute("name") === metaName) { + return metas[i].getAttribute("content"); + } + } + return ""; +} + +function algoliaSearch(query, limit, algoliaOptions) { + const { getAlgoliaResults } = window["@algolia/autocomplete-preset-algolia"]; + + const applicationId = algoliaOptions["application-id"]; + const searchOnlyApiKey = algoliaOptions["search-only-api-key"]; + const indexName = algoliaOptions["index-name"]; + const indexFields = algoliaOptions["index-fields"]; + const searchClient = window.algoliasearch(applicationId, searchOnlyApiKey); + const searchParams = algoliaOptions["params"]; + const searchAnalytics = !!algoliaOptions["analytics-events"]; + + return getAlgoliaResults({ + searchClient, + queries: [ + { + indexName: indexName, + query, + params: { + hitsPerPage: limit, + clickAnalytics: searchAnalytics, + ...searchParams, + }, + }, + ], + transformResponse: (response) => { + if (!indexFields) { + return response.hits.map((hit) => { + return hit.map((item) => { + return { + ...item, + text: highlightMatch(query, item.text), + }; + }); + }); + } else { + const remappedHits = response.hits.map((hit) => { + return hit.map((item) => { + const newItem = { ...item }; + ["href", "section", "title", "text", "crumbs"].forEach( + (keyName) => { + const mappedName = indexFields[keyName]; + if ( + mappedName && + item[mappedName] !== undefined && + mappedName !== keyName + ) { + newItem[keyName] = item[mappedName]; + delete newItem[mappedName]; + } + } + ); + newItem.text = highlightMatch(query, newItem.text); + return newItem; + }); + }); + return remappedHits; + } + }, + }); +} + +let subSearchTerm = undefined; +let subSearchFuse = undefined; +const kFuseMaxWait = 125; + +async function fuseSearch(query, fuse, fuseOptions) { + let index = fuse; + // Fuse.js using the Bitap algorithm for text matching which runs in + // O(nm) time (no matter the structure of the text). In our case this + // means that long search terms mixed with large index gets very slow + // + // This injects a subIndex that will be used once the terms get long enough + // Usually making this subindex is cheap since there will typically be + // a subset of results matching the existing query + if (subSearchFuse !== undefined && query.startsWith(subSearchTerm)) { + // Use the existing subSearchFuse + index = subSearchFuse; + } else if (subSearchFuse !== undefined) { + // The term changed, discard the existing fuse + subSearchFuse = undefined; + subSearchTerm = undefined; + } + + // Search using the active fuse + const then = performance.now(); + const resultsRaw = await index.search(query, fuseOptions); + const now = performance.now(); + + const results = resultsRaw.map((result) => { + const addParam = (url, name, value) => { + const anchorParts = url.split("#"); + const baseUrl = anchorParts[0]; + const sep = baseUrl.search("\\?") > 0 ? "&" : "?"; + anchorParts[0] = baseUrl + sep + name + "=" + value; + return anchorParts.join("#"); + }; + + return { + title: result.item.title, + section: result.item.section, + href: addParam(result.item.href, kQueryArg, query), + text: highlightMatch(query, result.item.text), + crumbs: result.item.crumbs, + }; + }); + + // If we don't have a subfuse and the query is long enough, go ahead + // and create a subfuse to use for subsequent queries + if ( + now - then > kFuseMaxWait && + subSearchFuse === undefined && + resultsRaw.length < fuseOptions.limit + ) { + subSearchTerm = query; + subSearchFuse = new window.Fuse([], kFuseIndexOptions); + resultsRaw.forEach((rr) => { + subSearchFuse.add(rr.item); + }); + } + return results; +} diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..4d13a1b --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,63 @@ + + + + https://franckalbinet.github.io/marisco/handlers/maris_legacy.html + 2024-09-13T22:10:49.812Z + + + https://franckalbinet.github.io/marisco/handlers/netcdf_to_csv.html + 2024-09-13T22:10:49.676Z + + + https://franckalbinet.github.io/marisco/api/nc_template.html + 2024-09-13T22:10:49.416Z + + + https://franckalbinet.github.io/marisco/api/configs.html + 2024-09-13T22:10:49.324Z + + + https://franckalbinet.github.io/marisco/api/callbacks.html + 2024-09-13T22:10:49.264Z + + + https://franckalbinet.github.io/marisco/api/inout.html + 2024-09-13T22:10:48.656Z + + + https://franckalbinet.github.io/marisco/cli/netcdfy.html + 2024-09-13T22:10:49.120Z + + + https://franckalbinet.github.io/marisco/index.html + 2024-09-13T22:10:48.604Z + + + https://franckalbinet.github.io/marisco/cli/init.html + 2024-09-13T22:10:49.296Z + + + https://franckalbinet.github.io/marisco/cli/create_nc_template.html + 2024-09-13T22:10:49.128Z + + + https://franckalbinet.github.io/marisco/api/serializers.html + 2024-09-13T22:10:49.152Z + + + https://franckalbinet.github.io/marisco/api/metadata.html + 2024-09-13T22:10:49.424Z + + + https://franckalbinet.github.io/marisco/api/utils.html + 2024-09-13T22:10:49.572Z + + + https://franckalbinet.github.io/marisco/handlers/helcom.html + 2024-09-13T22:10:49.872Z + + + https://franckalbinet.github.io/marisco/handlers/geotraces.html + 2024-09-13T22:10:49.668Z + + diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..f78354b --- /dev/null +++ b/styles.css @@ -0,0 +1,68 @@ +@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@700&display=swap'); + +.cell { + margin-bottom: 1rem; +} + +.cell>.sourceCode { + margin-bottom: 0; +} + +.cell-output>pre { + margin-bottom: 0; +} + +.cell-output>pre, +.cell-output>.sourceCode>pre, +.cell-output-stdout>pre { + margin-left: 0.8rem; + margin-top: 0; + background: none; + border-left: 2px solid lightsalmon; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.cell-output>.sourceCode { + border: none; +} + +.cell-output>.sourceCode { + background: none; + margin-top: 0; +} + +div.description { + padding-left: 2px; + padding-top: 5px; + font-style: italic; + font-size: 135%; + opacity: 70%; +} + +.navbar { + background-color: #3a6494 +} + +.navbar-brand { + text-transform: uppercase; + font-weight: bold; + font-family: 'Montserrat', sans-serif; + font-size: 1.2rem; + + background-image: url('./img/logo.png'); + background-repeat: no-repeat; + background-position: left center; + background-size: 65px 65px; + /* Increased logo size */ + + padding-left: 60px; + /* Increased to add more space between logo and text */ + height: 40px; + line-height: 40px; + /* Ensures vertical centering of text */ + + display: flex; + align-items: center; + /* This helps with vertical alignment */ +} \ No newline at end of file