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..be3dba2 --- /dev/null +++ b/api/callbacks.html @@ -0,0 +1,1449 @@ + + + + + + + + + + +Callbacks – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+ +
+ +
+
+ Callback used in handlers +
+
+ + +
+ + + + +
+ + + +
+ + + +
+

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

+
+

source

+
+

RemoveAllNAValuesCB

+
+
 RemoveAllNAValuesCB (cols_to_check:dict)
+
+

Remove rows with all NA values.

+ +++++ + + + + + + + + + + + + + + +
TypeDetails
cols_to_checkdictA dictionary with the sample type as key and the column name to check as value
+
+
+Exported source +
class RemoveAllNAValuesCB(Callback):
+    "Remove rows with all NA values."
+    def __init__(self, 
+                 cols_to_check:dict # A dictionary with the sample type as key and the column name to check as value
+                ):
+        fc.store_attr()
+
+    def __call__(self, tfm):
+        for k in tfm.dfs.keys():
+            col_to_check = self.cols_to_check[k]
+            mask = tfm.dfs[k][col_to_check].isnull().all(axis=1)
+            tfm.dfs[k] = tfm.dfs[k][~mask]
+
+
+

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..fd958bd --- /dev/null +++ b/api/configs.html @@ -0,0 +1,1903 @@ + + + + + + + + + + +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. +
+
+ + +
+ + + + +
+ + + +
+ + + +
+

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..6079948 --- /dev/null +++ b/api/inout.html @@ -0,0 +1,797 @@ + + + + + + + + + + +Input/Output – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+ +
+ +
+
+ Files reader and writer. +
+
+ + +
+ + + + +
+ + + +
+ + + +
+

source

+
+

write_toml

+
+
 write_toml (fname, cfg)
+
+

Write a TOML file from a dictionary.

+
+
+Exported source +
def write_toml(fname, cfg):
+    "Write a TOML file from a dictionary."
+    print(f'Creating {fname}')
+    with open(fname, "wb") as f:
+        tomli_w.dump(cfg, f)
+
+
+
+

source

+
+
+

read_toml

+
+
 read_toml (fname)
+
+

Read a TOML file into a dictionary.

+
+
+Exported source +
def read_toml(fname):
+    "Read a TOML file into a dictionary."
+    with open(fname, "rb") as f:
+        config = tomli.load(f)
+    return config
+
+
+ + +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/api/metadata.html b/api/metadata.html new file mode 100644 index 0000000..6f87360 --- /dev/null +++ b/api/metadata.html @@ -0,0 +1,1057 @@ + + + + + + + + + + +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 +
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..ea3dfb1 --- /dev/null +++ b/api/nc_template.html @@ -0,0 +1,1358 @@ + + + + + + + + + + +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
+
+
+Exported source +
class NCTemplater:
+    "MARIS NetCDF template generator."
+    def __init__(self, 
+                 cdl:Dict, # "Pseudo CDL" (`.toml`)
+                 nuclide_vars_fname:str, # File name and path of MARIS nuclide lookup table containing variable names
+                 tpl_fname:str, # File name and path of NetCDF4 file to be generated
+                 enum_dicts:Dict, # MARIS NetCDF enumeration types
+                 verbose=False
+                ):
+        fc.store_attr()
+        self.dim = cdl['dim']
+        self.enum_types = {}
+
+
+

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)
+
+
+

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)
+
+
+Exported source +
@patch
+def nuclide_vars(
+    self:NCTemplater,
+    col_varnames:str='nc_name', # Column name in the Excel lookup file containing the NetCDF variable names
+    col_stdnames:str='nusymbol', # Column name Excel lookup file containing the NetCDF standard names
+    dtype:str='f4', # Default data type
+    ) -> list[dict]: # List of nuclide variables (including their names and attributes)
+    "Return the name of the radionuclide variables analysed."
+    df = pd.read_excel(self.nuclide_vars_fname, index_col=0)
+    
+    df = df[(df.nuclide != 'NOT AVAILABLE') & (df.nuclide != 'NOT APPLICABLE')]
+    # df = df[df.nuclide.isin(['NOT AVAILABLE', 'NOT APPLICABLE'])]
+    
+    return [
+        {
+            'name': n,
+            'dtype': dtype,
+            'attrs': {
+                'long_name': f"{nuclide.capitalize()} {massnb}",
+                'standard_name': sn,
+            }
+        }
+        for n, nuclide, massnb, sn in zip(
+            df[col_varnames],
+            df['nuclide'].str.capitalize(),
+            df['massnb'].astype(int),
+            df[col_stdnames],
+        )
+    ]
+
+
+

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
+
+
+Exported source +
@patch
+def derive(
+    self:NCTemplater,
+    nuclide:dict, # Nuclide variable name and associated netcdf attributes
+    suffix:dict,  # Naming rules as described in CDL (e.g `_unc`)
+) -> dict: # Derived variable name and associated attributes
+    "Derive NetCDF nuclide-dependent variable names & attributes as defined in CDL." 
+    return {
+        # 'name': nuclide['name'] + '_' + suffix['name'],
+        'name': nuclide['name'] + suffix['name'],
+        'dtype': suffix['dtype'],  # Using dtype from suffix
+        'attrs': {key: nuclide['attrs'][key] + suffix['attrs'][key] for key in nuclide['attrs']}
+        }
+
+
+

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

+
+
+Exported source +
@patch
+def create_enum_types(self:NCTemplater):
+    "Create enumeration types"
+    for name, enum in self.enum_dicts.items(): 
+        if self.verbose: print(f'Creating {name} enumeration type')
+        self.enum_types[name] = self.nc.createEnumType(np.int_, name, enum)
+
+
+
+

source

+
+
+

NCTemplater.create_groups

+
+
 NCTemplater.create_groups ()
+
+

Create NetCDF groups

+
+
+Exported source +
@patch
+def create_groups(self:NCTemplater):
+    "Create NetCDF groups"
+    grp_names = [v['name'] for k, v in self.cdl['grps'].items()]
+    for grp_name in grp_names:
+        grp = self.nc.createGroup(grp_name)
+        self.create_variables(grp)
+
+
+
+

source

+
+
+

NCTemplater.create_variables

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

Create variables

+ + + + + + + + + + + + + + + +
TypeDetails
grpGroupNetCDF group
+
+
+Exported source +
@patch
+def create_variables(self:NCTemplater, 
+                     grp:netCDF4.Group, # NetCDF group
+                     ):
+        "Create variables"
+        self.create_variable(grp, self.dim) # Dimension variable
+        self.create_default_variables(grp)
+        self.create_group_specific_variables(grp)
+        self.create_analyte_variables(grp)
+
+
+
+

source

+
+
+

NCTemplater.create_default_variables

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

Create Default variables

+ + + + + + + + + + + + + + + +
TypeDetails
grpGroupNetCDF group
+
+
+Exported source +
@patch
+def create_default_variables(self:NCTemplater, 
+                             grp:netCDF4.Group, # NetCDF group
+                             ):
+        "Create Default variables"
+        vars = self.cdl['vars']['defaults'].values()
+        for var in vars: self.create_variable(grp, var)
+
+
+
+

source

+
+
+

NCTemplater.create_group_specific_variables

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

Create group specific variables

+ + + + + + + + + + + + + + + +
TypeDetails
grpGroupNetCDF group
+
+
+Exported source +
@patch
+def create_group_specific_variables(self:NCTemplater, 
+                             grp:netCDF4.Group, # NetCDF group
+                             ):
+        "Create group specific variables"
+        vars = self.cdl['vars']
+        for var in vars.get(name2grp(grp.name, self.cdl), {}).values(): 
+            self.create_variable(grp, var)
+
+
+
+

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
+
+
+Exported source +
@patch
+def create_analyte_variables(self:NCTemplater, 
+                             grp:netCDF4.Group, # NetCDF group
+                             ):
+    "Create analyte variables and dependent one as uncertainty, detection limit, ..."    
+    for var in self.nuclide_vars():
+        self.create_variable(grp, var)
+        for v in self.cdl['vars']['suffixes'].values(): 
+            self.create_variable(grp, self.derive(var, v))
+
+
+
+

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
+
+
+Exported source +
@patch
+def create_variable(self:NCTemplater, 
+                    grp:netCDF4.Group, # NetCDF group
+                    var:Dict, # Variable specificiation dict with `name`, `dtype` and `attrs` keys
+                    ):
+    "Create NetCDF variable with proper types (standard and enums)"
+    name, dtype, attrs = var.values()
+    nc_var = grp.createVariable(name, 
+                                self.enum_types.get(dtype) or dtype, 
+                                self.dim['name'])
+    nc_var.setncatts(attrs)
+
+
+
+

source

+
+
+

NCTemplater.generate

+
+
 NCTemplater.generate ()
+
+

Generate CDL

+
+
+Exported source +
@patch
+def generate(self:NCTemplater):
+    "Generate CDL"
+    # with NetCDFWriter(self.tpl_fname) as self.nc:
+    with Dataset(self.tpl_fname, 'w', format='NETCDF4') as self.nc:
+        self.nc.setncatts(self.cdl['global_attrs']) 
+        self.create_enum_types()
+        self.nc.createDimension(self.dim['name'], None) 
+        self.create_groups()
+
+
+

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..65eacd3 --- /dev/null +++ b/api/serializers.html @@ -0,0 +1,1295 @@ + + + + + + + + + + +Serializers – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+ +
+ +
+
+ Various utilities to encode MARIS dataset as NetCDF, csv, … formats. +
+
+ + +
+ + + + +
+ + + +
+ + + +
+

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..98d24c4 --- /dev/null +++ b/api/utils.html @@ -0,0 +1,2031 @@ + + + + + + + + + + +Utilities – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+ +
+ +
+
+ Various utilities +
+
+ + +
+ + + + +
+ + + +
+ + + +
+

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():
+    "Remap a data provider lookup table to a MARIS lookup table using fuzzy matching."
+    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
+                 ):
+        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"): 
+            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
+            # If value is in fixes, use the fixed value
+            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'))
+
+

Get the bounding box of a DataFrame.

+
+
+Exported source +
def get_bbox(df,
+             coord_cols=('lon', 'lat')
+            ):
+    "Get the bounding box of a DataFrame."
+    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)
+
+
+
+

source

+
+
+

ddmm_to_dd

+
+
 ddmm_to_dd (ddmmmm:float)
+
+ + + + + + + + + + + + + + + + + + + + +
TypeDetails
ddmmmmfloatCoordinates in degrees/minutes decimal format
ReturnsfloatCoordinates in degrees decimal format
+
+
+Exported source +
def ddmm_to_dd(
+    ddmmmm:float # Coordinates in degrees/minutes decimal format
+    ) -> float: # Coordinates in degrees decimal format
+    # Convert degrees/minutes decimal to degrees decimal.
+    mins, degs = modf(ddmmmm)
+    mins = mins * 100
+    return round(int(degs) + (mins / 60), 6)
+
+
+
+
fc.test_close(ddmm_to_dd(45.34), 45.566667)
+
+
+
+
+

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'}]]
+
+
+
+
+
+

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)
+
+

Match between a data provider name and a MARIS lookup table.

+
+
+Exported source +
@dataclass
+class Match:
+    "Match between a data provider name and a MARIS lookup table."
+    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:

+
+
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'))
+
+
+
+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'}]]
+
+
+
+
+
+

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..54c3411 --- /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..a7a4732 --- /dev/null +++ b/handlers/helcom.html @@ -0,0 +1,6999 @@ + + + + + + + + + +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
  14. +
+

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

+
+

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
+14     14  CS137            9               5
+20     20     SR90          6               4
+31     31   PU238           8               5
+34     34     CS137         6               5
+37     37   K40             8               3
+53     53    SR90           7               4
+54     54      SR90         5               4
+59     59   SR90            8               4
+62     62   CO60            8               4
+69     69   CS134           8               5
+73     73    TC99           7               4
+75     75   AM241           8               5
+91     91   CS137           8               5
+
+
+

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
00pu239240
11cs144
22cs141
33cs140
44sn117m
+ +
+
+
+

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, 48.57it/s]
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
matched_maris_namesource_namematch_score
source_key
pu239240pu240pu2392403
pu238240pu240pu2382403
cm243244cm244cm2432443
cs134137cs137cs1341373
cs142ce144cs1422
cs145cs136cs1452
cs143cs127cs1432
cs144ce144cs1441
cs141ce141cs1411
cs140ce140cs1401
cs138cs137cs1381
cs139ce139cs1391
cs146cs136cs1461
k-40k40k-401
+ +
+
+
+

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.64it/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

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

FEEDBACK TO DATA PROVIDER: Time/date is provide in the DATE, YEAR , MONTH, DAY columns. Note that the DATE contains missing values as indicated below. When missing, we fallback on the YEAR, MONTH, DAY columns. Note also that sometimes DAY and MONTH contain 0. In this case we systematically set them to 1.

+
+
+
+
dfs = load_data(fname_in)
+for key in dfs.keys():
+    print(f'{key} DATE null values: ', dfs[key]['DATE'].isna().sum())
+
+
seawater DATE null values:  502
+sediment DATE null values:  741
+biota DATE null values:  72
+
+
+
+

source

+
+

ParseTimeCB

+
+
 ParseTimeCB ()
+
+

Parse and standardize time information in the dataframe.

+
+
+Exported source +
class ParseTimeCB(Callback):
+    "Parse and standardize time information in the dataframe."
+    def __call__(self, tfm):
+        for df in tfm.dfs.values():
+            self._process_dates(df)
+            self._define_beg_period(df)
+
+    def _process_dates(self, df):
+        "Process and correct date and time information in the DataFrame."
+        df['time'] = self._parse_date(df)
+        self._handle_missing_dates(df)
+        self._fill_missing_time(df)
+
+    def _parse_date(self, df):
+        "Parse the DATE column if present."
+        return pd.to_datetime(df['DATE'], format='%m/%d/%y %H:%M:%S', errors='coerce')
+
+    def _handle_missing_dates(self, df):
+        "Handle cases where DAY or MONTH is 0 or missing."
+        df.loc[df["DAY"] == 0, "DAY"] = 1
+        df.loc[df["MONTH"] == 0, "MONTH"] = 1
+        
+        missing_day_month = (df["DAY"].isna()) & (df["MONTH"].isna()) & (df["YEAR"].notna())
+        df.loc[missing_day_month, ["DAY", "MONTH"]] = 1
+
+    def _fill_missing_time(self, df):
+        "Fill missing time values using YEAR, MONTH, and DAY columns."
+        missing_time = df['time'].isna()
+        df.loc[missing_time, 'time'] = pd.to_datetime(
+            df.loc[missing_time, ['YEAR', 'MONTH', 'DAY']], 
+            format='%Y%m%d', 
+            errors='coerce'
+        )
+
+    def _define_beg_period(self, df):
+        "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]
+
+
+

NetCDF time format requires the time to be encoded as number of milliseconds since a time of origin. In our case the time of origin is 1970-01-01 as indicated in configs.ipynb CONFIFS['units']['time'] dictionary.

+

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 
+
+
+
+
+
tfm.dfs['seawater']
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KEYNUCLIDEMETHOD< VALUE_Bq/m³VALUE_Bq/m³ERROR%_m³DATE_OF_ENTRY_xCOUNTRYLABORATORYSEQUENCE...TDEPTHSDEPTHSALINTTEMPFILTMORS_SUBBASINHELCOM_SUBBASINDATE_OF_ENTRY_ytimebegperiod
0WKRIL2012003CS137NaNNaN5.332.00000008/20/14 00:00:0090.0KRIL2012003.0...NaN0.0NaNNaNNaN11.011.008/20/14 00:00:0013377312002012-05-23
1WKRIL2012004CS137NaNNaN19.920.00000008/20/14 00:00:0090.0KRIL2012004.0...NaN29.0NaNNaNNaN11.011.008/20/14 00:00:0013377312002012-05-23
2WKRIL2012005CS137NaNNaN25.520.00000008/20/14 00:00:0090.0KRIL2012005.0...NaN0.0NaNNaNNaN11.03.008/20/14 00:00:0013398912002012-06-17
3WKRIL2012006CS137NaNNaN17.029.00000008/20/14 00:00:0090.0KRIL2012006.0...NaN0.0NaNNaNNaN11.011.008/20/14 00:00:0013378176002012-05-24
4WKRIL2012007CS137NaNNaN22.218.00000008/20/14 00:00:0090.0KRIL2012007.0...NaN39.0NaNNaNNaN11.011.008/20/14 00:00:0013378176002012-05-24
..................................................................
21211WSSSM2021005H3SSM45NaN1030.093.20388309/06/22 00:00:0077.0SSSM202105.0...NaN1.0NaNNaNN1.08.009/06/22 00:00:0016342560002021-10-15
21212WSSSM2021006H3SSM45NaN2240.043.30357109/06/22 00:00:0077.0SSSM202106.0...NaN1.0NaNNaNN10.010.009/06/22 00:00:0016359840002021-11-04
21213WSSSM2021007H3SSM45NaN2060.047.08737909/06/22 00:00:0077.0SSSM202107.0...NaN1.0NaNNaNN12.012.009/06/22 00:00:0016342560002021-10-15
21214WSSSM2021008H3SSM45NaN2300.043.47826109/06/22 00:00:0077.0SSSM202108.0...NaN1.0NaNNaNN12.012.009/06/22 00:00:0016212096002021-05-17
21215WSSSM2021004H3SSM45<NaNNaN09/06/22 00:00:0077.0SSSM202104.0...NaN1.0NaNNaNN15.018.009/06/22 00:00:0016208640002021-05-13
+ +

21208 rows × 29 columns

+
+
+
+
+
+
+

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/measurement by removing blank entries and populating value column.

+ +++++ + + + + + + + + + + + + + + +
TypeDetails
coidictDictionary containing column names for values based on group
+
+
+Exported source +
class SanitizeValue(Callback):
+    "Sanitize value/measurement by removing blank entries and populating `value` column."
+    def __init__(self, 
+                 coi:dict # Dictionary containing column names for values based on group
+                 ): 
+        fc.store_attr()
+
+    def __call__(self, tfm):
+        for grp, df in tfm.dfs.items():
+            value_col = self.coi[grp]['val']
+            df.dropna(subset=[value_col], inplace=True)
+            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:06<00:00,  6.75it/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.55it/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, 142.83it/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, 141.44it/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, 136.95it/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, 135.05it/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
00n
11F
22NaN
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

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

FEEDBACK TO DATA PROVIDER: Column names for geographical coordinates are inconsistent across sample types (biota, sediment, seawater). Sometimes using parentheses, sometimes not.

+
+
+
+
dfs = load_data(fname_in)
+for grp in dfs.keys():
+    print(f'{grp}: {[col for col in dfs[grp].columns if "LON" in col or "LAT" in col]}')
+
+
seawater: ['LATITUDE (ddmmmm)', 'LATITUDE (dddddd)', 'LONGITUDE (ddmmmm)', 'LONGITUDE (dddddd)']
+sediment: ['LATITUDE (ddmmmm)', 'LATITUDE (dddddd)', 'LONGITUDE (ddmmmm)', 'LONGITUDE (dddddd)']
+biota: ['LATITUDE ddmmmm', 'LATITUDE dddddd', 'LONGITUDE ddmmmm', 'LONGITUDE dddddd']
+
+
+
+
+
+ +
+
+Tip +
+
+
+

FEEDBACK TO DATA PROVIDER: Geographical coordinates are provided in both decimal degree and degree-minute formats. Some coordinates are missing the decimal format and obliged us to use the degree-minute format with less precision.

+
+
+
+

source

+
+

ParseCoordinates

+
+
 ParseCoordinates (fn_convert_cor:Callable)
+
+

Get geographical coordinates from columns expressed in degrees decimal format or from columns in degrees/minutes decimal format where degrees decimal format is missing.

+
+
+Exported source +
class ParseCoordinates(Callback):
+    """
+    Get geographical coordinates from columns expressed in degrees decimal format 
+    or from columns in degrees/minutes decimal format where degrees decimal format is missing.
+    """
+    def __init__(self, fn_convert_cor:Callable):
+        self.fn_convert_cor = fn_convert_cor
+
+    def __call__(self, tfm:Transformer):
+        for df in tfm.dfs.values():
+            self._format_coordinates(df)
+
+    def _format_coordinates(self, df:pd.DataFrame):
+        coord_cols = self._get_coord_columns(df.columns)
+        
+        for coord in ['lat', 'lon']:
+            decimal_col, minute_col = coord_cols[f'{coord}_d'], coord_cols[f'{coord}_m']
+            
+            condition = df[decimal_col].isna() | (df[decimal_col] == 0)
+            df[coord] = np.where(condition,
+                                 df[minute_col].apply(self._safe_convert),
+                                 df[decimal_col])
+        
+        df.dropna(subset=['lat', 'lon'], inplace=True)
+
+    def _get_coord_columns(self, columns):
+        return {
+            'lon_d': self._find_coord_column(columns, 'LON', 'dddddd'),
+            'lat_d': self._find_coord_column(columns, 'LAT', 'dddddd'),
+            'lon_m': self._find_coord_column(columns, 'LON', 'ddmmmm'),
+            'lat_m': self._find_coord_column(columns, 'LAT', 'ddmmmm')
+        }
+
+    def _find_coord_column(self, columns, coord_type, coord_format):
+        pattern = re.compile(f'{coord_type}.*{coord_format}', re.IGNORECASE)
+        matching_columns = [col for col in columns if pattern.search(col)]
+        return matching_columns[0] if matching_columns else None
+
+    def _safe_convert(self, value):
+        if pd.isna(value):
+            return value
+        try:
+            return self.fn_convert_cor(value)
+        except Exception as e:
+            print(f"Error converting value {value}: {e}")
+            return value
+
+
+
+
dfs = load_data(fname_in)
+tfm = Transformer(dfs, cbs=[                    
+                            ParseCoordinates(ddmm_to_dd),
+                            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]
+
+
+
+
+
+ +
+
+Tip +
+
+
+

FEEDBACK TO DATA PROVIDER: Some samples have (lon, lat): (0, 0) or are outside lon/lat possible values.

+
+
+

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=[
+                            ParseCoordinates(ddmm_to_dd),
+                            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(),
+                            ParseCoordinates(ddmm_to_dd),
+                            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_common_rules

+
+
 get_common_rules (vars, encoding_type)
+
+

Get common renaming rules for NetCDF and OpenRefine.

+
+
+Exported source +
def get_common_rules(vars, encoding_type):
+    "Get common renaming rules for NetCDF and OpenRefine."
+    common = {
+        'lat': 'latitude' if encoding_type == 'openrefine' else vars['defaults']['lat']['name'],
+        'lon': 'longitude' if encoding_type == 'openrefine' else vars['defaults']['lon']['name'],
+        'time': 'begperiod' if encoding_type == 'openrefine' else vars['defaults']['time']['name'],
+        'NUCLIDE': 'nuclide_id' if encoding_type == 'openrefine' else 'nuclide',
+        'detection_limit': 'detection' if encoding_type == 'openrefine' else vars['suffixes']['detection_limit']['name'],
+        'unit': 'unit_id' if encoding_type == 'openrefine' else vars['suffixes']['unit']['name'],
+        'value': 'activity' if encoding_type == 'openrefine' else 'value',
+        'uncertainty': 'uncertaint' if encoding_type == 'openrefine' else vars['suffixes']['uncertainty']['name'],
+        'SDEPTH': 'sampdepth' if encoding_type == 'openrefine' else vars['defaults']['smp_depth']['name'],
+        'TDEPTH': 'totdepth' if encoding_type == 'openrefine' else vars['defaults']['tot_depth']['name'],
+    }
+    
+    if encoding_type == 'openrefine':
+        common.update({
+            'samptype_id': 'samptype_id',
+            'station': 'station',
+            'samplabcode': 'samplabcode',
+            'SALIN': 'salinity',
+            'TTEMP': 'temperatur',
+            'FILT': 'filtered',
+            'measurenote': 'measurenote'
+        })
+    else:
+        common.update({
+            'counting_method': vars['suffixes']['counting_method']['name'],
+            'sampling_method': vars['suffixes']['sampling_method']['name'],
+            'preparation_method': vars['suffixes']['preparation_method']['name'],
+            'SALIN': vars['suffixes']['salinity']['name'],
+            'TTEMP': vars['suffixes']['temperature']['name'],
+        })
+    
+    return common
+
+
+
+

source

+
+
+

get_specific_rules

+
+
 get_specific_rules (vars, encoding_type)
+
+

Get specific renaming rules for NetCDF and OpenRefine.

+
+
+Exported source +
def get_specific_rules(vars, encoding_type):
+    "Get specific renaming rules for NetCDF and OpenRefine."
+    if encoding_type == 'netcdf':
+        return {
+            'biota': {
+                'species': vars['bio']['species']['name'],
+                'body_part': vars['bio']['body_part']['name'],
+                'bio_group': vars['bio']['bio_group']['name']
+            },
+            'sediment': {
+                'sed_type': vars['sed']['sed_type']['name'],
+            }
+        }
+    elif encoding_type == 'openrefine':
+        return {
+            'biota': {
+                'species': 'species_id',
+                'Taxonname': 'Taxonname',
+                'TaxonRepName': 'TaxonRepName',
+                'Taxonrank': 'Taxonrank',
+                'TaxonDB': 'TaxonDB',
+                'TaxonDBID': 'TaxonDBID',
+                'TaxonDBURL': 'TaxonDBURL',
+                'body_part': 'bodypar_id',
+                'dry_wet_ratio': 'percentwt',
+            },
+            'sediment': {
+                'sed_type': 'sedtype_id',
+                'top': 'sliceup',
+                'bottom': 'slicedown',
+                'SedRepName': 'SedRepName',
+                'dry_wet_ratio': 'percentwt',
+            }
+        }
+
+
+
+

source

+
+
+

get_renaming_rules

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

Get renaming rules for NetCDF and OpenRefine.

+
+
+Exported source +
def get_renaming_rules(encoding_type='netcdf'):
+    "Get renaming rules for NetCDF and OpenRefine."
+    vars = cdl_cfg()['vars']
+    
+    if encoding_type not in ['netcdf', 'openrefine']:
+        raise ValueError("Invalid encoding_type provided. Please use 'netcdf' or 'openrefine'.")
+    
+    common_rules = get_common_rules(vars, encoding_type)
+    specific_rules = get_specific_rules(vars, encoding_type)
+    
+    rules = defaultdict(dict)
+    for sample_type in ['seawater', 'biota', 'sediment']:
+        rules[sample_type] = common_rules.copy()
+        rules[sample_type].update(specific_rules.get(sample_type, {}))
+    
+    return dict(rules)
+
+
+
+

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(),
+                            ParseCoordinates(ddmm_to_dd),
+                            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',
+       'smp_depth', 'tot_depth', '_sal', '_temp'],
+      dtype='object')
+sediment columns:
+Index(['lat', 'lon', 'time', 'nuclide', '_dl', '_unit', 'value', '_unc',
+       'tot_depth', 'sed_type'],
+      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(),
+                            ParseCoordinates(ddmm_to_dd),
+                            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', 'smp_depth', 'time', 'tot_depth', 'lat', '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(['lon', 'time', 'tot_depth', 'lat', 'sed_type', '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', 'smp_depth', 'time', 'lat', 'species',
+       '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(),
+                            ParseCoordinates(ddmm_to_dd),
+                            SanitizeLonLatCB(),
+                            SelectAndRenameColumnCB(get_renaming_rules, encoding_type='netcdf'),
+                            ReshapeLongToWide()
+                            ])
+
+tfm()
+tfm.logs
+
+
["Convert values from 'NUCLIDE' to lowercase, strip spaces, and store in 'None'.",
+ 'Parse the time column in the dataframe.',
+ 'Encode time as `int` representing seconds since xxx',
+ "Sanitize value by removing blank entries and ensuring the 'value' column is retained.",
+ 'Convert from relative error % to uncertainty of activity unit.',
+ 'Biota species standardized to MARIS format.',
+ 'Update bodypart id based on MARIS body part LUT (dbo_bodypar.xlsx).',
+ 'Update biogroup id based on MARIS species LUT (dbo_species.xlsx).',
+ 'Update taxon names based on MARIS species LUT `dbo_species.xlsx`.',
+ 'Update sediment id based on MARIS species LUT (dbo_sedtype.xlsx).',
+ 'Set the `unit` id column in the DataFrames based on a lookup table.',
+ 'Remap value type to MARIS format.',
+ 'Lookup FILT value in dataframe using the lookup table.',
+ 'Remap `KEY` column to `samplabcode` in each DataFrame.',
+ "Record measurement notes by adding a 'measurenote' column to DataFrames.",
+ 'Remap Station ID to MARIS format.',
+ 'Remap Sediment slice top and bottom to MARIS format.',
+ 'Lookup dry-wet ratio and format for MARIS.',
+ '\n    Get geographical coordinates from columns expressed in degrees decimal format \n    or from columns in degrees/minutes decimal format where degrees decimal format is missing.\n    ',
+ 'Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator.',
+ 'Select and rename columns in a DataFrame based on renaming rules for a specified encoding type.']
+
+
+
+
+

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'., Parse the time column in the dataframe., Encode time as `int` representing seconds since xxx, Sanitize value by removing blank entries and ensuring the 'value' column is retained., Convert from relative error % to uncertainty of activity unit., Biota species standardized to MARIS format., Update bodypart id based on MARIS body part LUT (dbo_bodypar.xlsx)., Update biogroup id based on MARIS species LUT (dbo_species.xlsx)., Update taxon names based on MARIS species LUT `dbo_species.xlsx`., Update sediment id based on MARIS species LUT (dbo_sedtype.xlsx)., Set the `unit` id column in the DataFrames based on a lookup table., Remap value type to MARIS format., Lookup FILT value in dataframe using the lookup table., Remap `KEY` column to `samplabcode` in each DataFrame., Record measurement notes by adding a 'measurenote' column to DataFrames., Remap Station ID to MARIS format., Remap Sediment slice top and bottom to MARIS format., Lookup dry-wet ratio and format for MARIS., \n    Get geographical coordinates from columns expressed in degrees decimal format \n    or from columns in degrees/minutes decimal format where degrees decimal format is missing.\n    , Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator., Select and rename columns in a DataFrame based on renaming rules for a specified encoding type."}
+
+
+
+

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(),
+                            ParseCoordinates(ddmm_to_dd),
+                            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(),
+                            ParseCoordinates(ddmm_to_dd),
+                            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(),
+                                ParseCoordinates(ddmm_to_dd),
+                                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..abcb2bc --- /dev/null +++ b/handlers/maris_legacy.html @@ -0,0 +1,3944 @@ + + + + + + + + + +MARIS Legacy – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+ +
+ + + +
+ + + + +
+ + + +
+ + + +
+

This notebook contains a data pipeline (handler) that converts the master MARIS database dump into NetCDF format. It enables batch encoding of all legacy datasets into NetCDF.

+
+

Key functions of this handler:

+ +

The result is a set of NetCDF files, one for each unique reference ID in the input data.

+
+

Packages import

+
+
+

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:
+    "Load specific MARIS dataset through its ref_id."
+    LUT = {
+        'Sediment': 'sediment', 'Seawater': 'seawater',
+        'Suspended matter': 'suspended-matter', 'Biota': 'biota'}
+
+    def __init__(self, 
+                 fname: str # Path to the MARIS global dump file
+                 ):
+        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_zotero_key

+
+
 get_zotero_key (dfs)
+
+

Retrieve Zotero key from MARIS dump.

+
+
+Exported source +
def get_zotero_key(dfs):
+    "Retrieve Zotero key from MARIS dump."
+    return dfs[next(iter(dfs))][['zoterourl']].iloc[0].values[0].split('/')[-1]
+
+
+
+

source

+
+
+

get_fname

+
+
 get_fname (dfs)
+
+

Retrieve filename from MARIS dump.

+
+
+Exported source +
def get_fname(dfs):
+    "Retrieve filename from MARIS dump."
+    id, name = dfs[next(iter(dfs))][['ref_id', 'displaytext']].iloc[0]
+    name = name.replace(',', '').replace('.', '').replace('-', ' ').split(' ')
+    return '-'.join(([str(id)] + name)) + '.nc'
+
+
+
+
+
+

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 ()
+
+

Parse time column from MARIS dump.

+
+
+Exported source +
class ParseTimeCB(Callback):
+    "Parse time column from MARIS dump."
+    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 0000000..d211f4d Binary files /dev/null and b/img/logo.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..c9e39f9 --- /dev/null +++ b/index.html @@ -0,0 +1,849 @@ + + + + + + + + + + +MARISCO – marisco + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

MARISCO

+
+ +
+
+ IAEA | MARIS data NetCDF encoders. +
+
+ + +
+ + + + +
+ + + +
+ + + +

The IAEA Marine Radioactivity Information System (MARIS) provides open access to radioactivity measurements in marine environments. Developed by the IAEA Environmental Laboratories in Monaco, MARIS offers data on seawater, biota, sediment, and suspended matter.

+

This Python package includes command-line tools to convert MARIS datasets into NetCDF or .csv formats, enhancing compatibility with various scientific and data analysis software.

+
+

Core Concept: Handlers

+

marisco is built around the concept of handlers - specialized modules designed to convert MARIS datasets into NetCDF format. Each handler is tailored to a specific data provider and implemented as a dedicated Jupyter notebook.

+
+

Literate Programming Approach

+

We’ve adopted a Literate Programming approach, which means:

+
    +
  1. Documentation: Each handler serves as comprehensive documentation.
  2. +
  3. Code Reference: The notebooks contain the actual implementation code.
  4. +
  5. Communication Tool: They facilitate discussions with data providers about discrepancies or inconsistencies.
  6. +
+
+
+

Powered by nbdev

+

To achieve this, we leverage nbdev, a powerful tool that allows us to:

+
    +
  1. Write code within Jupyter notebooks
  2. +
  3. Automatically export relevant parts as dedicated Python modules
  4. +
+

This approach bridges the gap between documentation and implementation, ensuring they remain in sync.

+
+
+

See It in Action

+

For a concrete example of this approach, check out our HELCOM dataset handler implementation.

+

Please note that this project is still under development.

+

We have implemented the MARIS Legacy handler to convert all existing datasets from the MARIS master database into NetCDF format. For datasets that are frequently updated, such as HELCOM, OSPAR, and TEPCO/Fukushima-related datasets, individual handlers are currently being developed and will be available soon.

+
+
+
+

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..a84300e --- /dev/null +++ b/search.json @@ -0,0 +1,843 @@ +[ + { + "objectID": "api/callbacks.html", + "href": "api/callbacks.html", + "title": "Callbacks", + "section": "", + "text": "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.\n\nsource\n\n\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\n\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\n\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#core", + "href": "api/callbacks.html#core", + "title": "Callbacks", + "section": "", + "text": "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.\n\nsource\n\n\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\n\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\n\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\n\nsource\n\nRemoveAllNAValuesCB\n\n RemoveAllNAValuesCB (cols_to_check:dict)\n\nRemove rows with all NA values.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\ncols_to_check\ndict\nA dictionary with the sample type as key and the column name to check as value\n\n\n\n\n\nExported source\nclass RemoveAllNAValuesCB(Callback):\n \"Remove rows with all NA values.\"\n def __init__(self, \n cols_to_check:dict # A dictionary with the sample type as key and the column name to check as value\n ):\n fc.store_attr()\n\n def __call__(self, tfm):\n for k in tfm.dfs.keys():\n col_to_check = self.cols_to_check[k]\n mask = tfm.dfs[k][col_to_check].isnull().all(axis=1)\n tfm.dfs[k] = tfm.dfs[k][~mask]\n\n\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\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/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\n\n\nExported source\nclass NCTemplater:\n \"MARIS NetCDF template generator.\"\n def __init__(self, \n cdl:Dict, # \"Pseudo CDL\" (`.toml`)\n nuclide_vars_fname:str, # File name and path of MARIS nuclide lookup table containing variable names\n tpl_fname:str, # File name and path of NetCDF4 file to be generated\n enum_dicts:Dict, # MARIS NetCDF enumeration types\n verbose=False\n ):\n fc.store_attr()\n self.dim = cdl['dim']\n self.enum_types = {}\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\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\n\n\nExported source\n@patch\ndef nuclide_vars(\n self:NCTemplater,\n col_varnames:str='nc_name', # Column name in the Excel lookup file containing the NetCDF variable names\n col_stdnames:str='nusymbol', # Column name Excel lookup file containing the NetCDF standard names\n dtype:str='f4', # Default data type\n ) -> list[dict]: # List of nuclide variables (including their names and attributes)\n \"Return the name of the radionuclide variables analysed.\"\n df = pd.read_excel(self.nuclide_vars_fname, index_col=0)\n \n df = df[(df.nuclide != 'NOT AVAILABLE') & (df.nuclide != 'NOT APPLICABLE')]\n # df = df[df.nuclide.isin(['NOT AVAILABLE', 'NOT APPLICABLE'])]\n \n return [\n {\n 'name': n,\n 'dtype': dtype,\n 'attrs': {\n 'long_name': f\"{nuclide.capitalize()} {massnb}\",\n 'standard_name': sn,\n }\n }\n for n, nuclide, massnb, sn in zip(\n df[col_varnames],\n df['nuclide'].str.capitalize(),\n df['massnb'].astype(int),\n df[col_stdnames],\n )\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\n\n\nExported source\n@patch\ndef derive(\n self:NCTemplater,\n nuclide:dict, # Nuclide variable name and associated netcdf attributes\n suffix:dict, # Naming rules as described in CDL (e.g `_unc`)\n) -> dict: # Derived variable name and associated attributes\n \"Derive NetCDF nuclide-dependent variable names & attributes as defined in CDL.\" \n return {\n # 'name': nuclide['name'] + '_' + suffix['name'],\n 'name': nuclide['name'] + suffix['name'],\n 'dtype': suffix['dtype'], # Using dtype from suffix\n 'attrs': {key: nuclide['attrs'][key] + suffix['attrs'][key] for key in nuclide['attrs']}\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\n\nExported source\n@patch\ndef create_enum_types(self:NCTemplater):\n \"Create enumeration types\"\n for name, enum in self.enum_dicts.items(): \n if self.verbose: print(f'Creating {name} enumeration type')\n self.enum_types[name] = self.nc.createEnumType(np.int_, name, enum)\n\n\n\nsource\n\n\n\n\n NCTemplater.create_groups ()\n\nCreate NetCDF groups\n\n\nExported source\n@patch\ndef create_groups(self:NCTemplater):\n \"Create NetCDF groups\"\n grp_names = [v['name'] for k, v in self.cdl['grps'].items()]\n for grp_name in grp_names:\n grp = self.nc.createGroup(grp_name)\n self.create_variables(grp)\n\n\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\n\nExported source\n@patch\ndef create_variables(self:NCTemplater, \n grp:netCDF4.Group, # NetCDF group\n ):\n \"Create variables\"\n self.create_variable(grp, self.dim) # Dimension variable\n self.create_default_variables(grp)\n self.create_group_specific_variables(grp)\n self.create_analyte_variables(grp)\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\n\nExported source\n@patch\ndef create_default_variables(self:NCTemplater, \n grp:netCDF4.Group, # NetCDF group\n ):\n \"Create Default variables\"\n vars = self.cdl['vars']['defaults'].values()\n for var in vars: self.create_variable(grp, var)\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\n\nExported source\n@patch\ndef create_group_specific_variables(self:NCTemplater, \n grp:netCDF4.Group, # NetCDF group\n ):\n \"Create group specific variables\"\n vars = self.cdl['vars']\n for var in vars.get(name2grp(grp.name, self.cdl), {}).values(): \n self.create_variable(grp, var)\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\n\nExported source\n@patch\ndef create_analyte_variables(self:NCTemplater, \n grp:netCDF4.Group, # NetCDF group\n ):\n \"Create analyte variables and dependent one as uncertainty, detection limit, ...\" \n for var in self.nuclide_vars():\n self.create_variable(grp, var)\n for v in self.cdl['vars']['suffixes'].values(): \n self.create_variable(grp, self.derive(var, v))\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\nExported source\n@patch\ndef create_variable(self:NCTemplater, \n grp:netCDF4.Group, # NetCDF group\n var:Dict, # Variable specificiation dict with `name`, `dtype` and `attrs` keys\n ):\n \"Create NetCDF variable with proper types (standard and enums)\"\n name, dtype, attrs = var.values()\n nc_var = grp.createVariable(name, \n self.enum_types.get(dtype) or dtype, \n self.dim['name'])\n nc_var.setncatts(attrs)\n\n\n\nsource\n\n\n\n\n NCTemplater.generate ()\n\nGenerate CDL\n\n\nExported source\n@patch\ndef generate(self:NCTemplater):\n \"Generate CDL\"\n # with NetCDFWriter(self.tpl_fname) as self.nc:\n with Dataset(self.tpl_fname, 'w', format='NETCDF4') as self.nc:\n self.nc.setncatts(self.cdl['global_attrs']) \n self.create_enum_types()\n self.nc.createDimension(self.dim['name'], None) \n self.create_groups()\n\n\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\n\n\nExported source\nclass NCTemplater:\n \"MARIS NetCDF template generator.\"\n def __init__(self, \n cdl:Dict, # \"Pseudo CDL\" (`.toml`)\n nuclide_vars_fname:str, # File name and path of MARIS nuclide lookup table containing variable names\n tpl_fname:str, # File name and path of NetCDF4 file to be generated\n enum_dicts:Dict, # MARIS NetCDF enumeration types\n verbose=False\n ):\n fc.store_attr()\n self.dim = cdl['dim']\n self.enum_types = {}\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\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\n\n\nExported source\n@patch\ndef nuclide_vars(\n self:NCTemplater,\n col_varnames:str='nc_name', # Column name in the Excel lookup file containing the NetCDF variable names\n col_stdnames:str='nusymbol', # Column name Excel lookup file containing the NetCDF standard names\n dtype:str='f4', # Default data type\n ) -> list[dict]: # List of nuclide variables (including their names and attributes)\n \"Return the name of the radionuclide variables analysed.\"\n df = pd.read_excel(self.nuclide_vars_fname, index_col=0)\n \n df = df[(df.nuclide != 'NOT AVAILABLE') & (df.nuclide != 'NOT APPLICABLE')]\n # df = df[df.nuclide.isin(['NOT AVAILABLE', 'NOT APPLICABLE'])]\n \n return [\n {\n 'name': n,\n 'dtype': dtype,\n 'attrs': {\n 'long_name': f\"{nuclide.capitalize()} {massnb}\",\n 'standard_name': sn,\n }\n }\n for n, nuclide, massnb, sn in zip(\n df[col_varnames],\n df['nuclide'].str.capitalize(),\n df['massnb'].astype(int),\n df[col_stdnames],\n )\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\n\n\nExported source\n@patch\ndef derive(\n self:NCTemplater,\n nuclide:dict, # Nuclide variable name and associated netcdf attributes\n suffix:dict, # Naming rules as described in CDL (e.g `_unc`)\n) -> dict: # Derived variable name and associated attributes\n \"Derive NetCDF nuclide-dependent variable names & attributes as defined in CDL.\" \n return {\n # 'name': nuclide['name'] + '_' + suffix['name'],\n 'name': nuclide['name'] + suffix['name'],\n 'dtype': suffix['dtype'], # Using dtype from suffix\n 'attrs': {key: nuclide['attrs'][key] + suffix['attrs'][key] for key in nuclide['attrs']}\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\n\nExported source\n@patch\ndef create_enum_types(self:NCTemplater):\n \"Create enumeration types\"\n for name, enum in self.enum_dicts.items(): \n if self.verbose: print(f'Creating {name} enumeration type')\n self.enum_types[name] = self.nc.createEnumType(np.int_, name, enum)\n\n\n\nsource\n\n\n\n\n NCTemplater.create_groups ()\n\nCreate NetCDF groups\n\n\nExported source\n@patch\ndef create_groups(self:NCTemplater):\n \"Create NetCDF groups\"\n grp_names = [v['name'] for k, v in self.cdl['grps'].items()]\n for grp_name in grp_names:\n grp = self.nc.createGroup(grp_name)\n self.create_variables(grp)\n\n\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\n\nExported source\n@patch\ndef create_variables(self:NCTemplater, \n grp:netCDF4.Group, # NetCDF group\n ):\n \"Create variables\"\n self.create_variable(grp, self.dim) # Dimension variable\n self.create_default_variables(grp)\n self.create_group_specific_variables(grp)\n self.create_analyte_variables(grp)\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\n\nExported source\n@patch\ndef create_default_variables(self:NCTemplater, \n grp:netCDF4.Group, # NetCDF group\n ):\n \"Create Default variables\"\n vars = self.cdl['vars']['defaults'].values()\n for var in vars: self.create_variable(grp, var)\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\n\nExported source\n@patch\ndef create_group_specific_variables(self:NCTemplater, \n grp:netCDF4.Group, # NetCDF group\n ):\n \"Create group specific variables\"\n vars = self.cdl['vars']\n for var in vars.get(name2grp(grp.name, self.cdl), {}).values(): \n self.create_variable(grp, var)\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\n\nExported source\n@patch\ndef create_analyte_variables(self:NCTemplater, \n grp:netCDF4.Group, # NetCDF group\n ):\n \"Create analyte variables and dependent one as uncertainty, detection limit, ...\" \n for var in self.nuclide_vars():\n self.create_variable(grp, var)\n for v in self.cdl['vars']['suffixes'].values(): \n self.create_variable(grp, self.derive(var, v))\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\nExported source\n@patch\ndef create_variable(self:NCTemplater, \n grp:netCDF4.Group, # NetCDF group\n var:Dict, # Variable specificiation dict with `name`, `dtype` and `attrs` keys\n ):\n \"Create NetCDF variable with proper types (standard and enums)\"\n name, dtype, attrs = var.values()\n nc_var = grp.createVariable(name, \n self.enum_types.get(dtype) or dtype, \n self.dim['name'])\n nc_var.setncatts(attrs)\n\n\n\nsource\n\n\n\n\n NCTemplater.generate ()\n\nGenerate CDL\n\n\nExported source\n@patch\ndef generate(self:NCTemplater):\n \"Generate CDL\"\n # with NetCDFWriter(self.tpl_fname) as self.nc:\n with Dataset(self.tpl_fname, 'w', format='NETCDF4') as self.nc:\n self.nc.setncatts(self.cdl['global_attrs']) \n self.create_enum_types()\n self.nc.createDimension(self.dim['name'], None) \n self.create_groups()\n\n\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": "source\n\n\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\n\n\n cfg ()\n\n\n\nExported source\ndef cfg(): return read_toml(base_path() / CFG_FNAME)\n\n\n\nsource\n\n\n\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\n\n\n lut_path ()\n\n\n\nExported source\ndef lut_path(): return Path(cfg()['dirs']['lut'])\n\n\n\nsource\n\n\n\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\n\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\n\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\n\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\n\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\n\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\n\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\n\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\n\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\n\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#configuration-files", + "href": "api/configs.html#configuration-files", + "title": "Configs", + "section": "", + "text": "source\n\n\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\n\n\n cfg ()\n\n\n\nExported source\ndef cfg(): return read_toml(base_path() / CFG_FNAME)\n\n\n\nsource\n\n\n\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\n\n\n lut_path ()\n\n\n\nExported source\ndef lut_path(): return Path(cfg()['dirs']['lut'])\n\n\n\nsource\n\n\n\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\n\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\n\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\n\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\n\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\n\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\n\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\n\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\n\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\n\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/serializers.html", + "href": "api/serializers.html", + "title": "Serializers", + "section": "", + "text": "source", + "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": "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\n\nOnce converted to .csv files, the data is ready to be loaded into a dictionary of dataframes.\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\n14 14 CS137 9 5\n20 20 SR90 6 4\n31 31 PU238 8 5\n34 34 CS137 6 5\n37 37 K40 8 3\n53 53 SR90 7 4\n54 54 SR90 5 4\n59 59 SR90 8 4\n62 62 CO60 8 4\n69 69 CS134 8 5\n73 73 TC99 7 4\n75 75 AM241 8 5\n91 91 CS137 8 5\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\npu239240\n\n\n1\n1\ncs144\n\n\n2\n2\ncs141\n\n\n3\n3\ncs140\n\n\n4\n4\nsn117m\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, 48.57it/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\npu239240\npu240\npu239240\n3\n\n\npu238240\npu240\npu238240\n3\n\n\ncm243244\ncm244\ncm243244\n3\n\n\ncs134137\ncs137\ncs134137\n3\n\n\ncs142\nce144\ncs142\n2\n\n\ncs145\ncs136\ncs145\n2\n\n\ncs143\ncs127\ncs143\n2\n\n\ncs144\nce144\ncs144\n1\n\n\ncs141\nce141\ncs141\n1\n\n\ncs140\nce140\ncs140\n1\n\n\ncs138\ncs137\ncs138\n1\n\n\ncs139\nce139\ncs139\n1\n\n\ncs146\ncs136\ncs146\n1\n\n\nk-40\nk40\nk-40\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.64it/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\n\n\n\n\n\nTip\n\n\n\nFEEDBACK TO DATA PROVIDER: Time/date is provide in the DATE, YEAR , MONTH, DAY columns. Note that the DATE contains missing values as indicated below. When missing, we fallback on the YEAR, MONTH, DAY columns. Note also that sometimes DAY and MONTH contain 0. In this case we systematically set them to 1.\n\n\n\ndfs = load_data(fname_in)\nfor key in dfs.keys():\n print(f'{key} DATE null values: ', dfs[key]['DATE'].isna().sum())\n\nseawater DATE null values: 502\nsediment DATE null values: 741\nbiota DATE null values: 72\n\n\n\nsource\n\nParseTimeCB\n\n ParseTimeCB ()\n\nParse and standardize time information in the dataframe.\n\n\nExported source\nclass ParseTimeCB(Callback):\n \"Parse and standardize time information in the dataframe.\"\n def __call__(self, tfm):\n for df in tfm.dfs.values():\n self._process_dates(df)\n self._define_beg_period(df)\n\n def _process_dates(self, df):\n \"Process and correct date and time information in the DataFrame.\"\n df['time'] = self._parse_date(df)\n self._handle_missing_dates(df)\n self._fill_missing_time(df)\n\n def _parse_date(self, df):\n \"Parse the DATE column if present.\"\n return pd.to_datetime(df['DATE'], format='%m/%d/%y %H:%M:%S', errors='coerce')\n\n def _handle_missing_dates(self, df):\n \"Handle cases where DAY or MONTH is 0 or missing.\"\n df.loc[df[\"DAY\"] == 0, \"DAY\"] = 1\n df.loc[df[\"MONTH\"] == 0, \"MONTH\"] = 1\n \n missing_day_month = (df[\"DAY\"].isna()) & (df[\"MONTH\"].isna()) & (df[\"YEAR\"].notna())\n df.loc[missing_day_month, [\"DAY\", \"MONTH\"]] = 1\n\n def _fill_missing_time(self, df):\n \"Fill missing time values using YEAR, MONTH, and DAY columns.\"\n missing_time = df['time'].isna()\n df.loc[missing_time, 'time'] = pd.to_datetime(\n df.loc[missing_time, ['YEAR', 'MONTH', 'DAY']], \n format='%Y%m%d', \n errors='coerce'\n )\n\n def _define_beg_period(self, df):\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\nNetCDF time format requires the time to be encoded as number of milliseconds since a time of origin. In our case the time of origin is 1970-01-01 as indicated in configs.ipynb CONFIFS['units']['time'] dictionary.\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 \n\n\n\n\ntfm.dfs['seawater']\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...\nTDEPTH\nSDEPTH\nSALIN\nTTEMP\nFILT\nMORS_SUBBASIN\nHELCOM_SUBBASIN\nDATE_OF_ENTRY_y\ntime\nbegperiod\n\n\n\n\n0\nWKRIL2012003\nCS137\nNaN\nNaN\n5.3\n32.000000\n08/20/14 00:00:00\n90.0\nKRIL\n2012003.0\n...\nNaN\n0.0\nNaN\nNaN\nNaN\n11.0\n11.0\n08/20/14 00:00:00\n1337731200\n2012-05-23\n\n\n1\nWKRIL2012004\nCS137\nNaN\nNaN\n19.9\n20.000000\n08/20/14 00:00:00\n90.0\nKRIL\n2012004.0\n...\nNaN\n29.0\nNaN\nNaN\nNaN\n11.0\n11.0\n08/20/14 00:00:00\n1337731200\n2012-05-23\n\n\n2\nWKRIL2012005\nCS137\nNaN\nNaN\n25.5\n20.000000\n08/20/14 00:00:00\n90.0\nKRIL\n2012005.0\n...\nNaN\n0.0\nNaN\nNaN\nNaN\n11.0\n3.0\n08/20/14 00:00:00\n1339891200\n2012-06-17\n\n\n3\nWKRIL2012006\nCS137\nNaN\nNaN\n17.0\n29.000000\n08/20/14 00:00:00\n90.0\nKRIL\n2012006.0\n...\nNaN\n0.0\nNaN\nNaN\nNaN\n11.0\n11.0\n08/20/14 00:00:00\n1337817600\n2012-05-24\n\n\n4\nWKRIL2012007\nCS137\nNaN\nNaN\n22.2\n18.000000\n08/20/14 00:00:00\n90.0\nKRIL\n2012007.0\n...\nNaN\n39.0\nNaN\nNaN\nNaN\n11.0\n11.0\n08/20/14 00:00:00\n1337817600\n2012-05-24\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\n21211\nWSSSM2021005\nH3\nSSM45\nNaN\n1030.0\n93.203883\n09/06/22 00:00:00\n77.0\nSSSM\n202105.0\n...\nNaN\n1.0\nNaN\nNaN\nN\n1.0\n8.0\n09/06/22 00:00:00\n1634256000\n2021-10-15\n\n\n21212\nWSSSM2021006\nH3\nSSM45\nNaN\n2240.0\n43.303571\n09/06/22 00:00:00\n77.0\nSSSM\n202106.0\n...\nNaN\n1.0\nNaN\nNaN\nN\n10.0\n10.0\n09/06/22 00:00:00\n1635984000\n2021-11-04\n\n\n21213\nWSSSM2021007\nH3\nSSM45\nNaN\n2060.0\n47.087379\n09/06/22 00:00:00\n77.0\nSSSM\n202107.0\n...\nNaN\n1.0\nNaN\nNaN\nN\n12.0\n12.0\n09/06/22 00:00:00\n1634256000\n2021-10-15\n\n\n21214\nWSSSM2021008\nH3\nSSM45\nNaN\n2300.0\n43.478261\n09/06/22 00:00:00\n77.0\nSSSM\n202108.0\n...\nNaN\n1.0\nNaN\nNaN\nN\n12.0\n12.0\n09/06/22 00:00:00\n1621209600\n2021-05-17\n\n\n21215\nWSSSM2021004\nH3\nSSM45\n<\nNaN\nNaN\n09/06/22 00:00:00\n77.0\nSSSM\n202104.0\n...\nNaN\n1.0\nNaN\nNaN\nN\n15.0\n18.0\n09/06/22 00:00:00\n1620864000\n2021-05-13\n\n\n\n\n21208 rows × 29 columns", + "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/measurement by removing blank entries and populating value column.\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/measurement by removing blank entries and populating `value` column.\"\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, tfm):\n for grp, df in tfm.dfs.items():\n value_col = self.coi[grp]['val']\n df.dropna(subset=[value_col], inplace=True)\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:06<00:00, 6.75it/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.55it/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, 142.83it/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, 141.44it/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, 136.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\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, 135.05it/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\nn\n\n\n1\n1\nF\n\n\n2\n2\nNaN\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\n\n\n\n\n\nTip\n\n\n\nFEEDBACK TO DATA PROVIDER: Column names for geographical coordinates are inconsistent across sample types (biota, sediment, seawater). Sometimes using parentheses, sometimes not.\n\n\n\ndfs = load_data(fname_in)\nfor grp in dfs.keys():\n print(f'{grp}: {[col for col in dfs[grp].columns if \"LON\" in col or \"LAT\" in col]}')\n\nseawater: ['LATITUDE (ddmmmm)', 'LATITUDE (dddddd)', 'LONGITUDE (ddmmmm)', 'LONGITUDE (dddddd)']\nsediment: ['LATITUDE (ddmmmm)', 'LATITUDE (dddddd)', 'LONGITUDE (ddmmmm)', 'LONGITUDE (dddddd)']\nbiota: ['LATITUDE ddmmmm', 'LATITUDE dddddd', 'LONGITUDE ddmmmm', 'LONGITUDE dddddd']\n\n\n\n\n\n\n\n\nTip\n\n\n\nFEEDBACK TO DATA PROVIDER: Geographical coordinates are provided in both decimal degree and degree-minute formats. Some coordinates are missing the decimal format and obliged us to use the degree-minute format with less precision.\n\n\n\nsource\n\nParseCoordinates\n\n ParseCoordinates (fn_convert_cor:Callable)\n\nGet geographical coordinates from columns expressed in degrees decimal format or from columns in degrees/minutes decimal format where degrees decimal format is missing.\n\n\nExported source\nclass ParseCoordinates(Callback):\n \"\"\"\n Get geographical coordinates from columns expressed in degrees decimal format \n or from columns in degrees/minutes decimal format where degrees decimal format is missing.\n \"\"\"\n def __init__(self, fn_convert_cor:Callable):\n self.fn_convert_cor = fn_convert_cor\n\n def __call__(self, tfm:Transformer):\n for df in tfm.dfs.values():\n self._format_coordinates(df)\n\n def _format_coordinates(self, df:pd.DataFrame):\n coord_cols = self._get_coord_columns(df.columns)\n \n for coord in ['lat', 'lon']:\n decimal_col, minute_col = coord_cols[f'{coord}_d'], coord_cols[f'{coord}_m']\n \n condition = df[decimal_col].isna() | (df[decimal_col] == 0)\n df[coord] = np.where(condition,\n df[minute_col].apply(self._safe_convert),\n df[decimal_col])\n \n df.dropna(subset=['lat', 'lon'], inplace=True)\n\n def _get_coord_columns(self, columns):\n return {\n 'lon_d': self._find_coord_column(columns, 'LON', 'dddddd'),\n 'lat_d': self._find_coord_column(columns, 'LAT', 'dddddd'),\n 'lon_m': self._find_coord_column(columns, 'LON', 'ddmmmm'),\n 'lat_m': self._find_coord_column(columns, 'LAT', 'ddmmmm')\n }\n\n def _find_coord_column(self, columns, coord_type, coord_format):\n pattern = re.compile(f'{coord_type}.*{coord_format}', re.IGNORECASE)\n matching_columns = [col for col in columns if pattern.search(col)]\n return matching_columns[0] if matching_columns else None\n\n def _safe_convert(self, value):\n if pd.isna(value):\n return value\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\n\n\n\ndfs = load_data(fname_in)\ntfm = Transformer(dfs, cbs=[ \n ParseCoordinates(ddmm_to_dd),\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\n\n\n\n\nTip\n\n\n\nFEEDBACK TO DATA PROVIDER: Some samples have (lon, lat): (0, 0) or are outside lon/lat possible values.\n\n\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 ParseCoordinates(ddmm_to_dd),\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 ParseCoordinates(ddmm_to_dd),\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_common_rules\n\n get_common_rules (vars, encoding_type)\n\nGet common renaming rules for NetCDF and OpenRefine.\n\n\nExported source\ndef get_common_rules(vars, encoding_type):\n \"Get common renaming rules for NetCDF and OpenRefine.\"\n common = {\n 'lat': 'latitude' if encoding_type == 'openrefine' else vars['defaults']['lat']['name'],\n 'lon': 'longitude' if encoding_type == 'openrefine' else vars['defaults']['lon']['name'],\n 'time': 'begperiod' if encoding_type == 'openrefine' else vars['defaults']['time']['name'],\n 'NUCLIDE': 'nuclide_id' if encoding_type == 'openrefine' else 'nuclide',\n 'detection_limit': 'detection' if encoding_type == 'openrefine' else vars['suffixes']['detection_limit']['name'],\n 'unit': 'unit_id' if encoding_type == 'openrefine' else vars['suffixes']['unit']['name'],\n 'value': 'activity' if encoding_type == 'openrefine' else 'value',\n 'uncertainty': 'uncertaint' if encoding_type == 'openrefine' else vars['suffixes']['uncertainty']['name'],\n 'SDEPTH': 'sampdepth' if encoding_type == 'openrefine' else vars['defaults']['smp_depth']['name'],\n 'TDEPTH': 'totdepth' if encoding_type == 'openrefine' else vars['defaults']['tot_depth']['name'],\n }\n \n if encoding_type == 'openrefine':\n common.update({\n 'samptype_id': 'samptype_id',\n 'station': 'station',\n 'samplabcode': 'samplabcode',\n 'SALIN': 'salinity',\n 'TTEMP': 'temperatur',\n 'FILT': 'filtered',\n 'measurenote': 'measurenote'\n })\n else:\n common.update({\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 'SALIN': vars['suffixes']['salinity']['name'],\n 'TTEMP': vars['suffixes']['temperature']['name'],\n })\n \n return common\n\n\n\nsource\n\n\nget_specific_rules\n\n get_specific_rules (vars, encoding_type)\n\nGet specific renaming rules for NetCDF and OpenRefine.\n\n\nExported source\ndef get_specific_rules(vars, encoding_type):\n \"Get specific renaming rules for NetCDF and OpenRefine.\"\n if encoding_type == 'netcdf':\n return {\n 'biota': {\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 'sed_type': vars['sed']['sed_type']['name'],\n }\n }\n elif encoding_type == 'openrefine':\n return {\n 'biota': {\n 'species': 'species_id',\n 'Taxonname': 'Taxonname',\n 'TaxonRepName': 'TaxonRepName',\n 'Taxonrank': 'Taxonrank',\n 'TaxonDB': 'TaxonDB',\n 'TaxonDBID': 'TaxonDBID',\n 'TaxonDBURL': 'TaxonDBURL',\n 'body_part': 'bodypar_id',\n 'dry_wet_ratio': 'percentwt',\n },\n 'sediment': {\n 'sed_type': 'sedtype_id',\n 'top': 'sliceup',\n 'bottom': 'slicedown',\n 'SedRepName': 'SedRepName',\n 'dry_wet_ratio': 'percentwt',\n }\n }\n\n\n\nsource\n\n\nget_renaming_rules\n\n get_renaming_rules (encoding_type='netcdf')\n\nGet renaming rules for NetCDF and OpenRefine.\n\n\nExported source\ndef get_renaming_rules(encoding_type='netcdf'):\n \"Get renaming rules for NetCDF and OpenRefine.\"\n vars = cdl_cfg()['vars']\n \n if encoding_type not in ['netcdf', 'openrefine']:\n raise ValueError(\"Invalid encoding_type provided. Please use 'netcdf' or 'openrefine'.\")\n \n common_rules = get_common_rules(vars, encoding_type)\n specific_rules = get_specific_rules(vars, encoding_type)\n \n rules = defaultdict(dict)\n for sample_type in ['seawater', 'biota', 'sediment']:\n rules[sample_type] = common_rules.copy()\n rules[sample_type].update(specific_rules.get(sample_type, {}))\n \n return dict(rules)\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 ParseCoordinates(ddmm_to_dd),\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 'smp_depth', 'tot_depth', '_sal', '_temp'],\n dtype='object')\nsediment columns:\nIndex(['lat', 'lon', 'time', 'nuclide', '_dl', '_unit', 'value', '_unc',\n 'tot_depth', 'sed_type'],\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 ParseCoordinates(ddmm_to_dd),\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', 'smp_depth', 'time', 'tot_depth', 'lat', '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(['lon', 'time', 'tot_depth', 'lat', 'sed_type', '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', 'smp_depth', 'time', 'lat', 'species',\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 ParseCoordinates(ddmm_to_dd),\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 'Parse the time column in the dataframe.',\n 'Encode time as `int` representing seconds since xxx',\n \"Sanitize value by removing blank entries and ensuring the 'value' column is retained.\",\n 'Convert from relative error % to uncertainty of activity unit.',\n 'Biota species standardized to MARIS format.',\n 'Update bodypart id based on MARIS body part LUT (dbo_bodypar.xlsx).',\n 'Update biogroup id based on MARIS species LUT (dbo_species.xlsx).',\n 'Update taxon names based on MARIS species LUT `dbo_species.xlsx`.',\n 'Update sediment id based on MARIS species LUT (dbo_sedtype.xlsx).',\n 'Set the `unit` id column in the DataFrames based on a lookup table.',\n 'Remap value type to MARIS format.',\n 'Lookup FILT value in dataframe using the lookup table.',\n 'Remap `KEY` column to `samplabcode` in each DataFrame.',\n \"Record measurement notes by adding a 'measurenote' column to DataFrames.\",\n 'Remap Station ID to MARIS format.',\n 'Remap Sediment slice top and bottom to MARIS format.',\n 'Lookup dry-wet ratio and format for MARIS.',\n '\\n Get geographical coordinates from columns expressed in degrees decimal format \\n or from columns in degrees/minutes decimal format where degrees decimal format is missing.\\n ',\n 'Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator.',\n 'Select and rename columns in a DataFrame based on renaming rules for a specified encoding type.']\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'., Parse the time column in the dataframe., Encode time as `int` representing seconds since xxx, Sanitize value by removing blank entries and ensuring the 'value' column is retained., Convert from relative error % to uncertainty of activity unit., Biota species standardized to MARIS format., Update bodypart id based on MARIS body part LUT (dbo_bodypar.xlsx)., Update biogroup id based on MARIS species LUT (dbo_species.xlsx)., Update taxon names based on MARIS species LUT `dbo_species.xlsx`., Update sediment id based on MARIS species LUT (dbo_sedtype.xlsx)., Set the `unit` id column in the DataFrames based on a lookup table., Remap value type to MARIS format., Lookup FILT value in dataframe using the lookup table., Remap `KEY` column to `samplabcode` in each DataFrame., Record measurement notes by adding a 'measurenote' column to DataFrames., Remap Station ID to MARIS format., Remap Sediment slice top and bottom to MARIS format., Lookup dry-wet ratio and format for MARIS., \\n Get geographical coordinates from columns expressed in degrees decimal format \\n or from columns in degrees/minutes decimal format where degrees decimal format is missing.\\n , Drop row when both longitude & latitude equal 0. Drop unrealistic longitude & latitude values. Convert longitude & latitude `,` separator to `.` separator., Select and rename columns in a DataFrame based on renaming rules for a specified encoding type.\"}\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 ParseCoordinates(ddmm_to_dd),\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 ParseCoordinates(ddmm_to_dd),\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 ParseCoordinates(ddmm_to_dd),\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/maris_legacy.html", + "href": "handlers/maris_legacy.html", + "title": "MARIS Legacy", + "section": "", + "text": "This notebook contains a data pipeline (handler) that converts the master MARIS database dump into NetCDF format. It enables batch encoding of all legacy datasets into NetCDF.\nKey functions of this handler:\nThe result is a set of NetCDF files, one for each unique reference ID in the input data.", + "crumbs": [ + "Handlers", + "MARIS Legacy" + ] + }, + { + "objectID": "handlers/maris_legacy.html#packages-import", + "href": "handlers/maris_legacy.html#packages-import", + "title": "MARIS Legacy", + "section": "Packages import", + "text": "Packages import", + "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 \"Load specific MARIS dataset through its ref_id.\"\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 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_zotero_key\n\n get_zotero_key (dfs)\n\nRetrieve Zotero key from MARIS dump.\n\n\nExported source\ndef get_zotero_key(dfs):\n \"Retrieve Zotero key from MARIS dump.\"\n return dfs[next(iter(dfs))][['zoterourl']].iloc[0].values[0].split('/')[-1]\n\n\n\nsource\n\n\nget_fname\n\n get_fname (dfs)\n\nRetrieve filename from MARIS dump.\n\n\nExported source\ndef get_fname(dfs):\n \"Retrieve filename from MARIS dump.\"\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'", + "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\nParse time column from MARIS dump.\n\n\nExported source\nclass ParseTimeCB(Callback):\n \"Parse time column from MARIS dump.\"\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": "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": "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) provides open access to radioactivity measurements in marine environments. Developed by the IAEA Environmental Laboratories in Monaco, MARIS offers data on seawater, biota, sediment, and suspended matter.\nThis Python package includes command-line tools to convert MARIS datasets into NetCDF or .csv formats, enhancing compatibility with various scientific and data analysis software.", + "crumbs": [ + "MARISCO" + ] + }, + { + "objectID": "index.html#core-concept-handlers", + "href": "index.html#core-concept-handlers", + "title": "MARISCO", + "section": "Core Concept: Handlers", + "text": "Core Concept: Handlers\nmarisco is built around the concept of handlers - specialized modules designed to convert MARIS datasets into NetCDF format. Each handler is tailored to a specific data provider and implemented as a dedicated Jupyter notebook.\n\nLiterate Programming Approach\nWe’ve adopted a Literate Programming approach, which means:\n\nDocumentation: Each handler serves as comprehensive documentation.\nCode Reference: The notebooks contain the actual implementation code.\nCommunication Tool: They facilitate discussions with data providers about discrepancies or inconsistencies.\n\n\n\nPowered by nbdev\nTo achieve this, we leverage nbdev, a powerful tool that allows us to:\n\nWrite code within Jupyter notebooks\nAutomatically export relevant parts as dedicated Python modules\n\nThis approach bridges the gap between documentation and implementation, ensuring they remain in sync.\n\n\nSee It in Action\nFor a concrete example of this approach, check out our HELCOM dataset handler implementation.\nPlease note that this project is still under development.\nWe have implemented the MARIS Legacy handler to convert all existing datasets from the MARIS master database into NetCDF format. For datasets that are frequently updated, such as HELCOM, OSPAR, and TEPCO/Fukushima-related datasets, individual handlers are currently being developed and will be available soon.", + "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": "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": "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)" + }, + { + "objectID": "api/utils.html", + "href": "api/utils.html", + "title": "Utilities", + "section": "", + "text": "Abstracting some common operations.\n\nsource\n\n\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\n\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 \"Remap a data provider lookup table to a MARIS lookup table using fuzzy matching.\"\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 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 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 # If value is in fixes, use the fixed value\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#core", + "href": "api/utils.html#core", + "title": "Utilities", + "section": "", + "text": "Abstracting some common operations.\n\nsource\n\n\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\n\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 \"Remap a data provider lookup table to a MARIS lookup table using fuzzy matching.\"\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 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 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 # If value is in fixes, use the fixed value\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\nGet the bounding box of a DataFrame.\n\n\nExported source\ndef get_bbox(df,\n coord_cols=('lon', 'lat')\n ):\n \"Get the bounding box of a DataFrame.\"\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)\n\n\n\nsource\n\n\nddmm_to_dd\n\n ddmm_to_dd (ddmmmm:float)\n\n\n\n\n\nType\nDetails\n\n\n\n\nddmmmm\nfloat\nCoordinates in degrees/minutes decimal format\n\n\nReturns\nfloat\nCoordinates in degrees decimal format\n\n\n\n\n\nExported source\ndef ddmm_to_dd(\n ddmmmm:float # Coordinates in degrees/minutes decimal format\n ) -> float: # Coordinates in degrees decimal format\n # Convert degrees/minutes decimal to degrees decimal.\n mins, degs = modf(ddmmmm)\n mins = mins * 100\n return round(int(degs) + (mins / 60), 6)\n\n\n\nfc.test_close(ddmm_to_dd(45.34), 45.566667)", + "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'}]]", + "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\nMatch between a data provider name and a MARIS lookup table.\n\n\nExported source\n@dataclass\nclass Match:\n \"Match between a data provider name and a MARIS lookup table.\"\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\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\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-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\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-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\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'}]]", + "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": "api/inout.html", + "href": "api/inout.html", + "title": "Input/Output", + "section": "", + "text": "source\n\nwrite_toml\n\n write_toml (fname, cfg)\n\nWrite a TOML file from a dictionary.\n\n\nExported source\ndef write_toml(fname, cfg):\n \"Write a TOML file from a dictionary.\"\n print(f'Creating {fname}')\n with open(fname, \"wb\") as f:\n tomli_w.dump(cfg, f)\n\n\n\nsource\n\n\nread_toml\n\n read_toml (fname)\n\nRead a TOML file into a dictionary.\n\n\nExported source\ndef read_toml(fname):\n \"Read a TOML file into a dictionary.\"\n with open(fname, \"rb\") as f:\n config = tomli.load(f)\n return config" + }, + { + "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" + ] + } +] \ 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 0000000..dbeeb05 Binary files /dev/null and b/site_libs/bootstrap/bootstrap-icons.woff differ diff --git a/site_libs/bootstrap/bootstrap.min.css b/site_libs/bootstrap/bootstrap.min.css new file mode 100644 index 0000000..bc8e007 --- /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}}: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}: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}.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}@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}}.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}}: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}.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)}.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}}.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)}}: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%)}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..7e74f2e --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,63 @@ + + + + https://franckalbinet.github.io/marisco/api/callbacks.html + 2024-09-25T09:35:07.233Z + + + https://franckalbinet.github.io/marisco/api/nc_template.html + 2024-09-25T09:35:07.168Z + + + https://franckalbinet.github.io/marisco/api/configs.html + 2024-09-25T09:35:07.151Z + + + https://franckalbinet.github.io/marisco/api/serializers.html + 2024-09-25T09:35:06.937Z + + + https://franckalbinet.github.io/marisco/handlers/helcom.html + 2024-09-25T09:35:07.156Z + + + https://franckalbinet.github.io/marisco/handlers/maris_legacy.html + 2024-09-25T09:35:06.827Z + + + https://franckalbinet.github.io/marisco/cli/init.html + 2024-09-25T09:35:06.709Z + + + https://franckalbinet.github.io/marisco/cli/create_nc_template.html + 2024-09-25T09:35:06.529Z + + + https://franckalbinet.github.io/marisco/cli/netcdfy.html + 2024-09-25T09:35:06.491Z + + + https://franckalbinet.github.io/marisco/index.html + 2024-09-25T09:35:06.027Z + + + https://franckalbinet.github.io/marisco/handlers/netcdf_to_csv.html + 2024-09-25T09:35:06.793Z + + + https://franckalbinet.github.io/marisco/handlers/geotraces.html + 2024-09-25T09:35:06.958Z + + + https://franckalbinet.github.io/marisco/api/utils.html + 2024-09-25T09:35:07.058Z + + + https://franckalbinet.github.io/marisco/api/inout.html + 2024-09-25T09:35:07.051Z + + + https://franckalbinet.github.io/marisco/api/metadata.html + 2024-09-25T09:35:07.145Z + + diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..e99da6b --- /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: 70px 70px; + /* Increased logo size */ + + padding-left: 65px; + /* 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