diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/00_test_files/figure-html/cell-35-output-1.png b/00_test_files/figure-html/cell-35-output-1.png new file mode 100644 index 00000000..7b80ee81 Binary files /dev/null and b/00_test_files/figure-html/cell-35-output-1.png differ diff --git a/00_test_files/figure-html/cell-36-output-1.png b/00_test_files/figure-html/cell-36-output-1.png new file mode 100644 index 00000000..4ddbcd3e Binary files /dev/null and b/00_test_files/figure-html/cell-36-output-1.png differ diff --git a/00_test_files/figure-html/cell-38-output-1.png b/00_test_files/figure-html/cell-38-output-1.png new file mode 100644 index 00000000..b8e59c91 Binary files /dev/null and b/00_test_files/figure-html/cell-38-output-1.png differ diff --git a/05_transform_files/figure-html/cell-73-output-1.png b/05_transform_files/figure-html/cell-73-output-1.png new file mode 100644 index 00000000..45f2e4cf Binary files /dev/null and b/05_transform_files/figure-html/cell-73-output-1.png differ diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..d9bb41c6 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +fastcore.fast.ai diff --git a/basics.html b/basics.html new file mode 100644 index 00000000..9f8eb33a --- /dev/null +++ b/basics.html @@ -0,0 +1,3442 @@ + + + + + + + + + + +Basic functionality – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Basic functionality

+
+ +
+
+ Basic functionality used in the fastai library +
+
+ + +
+ + + + +
+ + + +
+ + + +
+

Basics

+
+

source

+
+

ifnone

+
+
 ifnone (a, b)
+
+

b if a is None else a

+

Since b if a is None else a is such a common pattern, we wrap it in a function. However, be careful, because python will evaluate both a and b when calling ifnone (which it doesn’t do if using the if version directly).

+
+
test_eq(ifnone(None,1), 1)
+test_eq(ifnone(2   ,1), 2)
+
+
+

source

+
+
+

maybe_attr

+
+
 maybe_attr (o, attr)
+
+

getattr(o,attr,o)

+

Return the attribute attr for object o. If the attribute doesn’t exist, then return the object o instead.

+
+
class myobj: myattr='foo'
+
+test_eq(maybe_attr(myobj, 'myattr'), 'foo')
+test_eq(maybe_attr(myobj, 'another_attr'), myobj)
+
+
+

source

+
+
+

basic_repr

+
+
 basic_repr (flds=None)
+
+

Minimal __repr__

+

In types which provide rich display functionality in Jupyter, their __repr__ is also called in order to provide a fallback text representation. Unfortunately, this includes a memory address which changes on every invocation, making it non-deterministic. This causes diffs to get messy and creates conflicts in git. To fix this, put __repr__=basic_repr() inside your class.

+
+
class SomeClass: __repr__=basic_repr()
+repr(SomeClass())
+
+
'<__main__.SomeClass>'
+
+
+

If you pass a list of attributes (flds) of an object, then this will generate a string with the name of each attribute and its corresponding value. The format of this string is key=value, where key is the name of the attribute, and value is the value of the attribute. For each value, attempt to use the __name__ attribute, otherwise fall back to using the value’s __repr__ when constructing the string.

+
+
class SomeClass:
+    a=1
+    b='foo'
+    __repr__=basic_repr('a,b')
+    __name__='some-class'
+
+repr(SomeClass())
+
+
"__main__.SomeClass(a=1, b='foo')"
+
+
+
+
class AnotherClass:
+    c=SomeClass()
+    d='bar'
+    __repr__=basic_repr(['c', 'd'])
+
+repr(AnotherClass())
+
+
"__main__.AnotherClass(c=__main__.SomeClass(a=1, b='foo'), d='bar')"
+
+
+
+

source

+
+
+

is_array

+
+
 is_array (x)
+
+

True if x supports __array__ or iloc

+
+
is_array(np.array(1)),is_array([1])
+
+
(True, False)
+
+
+
+

source

+
+
+

listify

+
+
 listify (o=None, *rest, use_list=False, match=None)
+
+

Convert o to a list

+

Conversion is designed to “do what you mean”, e.g:

+
+
test_eq(listify('hi'), ['hi'])
+test_eq(listify(b'hi'), [b'hi'])
+test_eq(listify(array(1)), [array(1)])
+test_eq(listify(1), [1])
+test_eq(listify([1,2]), [1,2])
+test_eq(listify(range(3)), [0,1,2])
+test_eq(listify(None), [])
+test_eq(listify(1,2), [1,2])
+
+
+
arr = np.arange(9).reshape(3,3)
+listify(arr)
+
+
[array([[0, 1, 2],
+        [3, 4, 5],
+        [6, 7, 8]])]
+
+
+
+
listify(array([1,2]))
+
+
[array([1, 2])]
+
+
+

Generators are turned into lists too:

+
+
gen = (o for o in range(3))
+test_eq(listify(gen), [0,1,2])
+
+

Use match to provide a length to match:

+
+
test_eq(listify(1,match=3), [1,1,1])
+
+

If match is a sequence, it’s length is used:

+
+
test_eq(listify(1,match=range(3)), [1,1,1])
+
+

If the listified item is not of length 1, it must be the same length as match:

+
+
test_eq(listify([1,1,1],match=3), [1,1,1])
+test_fail(lambda: listify([1,1],match=3))
+
+
+

source

+
+
+

tuplify

+
+
 tuplify (o, use_list=False, match=None)
+
+

Make o a tuple

+
+
test_eq(tuplify(None),())
+test_eq(tuplify([1,2,3]),(1,2,3))
+test_eq(tuplify(1,match=[1,2,3]),(1,1,1))
+
+
+

source

+
+
+

true

+
+
 true (x)
+
+

Test whether x is truthy; collections with >0 elements are considered True

+
+
[(o,true(o)) for o in
+ (array(0),array(1),array([0]),array([0,1]),1,0,'',None)]
+
+
[(array(0), False),
+ (array(1), True),
+ (array([0]), True),
+ (array([0, 1]), True),
+ (1, True),
+ (0, False),
+ ('', False),
+ (None, False)]
+
+
+
+

source

+
+
+

NullType

+
+
 NullType ()
+
+

An object that is False and can be called, chained, and indexed

+
+
bool(null.hi().there[3])
+
+
False
+
+
+
+

source

+
+
+

tonull

+
+
 tonull (x)
+
+

Convert None to null

+
+
bool(tonull(None).hi().there[3])
+
+
False
+
+
+
+

source

+
+
+

get_class

+
+
 get_class (nm, *fld_names, sup=None, doc=None, funcs=None, anno=None,
+            **flds)
+
+

Dynamically create a class, optionally inheriting from sup, containing fld_names

+
+
_t = get_class('_t', 'a', b=2, anno={'b':int})
+t = _t()
+test_eq(t.a, None)
+test_eq(t.b, 2)
+t = _t(1, b=3)
+test_eq(t.a, 1)
+test_eq(t.b, 3)
+t = _t(1, 3)
+test_eq(t.a, 1)
+test_eq(t.b, 3)
+test_eq(t, pickle.loads(pickle.dumps(t)))
+test_eq(_t.__annotations__, {'b':int, 'a':typing.Any})
+repr(t)
+
+
'__main__._t(a=1, b=3)'
+
+
+

Most often you’ll want to call mk_class, since it adds the class to your module. See mk_class for more details and examples of use (which also apply to get_class).

+
+

source

+
+
+

mk_class

+
+
 mk_class (nm, *fld_names, sup=None, doc=None, funcs=None, mod=None,
+           anno=None, **flds)
+
+

Create a class using get_class and add to the caller’s module

+

Any kwargs will be added as class attributes, and sup is an optional (tuple of) base classes.

+
+
mk_class('_t', a=1, sup=dict)
+t = _t()
+test_eq(t.a, 1)
+assert(isinstance(t,dict))
+
+

A __init__ is provided that sets attrs for any kwargs, and for any args (matching by position to fields), along with a __repr__ which prints all attrs. The docstring is set to doc. You can pass funcs which will be added as attrs with the function names.

+
+
def foo(self): return 1
+mk_class('_t', 'a', sup=dict, doc='test doc', funcs=foo)
+
+t = _t(3, b=2)
+test_eq(t.a, 3)
+test_eq(t.b, 2)
+test_eq(t.foo(), 1)
+test_eq(t.__doc__, 'test doc')
+t
+
+
{}
+
+
+
+

source

+
+
+

wrap_class

+
+
 wrap_class (nm, *fld_names, sup=None, doc=None, funcs=None, **flds)
+
+

Decorator: makes function a method of a new class nm passing parameters to mk_class

+
+
@wrap_class('_t', a=2)
+def bar(self,x): return x+1
+
+t = _t()
+test_eq(t.a, 2)
+test_eq(t.bar(3), 4)
+
+
+

source

+
+

ignore_exceptions

+
+
 ignore_exceptions ()
+
+

Context manager to ignore exceptions

+
+
with ignore_exceptions(): 
+    # Exception will be ignored
+    raise Exception
+
+
+

source

+
+
+
+

exec_local

+
+
 exec_local (code, var_name)
+
+

Call exec on code and return the var var_name

+
+
test_eq(exec_local("a=1", "a"), 1)
+
+
+

source

+
+
+

risinstance

+
+
 risinstance (types, obj=None)
+
+

Curried isinstance but with args reversed

+
+
assert risinstance(int, 1)
+assert not risinstance(str, 0)
+assert risinstance(int)(1)
+
+

types can also be strings:

+
+
assert risinstance(('str','int'), 'a')
+assert risinstance('str', 'a')
+assert not risinstance('int', 'a')
+
+
+

source

+
+
+

ver2tuple

+
+
 ver2tuple (v:str)
+
+
+
test_eq(ver2tuple('3.8.1'), (3,8,1))
+test_eq(ver2tuple('3.1'), (3,1,0))
+test_eq(ver2tuple('3.'), (3,0,0))
+test_eq(ver2tuple('3'), (3,0,0))
+
+
+
+
+

NoOp

+

These are used when you need a pass-through function.

+
+
+

noop

+
+
 noop (x=None, *args, **kwargs)
+
+

Do nothing

+
+
noop()
+test_eq(noop(1),1)
+
+
+
+
+

noops

+
+
 noops (x=None, *args, **kwargs)
+
+

Do nothing (method)

+
+
class _t: foo=noops
+test_eq(_t().foo(1),1)
+
+
+
+
+

Infinite Lists

+

These lists are useful for things like padding an array or adding index column(s) to arrays.

+

Inf defines the following properties:

+
    +
  • count: itertools.count()
  • +
  • zeros: itertools.cycle([0])
  • +
  • ones : itertools.cycle([1])
  • +
  • nones: itertools.cycle([None])
  • +
+
+
test_eq([o for i,o in zip(range(5), Inf.count)],
+        [0, 1, 2, 3, 4])
+
+test_eq([o for i,o in zip(range(5), Inf.zeros)],
+        [0]*5)
+
+test_eq([o for i,o in zip(range(5), Inf.ones)],
+        [1]*5)
+
+test_eq([o for i,o in zip(range(5), Inf.nones)],
+        [None]*5)
+
+
+
+

Operator Functions

+
+

source

+
+

in_

+
+
 in_ (x, a)
+
+

True if x in a

+
+
# test if element is in another
+assert in_('c', ('b', 'c', 'a'))
+assert in_(4, [2,3,4,5])
+assert in_('t', 'fastai')
+test_fail(in_('h', 'fastai'))
+
+# use in_ as a partial
+assert in_('fastai')('t')
+assert in_([2,3,4,5])(4)
+test_fail(in_('fastai')('h'))
+
+

In addition to in_, the following functions are provided matching the behavior of the equivalent versions in operator: lt gt le ge eq ne add sub mul truediv is_ is_not mod.

+
+
lt(3,5),gt(3,5),is_(None,None),in_(0,[1,2]),mod(3,2)
+
+
(True, False, True, False, 1)
+
+
+

Similarly to _in, they also have additional functionality: if you only pass one param, they return a partial function that passes that param as the second positional parameter.

+
+
lt(5)(3),gt(5)(3),is_(None)(None),in_([1,2])(0),mod(2)(3)
+
+
(True, False, True, False, 1)
+
+
+
+

source

+
+
+

ret_true

+
+
 ret_true (*args, **kwargs)
+
+

Predicate: always True

+
+
assert ret_true(1,2,3)
+assert ret_true(False)
+
+
+

source

+
+
+

ret_false

+
+
 ret_false (*args, **kwargs)
+
+

Predicate: always False

+
+

source

+
+
+

stop

+
+
 stop (e=<class 'StopIteration'>)
+
+

Raises exception e (by default StopIteration)

+
+

source

+
+
+

gen

+
+
 gen (func, seq, cond=<function ret_true>)
+
+

Like (func(o) for o in seq if cond(func(o))) but handles StopIteration

+
+
test_eq(gen(noop, Inf.count, lt(5)),
+        range(5))
+test_eq(gen(operator.neg, Inf.count, gt(-5)),
+        [0,-1,-2,-3,-4])
+test_eq(gen(lambda o:o if o<5 else stop(), Inf.count),
+        range(5))
+
+
+

source

+
+
+

chunked

+
+
 chunked (it, chunk_sz=None, drop_last=False, n_chunks=None)
+
+

Return batches from iterator it of size chunk_sz (or return n_chunks total)

+

Note that you must pass either chunk_sz, or n_chunks, but not both.

+
+
t = list(range(10))
+test_eq(chunked(t,3),      [[0,1,2], [3,4,5], [6,7,8], [9]])
+test_eq(chunked(t,3,True), [[0,1,2], [3,4,5], [6,7,8],    ])
+
+t = map(lambda o:stop() if o==6 else o, Inf.count)
+test_eq(chunked(t,3), [[0, 1, 2], [3, 4, 5]])
+t = map(lambda o:stop() if o==7 else o, Inf.count)
+test_eq(chunked(t,3), [[0, 1, 2], [3, 4, 5], [6]])
+
+t = np.arange(10)
+test_eq(chunked(t,3),      [[0,1,2], [3,4,5], [6,7,8], [9]])
+test_eq(chunked(t,3,True), [[0,1,2], [3,4,5], [6,7,8],    ])
+
+test_eq(chunked([], 3),          [])
+test_eq(chunked([], n_chunks=3), [])
+
+
+

source

+
+
+

otherwise

+
+
 otherwise (x, tst, y)
+
+

y if tst(x) else x

+
+
test_eq(otherwise(2+1, gt(3), 4), 3)
+test_eq(otherwise(2+1, gt(2), 4), 4)
+
+
+
+
+

Attribute Helpers

+

These functions reduce boilerplate when setting or manipulating attributes or properties of objects.

+
+

source

+
+

custom_dir

+
+
 custom_dir (c, add)
+
+

Implement custom __dir__, adding add to cls

+

custom_dir allows you extract the __dict__ property of a class and appends the list add to it.

+
+
class _T: 
+    def f(): pass
+
+s = custom_dir(_T(), add=['foo', 'bar'])
+assert {'foo', 'bar', 'f'}.issubset(s)
+
+
+

source

+
+
+

AttrDict

+

dict subclass that also provides access to keys as attrs

+
+
d = AttrDict(a=1,b="two")
+test_eq(d.a, 1)
+test_eq(d['b'], 'two')
+test_eq(d.get('c','nope'), 'nope')
+d.b = 2
+test_eq(d.b, 2)
+test_eq(d['b'], 2)
+d['b'] = 3
+test_eq(d['b'], 3)
+test_eq(d.b, 3)
+assert 'a' in dir(d)
+
+

AttrDict will pretty print in Jupyter Notebooks:

+
+
_test_dict = {'a':1, 'b': {'c':1, 'd':2}, 'c': {'c':1, 'd':2}, 'd': {'c':1, 'd':2},
+              'e': {'c':1, 'd':2}, 'f': {'c':1, 'd':2, 'e': 4, 'f':[1,2,3,4,5]}}
+AttrDict(_test_dict)
+
+
{ 'a': 1,
+  'b': {'c': 1, 'd': 2},
+  'c': {'c': 1, 'd': 2},
+  'd': {'c': 1, 'd': 2},
+  'e': {'c': 1, 'd': 2},
+  'f': {'c': 1, 'd': 2, 'e': 4, 'f': [1, 2, 3, 4, 5]}}
+
+
+
+

source

+
+
+

NS

+

SimpleNamespace subclass that also adds iter and dict support

+

This is very similar to AttrDict, but since it starts with SimpleNamespace, it has some differences in behavior. You can use it just like SimpleNamespace:

+
+
d = NS(**_test_dict)
+d
+
+
namespace(a=1,
+          b={'c': 1, 'd': 2},
+          c={'c': 1, 'd': 2},
+          d={'c': 1, 'd': 2},
+          e={'c': 1, 'd': 2},
+          f={'c': 1, 'd': 2, 'e': 4, 'f': [1, 2, 3, 4, 5]})
+
+
+

…but you can also index it to get/set:

+
+
d['a']
+
+
1
+
+
+

…and iterate t:

+
+
list(d)
+
+
['a', 'b', 'c', 'd', 'e', 'f']
+
+
+
+

source

+
+
+

get_annotations_ex

+
+
 get_annotations_ex (obj, globals=None, locals=None)
+
+

Backport of py3.10 get_annotations that returns globals/locals

+

In Python 3.10 inspect.get_annotations was added. However previous versions of Python are unable to evaluate type annotations correctly if from future import __annotations__ is used. Furthermore, all annotations are evaluated, even if only some subset are needed. get_annotations_ex provides the same functionality as inspect.get_annotations, but works on earlier versions of Python, and returns the globals and locals needed to evaluate types.

+
+

source

+
+
+

eval_type

+
+
 eval_type (t, glb, loc)
+
+

eval a type or collection of types, if needed, for annotations in py3.10+

+

In py3.10, or if from future import __annotations__ is used, a is a str:

+
+
class _T2a: pass
+def func(a: _T2a): pass
+ann,glb,loc = get_annotations_ex(func)
+
+eval_type(ann['a'], glb, loc)
+
+
__main__._T2a
+
+
+

| is supported for defining Union types when using eval_type even for python versions prior to 3.9:

+
+
class _T2b: pass
+def func(a: _T2a|_T2b): pass
+ann,glb,loc = get_annotations_ex(func)
+
+eval_type(ann['a'], glb, loc)
+
+
typing.Union[__main__._T2a, __main__._T2b]
+
+
+
+

source

+
+
+

type_hints

+
+
 type_hints (f)
+
+

Like typing.get_type_hints but returns {} if not allowed type

+

Below is a list of allowed types for type hints in python:

+
+
list(typing._allowed_types)
+
+
[function,
+ builtin_function_or_method,
+ method,
+ module,
+ wrapper_descriptor,
+ method-wrapper,
+ method_descriptor]
+
+
+

For example, type func is allowed so type_hints returns the same value as typing.get_hints:

+
+
def f(a:int)->bool: ... # a function with type hints (allowed)
+exp = {'a':int,'return':bool}
+test_eq(type_hints(f), typing.get_type_hints(f))
+test_eq(type_hints(f), exp)
+
+

However, class is not an allowed type, so type_hints returns {}:

+
+
class _T:
+    def __init__(self, a:int=0)->bool: ...
+assert not type_hints(_T)
+
+
+

source

+
+
+

annotations

+
+
 annotations (o)
+
+

Annotations for o, or type(o)

+

This supports a wider range of situations than type_hints, by checking type() and __init__ for annotations too:

+
+
for o in _T,_T(),_T.__init__,f: test_eq(annotations(o), exp)
+assert not annotations(int)
+assert not annotations(print)
+
+
+

source

+
+
+

anno_ret

+
+
 anno_ret (func)
+
+

Get the return annotation of func

+
+
def f(x) -> float: return x
+test_eq(anno_ret(f), float)
+
+def f(x) -> typing.Tuple[float,float]: return x
+assert anno_ret(f)==typing.Tuple[float,float]
+
+

If your return annotation is None, anno_ret will return NoneType (and not None):

+
+
def f(x) -> None: return x
+
+test_eq(anno_ret(f), NoneType)
+assert anno_ret(f) is not None # returns NoneType instead of None
+
+

If your function does not have a return type, or if you pass in None instead of a function, then anno_ret returns None:

+
+
def f(x): return x
+
+test_eq(anno_ret(f), None)
+test_eq(anno_ret(None), None) # instead of passing in a func, pass in None
+
+
+

source

+
+
+

signature_ex

+
+
 signature_ex (obj, eval_str:bool=False)
+
+

Backport of inspect.signature(..., eval_str=True to <py310

+
+

source

+
+
+

union2tuple

+
+
 union2tuple (t)
+
+
+
test_eq(union2tuple(Union[int,str]), (int,str))
+test_eq(union2tuple(int), int)
+assert union2tuple(Tuple[int,str])==Tuple[int,str]
+test_eq(union2tuple((int,str)), (int,str))
+if UnionType: test_eq(union2tuple(int|str), (int,str))
+
+
+

source

+
+
+

argnames

+
+
 argnames (f, frame=False)
+
+

Names of arguments to function or frame f

+
+
test_eq(argnames(f), ['x'])
+
+
+

source

+
+
+

with_cast

+
+
 with_cast (f)
+
+

Decorator which uses any parameter annotations as preprocessing functions

+
+
@with_cast
+def _f(a, b:Path, c:str='', d=0): return (a,b,c,d)
+
+test_eq(_f(1, '.', 3), (1,Path('.'),'3',0))
+test_eq(_f(1, '.'), (1,Path('.'),'',0))
+
+@with_cast
+def _g(a:int=0)->str: return a
+
+test_eq(_g(4.0), '4')
+test_eq(_g(4.4), '4')
+test_eq(_g(2), '2')
+
+
+

source

+
+
+

store_attr

+
+
 store_attr (names=None, but='', cast=False, store_args=None, **attrs)
+
+

Store params named in comma-separated names from calling context into attrs in self

+

In it’s most basic form, you can use store_attr to shorten code like this:

+
+
class T:
+    def __init__(self, a,b,c): self.a,self.b,self.c = a,b,c
+
+

…to this:

+
+
class T:
+    def __init__(self, a,b,c): store_attr('a,b,c', self)
+
+

This class behaves as if we’d used the first form:

+
+
t = T(1,c=2,b=3)
+assert t.a==1 and t.b==3 and t.c==2
+
+

In addition, it stores the attrs as a dict in __stored_args__, which you can use for display, logging, and so forth.

+
+
test_eq(t.__stored_args__, {'a':1, 'b':3, 'c':2})
+
+

Since you normally want to use the first argument (often called self) for storing attributes, it’s optional:

+
+
class T:
+    def __init__(self, a,b,c:str): store_attr('a,b,c')
+
+t = T(1,c=2,b=3)
+assert t.a==1 and t.b==3 and t.c==2
+
+

With cast=True any parameter annotations will be used as preprocessing functions for the corresponding arguments:

+
+
class T:
+    def __init__(self, a:listify, b, c:str): store_attr('a,b,c', cast=True)
+
+t = T(1,c=2,b=3)
+assert t.a==[1] and t.b==3 and t.c=='2'
+
+

You can inherit from a class using store_attr, and just call it again to add in any new attributes added in the derived class:

+
+
class T2(T):
+    def __init__(self, d, **kwargs):
+        super().__init__(**kwargs)
+        store_attr('d')
+
+t = T2(d=1,a=2,b=3,c=4)
+assert t.a==2 and t.b==3 and t.c==4 and t.d==1
+
+

You can skip passing a list of attrs to store. In this case, all arguments passed to the method are stored:

+
+
class T:
+    def __init__(self, a,b,c): store_attr()
+
+t = T(1,c=2,b=3)
+assert t.a==1 and t.b==3 and t.c==2
+
+
+
class T4(T):
+    def __init__(self, d, **kwargs):
+        super().__init__(**kwargs)
+        store_attr()
+
+t = T4(4, a=1,c=2,b=3)
+assert t.a==1 and t.b==3 and t.c==2 and t.d==4
+
+
+
class T4:
+    def __init__(self, *, a: int, b: float = 1):
+        store_attr()
+        
+t = T4(a=3)
+assert t.a==3 and t.b==1
+t = T4(a=3, b=2)
+assert t.a==3 and t.b==2
+
+

You can skip some attrs by passing but:

+
+
class T:
+    def __init__(self, a,b,c): store_attr(but='a')
+
+t = T(1,c=2,b=3)
+assert t.b==3 and t.c==2
+assert not hasattr(t,'a')
+
+

You can also pass keywords to store_attr, which is identical to setting the attrs directly, but also stores them in __stored_args__.

+
+
class T:
+    def __init__(self): store_attr(a=1)
+
+t = T()
+assert t.a==1
+
+

You can also use store_attr inside functions.

+
+
def create_T(a, b):
+    t = SimpleNamespace()
+    store_attr(self=t)
+    return t
+
+t = create_T(a=1, b=2)
+assert t.a==1 and t.b==2
+
+
+

source

+
+
+

attrdict

+
+
 attrdict (o, *ks, default=None)
+
+

Dict from each k in ks to getattr(o,k)

+
+
class T:
+    def __init__(self, a,b,c): store_attr()
+
+t = T(1,c=2,b=3)
+test_eq(attrdict(t,'b','c'), {'b':3, 'c':2})
+
+
+

source

+
+
+

properties

+
+
 properties (cls, *ps)
+
+

Change attrs in cls with names in ps to properties

+
+
class T:
+    def a(self): return 1
+    def b(self): return 2
+properties(T,'a')
+
+test_eq(T().a,1)
+test_eq(T().b(),2)
+
+
+

source

+
+
+

camel2words

+
+
 camel2words (s, space=' ')
+
+

Convert CamelCase to ‘spaced words’

+
+
test_eq(camel2words('ClassAreCamel'), 'Class Are Camel')
+
+
+

source

+
+
+

camel2snake

+
+
 camel2snake (name)
+
+

Convert CamelCase to snake_case

+
+
test_eq(camel2snake('ClassAreCamel'), 'class_are_camel')
+test_eq(camel2snake('Already_Snake'), 'already__snake')
+
+
+

source

+
+
+

snake2camel

+
+
 snake2camel (s)
+
+

Convert snake_case to CamelCase

+
+
test_eq(snake2camel('a_b_cc'), 'ABCc')
+
+
+

source

+
+
+

class2attr

+
+
 class2attr (cls_name)
+
+

Return the snake-cased name of the class; strip ending cls_name if it exists.

+
+
class Parent:
+    @property
+    def name(self): return class2attr(self, 'Parent')
+
+class ChildOfParent(Parent): pass
+class ParentChildOf(Parent): pass
+
+p = Parent()
+cp = ChildOfParent()
+cp2 = ParentChildOf()
+
+test_eq(p.name, 'parent')
+test_eq(cp.name, 'child_of')
+test_eq(cp2.name, 'parent_child_of')
+
+
+

source

+
+
+

getcallable

+
+
 getcallable (o, attr)
+
+

Calls getattr with a default of noop

+
+
class Math:
+    def addition(self,a,b): return a+b
+
+m = Math()
+
+test_eq(getcallable(m, "addition")(a=1,b=2), 3)
+test_eq(getcallable(m, "subtraction")(a=1,b=2), None)
+
+
+

source

+
+
+

getattrs

+
+
 getattrs (o, *attrs, default=None)
+
+

List of all attrs in o

+
+
from fractions import Fraction
+
+
+
getattrs(Fraction(1,2), 'numerator', 'denominator')
+
+
[1, 2]
+
+
+
+

source

+
+
+

hasattrs

+
+
 hasattrs (o, attrs)
+
+

Test whether o contains all attrs

+
+
assert hasattrs(1,('imag','real'))
+assert not hasattrs(1,('imag','foo'))
+
+
+

source

+
+
+

setattrs

+
+
 setattrs (dest, flds, src)
+
+
+
d = dict(a=1,bb="2",ignore=3)
+o = SimpleNamespace()
+setattrs(o, "a,bb", d)
+test_eq(o.a, 1)
+test_eq(o.bb, "2")
+
+
+
d = SimpleNamespace(a=1,bb="2",ignore=3)
+o = SimpleNamespace()
+setattrs(o, "a,bb", d)
+test_eq(o.a, 1)
+test_eq(o.bb, "2")
+
+
+

source

+
+
+

try_attrs

+
+
 try_attrs (obj, *attrs)
+
+

Return first attr that exists in obj

+
+
test_eq(try_attrs(1, 'real'), 1)
+test_eq(try_attrs(1, 'foobar', 'real'), 1)
+
+
+
+
+

Attribute Delegation

+
+

source

+
+

GetAttrBase

+
+
 GetAttrBase ()
+
+

Basic delegation of __getattr__ and __dir__

+
+

source

+
+

GetAttr

+
+
 GetAttr ()
+
+

Inherit from this to have all attr accesses in self._xtra passed down to self.default

+

Inherit from GetAttr to have attr access passed down to an instance attribute. This makes it easy to create composites that don’t require callers to know about their components. For a more detailed discussion of how this works as well as relevant context, we suggest reading the delegated composition section of this blog article.

+

You can customise the behaviour of GetAttr in subclasses via; - _default - By default, this is set to 'default', so attr access is passed down to self.default - _default can be set to the name of any instance attribute that does not start with dunder __ - _xtra - By default, this is None, so all attr access is passed down - You can limit which attrs get passed down by setting _xtra to a list of attribute names

+

To illuminate the utility of GetAttr, suppose we have the following two classes, _WebPage which is a superclass of _ProductPage, which we wish to compose like so:

+
+
class _WebPage:
+    def __init__(self, title, author="Jeremy"):
+        self.title,self.author = title,author
+
+class _ProductPage:
+    def __init__(self, page, price): self.page,self.price = page,price
+        
+page = _WebPage('Soap', author="Sylvain")
+p = _ProductPage(page, 15.0)
+
+

How do we make it so we can just write p.author, instead of p.page.author to access the author attribute? We can use GetAttr, of course! First, we subclass GetAttr when defining _ProductPage. Next, we set self.default to the object whose attributes we want to be able to access directly, which in this case is the page argument passed on initialization:

+
+
class _ProductPage(GetAttr):
+    def __init__(self, page, price): self.default,self.price = page,price #self.default allows you to access page directly.
+
+p = _ProductPage(page, 15.0)
+
+

Now, we can access the author attribute directly from the instance:

+
+
test_eq(p.author, 'Sylvain')
+
+

If you wish to store the object you are composing in an attribute other than self.default, you can set the class attribute _data as shown below. This is useful in the case where you might have a name collision with self.default:

+
+
class _C(GetAttr):
+    _default = '_data' # use different component name; `self._data` rather than `self.default`
+    def __init__(self,a): self._data = a
+    def foo(self): noop
+
+t = _C('Hi')
+test_eq(t._data, 'Hi') 
+test_fail(lambda: t.default) # we no longer have self.default
+test_eq(t.lower(), 'hi')
+test_eq(t.upper(), 'HI')
+assert 'lower' in dir(t)
+assert 'upper' in dir(t)
+
+

By default, all attributes and methods of the object you are composing are retained. In the below example, we compose a str object with the class _C. This allows us to directly call string methods on instances of class _C, such as str.lower() or str.upper():

+
+
class _C(GetAttr):
+    # allow all attributes and methods to get passed to `self.default` (by leaving _xtra=None)
+    def __init__(self,a): self.default = a
+    def foo(self): noop
+
+t = _C('Hi')
+test_eq(t.lower(), 'hi')
+test_eq(t.upper(), 'HI')
+assert 'lower' in dir(t)
+assert 'upper' in dir(t)
+
+

However, you can choose which attributes or methods to retain by defining a class attribute _xtra, which is a list of allowed attribute and method names to delegate. In the below example, we only delegate the lower method from the composed str object when defining class _C:

+
+
class _C(GetAttr):
+    _xtra = ['lower'] # specify which attributes get passed to `self.default`
+    def __init__(self,a): self.default = a
+    def foo(self): noop
+
+t = _C('Hi')
+test_eq(t.default, 'Hi')
+test_eq(t.lower(), 'hi')
+test_fail(lambda: t.upper()) # upper wasn't in _xtra, so it isn't available to be called
+assert 'lower' in dir(t)
+assert 'upper' not in dir(t)
+
+

You must be careful to properly set an instance attribute in __init__ that corresponds to the class attribute _default. The below example sets the class attribute _default to data, but erroneously fails to define self.data (and instead defines self.default).

+

Failing to properly set instance attributes leads to errors when you try to access methods directly:

+
+
class _C(GetAttr):
+    _default = 'data' # use a bad component name; i.e. self.data does not exist
+    def __init__(self,a): self.default = a
+    def foo(self): noop
+        
+# TODO: should we raise an error when we create a new instance ...
+t = _C('Hi')
+test_eq(t.default, 'Hi')
+# ... or is it enough for all GetAttr features to raise errors
+test_fail(lambda: t.data)
+test_fail(lambda: t.lower())
+test_fail(lambda: t.upper())
+test_fail(lambda: dir(t))
+
+
+

source

+
+
+
+

delegate_attr

+
+
 delegate_attr (k, to)
+
+

Use in __getattr__ to delegate to attr to without inheriting from GetAttr

+

delegate_attr is a functional way to delegate attributes, and is an alternative to GetAttr. We recommend reading the documentation of GetAttr for more details around delegation.

+

You can use achieve delegation when you define __getattr__ by using delegate_attr:

+
+
class _C:
+    def __init__(self, o): self.o = o # self.o corresponds to the `to` argument in delegate_attr.
+    def __getattr__(self, k): return delegate_attr(self, k, to='o')
+    
+
+t = _C('HELLO') # delegates to a string
+test_eq(t.lower(), 'hello')
+
+t = _C(np.array([5,4,3])) # delegates to a numpy array
+test_eq(t.sum(), 12)
+
+t = _C(pd.DataFrame({'a': [1,2], 'b': [3,4]})) # delegates to a pandas.DataFrame
+test_eq(t.b.max(), 4)
+
+
+
+
+

Extensible Types

+

ShowPrint is a base class that defines a show method, which is used primarily for callbacks in fastai that expect this method to be defined.

+

Int, Float, and Str extend int, float and str respectively by adding an additional show method by inheriting from ShowPrint.

+

The code for Int is shown below:

+

Examples:

+
+
Int(0).show()
+Float(2.0).show()
+Str('Hello').show()
+
+
0
+2.0
+Hello
+
+
+
+
+

Collection functions

+

Functions that manipulate popular python collections.

+
+

source

+
+

partition

+
+
 partition (coll, f)
+
+

Partition a collection by a predicate

+
+
ts,fs = partition(range(10), mod(2))
+test_eq(fs, [0,2,4,6,8])
+test_eq(ts, [1,3,5,7,9])
+
+
+

source

+
+
+

flatten

+
+
 flatten (o)
+
+

Concatenate all collections and items as a generator

+
+

source

+
+
+

concat

+
+
 concat (colls)
+
+

Concatenate all collections and items as a list

+
+
concat([(o for o in range(2)),[2,3,4], 5])
+
+
[0, 1, 2, 3, 4, 5]
+
+
+
+
concat([["abc", "xyz"], ["foo", "bar"]])
+
+
['abc', 'xyz', 'foo', 'bar']
+
+
+
+

source

+
+
+

strcat

+
+
 strcat (its, sep:str='')
+
+

Concatenate stringified items its

+
+
test_eq(strcat(['a',2]), 'a2')
+test_eq(strcat(['a',2], ';'), 'a;2')
+
+
+

source

+
+
+

detuplify

+
+
 detuplify (x)
+
+

If x is a tuple with one thing, extract it

+
+
test_eq(detuplify(()),None)
+test_eq(detuplify([1]),1)
+test_eq(detuplify([1,2]), [1,2])
+test_eq(detuplify(np.array([[1,2]])), np.array([[1,2]]))
+
+
+

source

+
+
+

replicate

+
+
 replicate (item, match)
+
+

Create tuple of item copied len(match) times

+
+
t = [1,1]
+test_eq(replicate([1,2], t),([1,2],[1,2]))
+test_eq(replicate(1, t),(1,1))
+
+
+

source

+
+
+

setify

+
+
 setify (o)
+
+

Turn any list like-object into a set.

+
+
# test
+test_eq(setify(None),set())
+test_eq(setify('abc'),{'abc'})
+test_eq(setify([1,2,2]),{1,2})
+test_eq(setify(range(0,3)),{0,1,2})
+test_eq(setify({1,2}),{1,2})
+
+
+

source

+
+
+

merge

+
+
 merge (*ds)
+
+

Merge all dictionaries in ds

+
+
test_eq(merge(), {})
+test_eq(merge(dict(a=1,b=2)), dict(a=1,b=2))
+test_eq(merge(dict(a=1,b=2), dict(b=3,c=4), None), dict(a=1, b=3, c=4))
+
+
+

source

+
+
+

range_of

+
+
 range_of (x)
+
+

All indices of collection x (i.e. list(range(len(x))))

+
+
test_eq(range_of([1,1,1,1]), [0,1,2,3])
+
+
+

source

+
+
+

groupby

+
+
 groupby (x, key, val=<function noop>)
+
+

Like itertools.groupby but doesn’t need to be sorted, and isn’t lazy, plus some extensions

+
+
test_eq(groupby('aa ab bb'.split(), itemgetter(0)), {'a':['aa','ab'], 'b':['bb']})
+
+

Here’s an example of how to invert a grouping, using an int as key (which uses itemgetter; passing a str will use attrgetter), and using a val function:

+
+
d = {0: [1, 3, 7], 2: [3], 3: [5], 4: [8], 5: [4], 7: [5]}
+groupby(((o,k) for k,v in d.items() for o in v), 0, 1)
+
+
{1: [0], 3: [0, 2], 7: [0], 5: [3, 7], 8: [4], 4: [5]}
+
+
+
+

source

+
+
+

last_index

+
+
 last_index (x, o)
+
+

Finds the last index of occurence of x in o (returns -1 if no occurence)

+
+
test_eq(last_index(9, [1, 2, 9, 3, 4, 9, 10]), 5)
+test_eq(last_index(6, [1, 2, 9, 3, 4, 9, 10]), -1)
+
+
+

source

+
+
+

filter_dict

+
+
 filter_dict (d, func)
+
+

Filter a dict using func, applied to keys and values

+
+
letters = {o:chr(o) for o in range(65,73)}
+letters
+
+
{65: 'A', 66: 'B', 67: 'C', 68: 'D', 69: 'E', 70: 'F', 71: 'G', 72: 'H'}
+
+
+
+
filter_dict(letters, lambda k,v: k<67 or v in 'FG')
+
+
{65: 'A', 66: 'B', 70: 'F', 71: 'G'}
+
+
+
+

source

+
+
+

filter_keys

+
+
 filter_keys (d, func)
+
+

Filter a dict using func, applied to keys

+
+
filter_keys(letters, lt(67))
+
+
{65: 'A', 66: 'B'}
+
+
+
+

source

+
+
+

filter_values

+
+
 filter_values (d, func)
+
+

Filter a dict using func, applied to values

+
+
filter_values(letters, in_('FG'))
+
+
{70: 'F', 71: 'G'}
+
+
+
+

source

+
+
+

cycle

+
+
 cycle (o)
+
+

Like itertools.cycle except creates list of Nones if o is empty

+
+
test_eq(itertools.islice(cycle([1,2,3]),5), [1,2,3,1,2])
+test_eq(itertools.islice(cycle([]),3), [None]*3)
+test_eq(itertools.islice(cycle(None),3), [None]*3)
+test_eq(itertools.islice(cycle(1),3), [1,1,1])
+
+
+

source

+
+
+

zip_cycle

+
+
 zip_cycle (x, *args)
+
+

Like itertools.zip_longest but cycles through elements of all but first argument

+
+
test_eq(zip_cycle([1,2,3,4],list('abc')), [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'a')])
+
+
+

source

+
+
+

sorted_ex

+
+
 sorted_ex (iterable, key=None, reverse=False)
+
+

Like sorted, but if key is str use attrgetter; if int use itemgetter

+
+

source

+
+
+

not_

+
+
 not_ (f)
+
+

Create new function that negates result of f

+
+
def f(a): return a>0
+test_eq(f(1),True)
+test_eq(not_(f)(1),False)
+test_eq(not_(f)(a=-1),True)
+
+
+

source

+
+
+

argwhere

+
+
 argwhere (iterable, f, negate=False, **kwargs)
+
+

Like filter_ex, but return indices for matching items

+
+

source

+
+
+

filter_ex

+
+
 filter_ex (iterable, f=<function noop>, negate=False, gen=False,
+            **kwargs)
+
+

Like filter, but passing kwargs to f, defaulting f to noop, and adding negate and gen

+
+

source

+
+
+

range_of

+
+
 range_of (a, b=None, step=None)
+
+

All indices of collection a, if a is a collection, otherwise range

+
+
test_eq(range_of([1,1,1,1]), [0,1,2,3])
+test_eq(range_of(4), [0,1,2,3])
+
+
+

source

+
+
+

renumerate

+
+
 renumerate (iterable, start=0)
+
+

Same as enumerate, but returns index as 2nd element instead of 1st

+
+
test_eq(renumerate('abc'), (('a',0),('b',1),('c',2)))
+
+
+

source

+
+
+

first

+
+
 first (x, f=None, negate=False, **kwargs)
+
+

First element of x, optionally filtered by f, or None if missing

+
+
test_eq(first(['a', 'b', 'c', 'd', 'e']), 'a')
+test_eq(first([False]), False)
+test_eq(first([False], noop), None)
+
+
+

source

+
+
+

only

+
+
 only (o)
+
+

Return the only item of o, raise if o doesn’t have exactly one item

+
+

source

+
+
+

nested_attr

+
+
 nested_attr (o, attr, default=None)
+
+

Same as getattr, but if attr includes a ., then looks inside nested objects

+
+
a = SimpleNamespace(b=(SimpleNamespace(c=1)))
+test_eq(nested_attr(a, 'b.c'), getattr(getattr(a, 'b'), 'c'))
+test_eq(nested_attr(a, 'b.d'), None)
+
+
+

source

+
+
+

nested_setdefault

+
+
 nested_setdefault (o, attr, default)
+
+

Same as setdefault, but if attr includes a ., then looks inside nested objects

+
+

source

+
+
+

nested_callable

+
+
 nested_callable (o, attr)
+
+

Same as nested_attr but if not found will return noop

+
+
a = SimpleNamespace(b=(SimpleNamespace(c=1)))
+test_eq(nested_callable(a, 'b.c'), getattr(getattr(a, 'b'), 'c'))
+test_eq(nested_callable(a, 'b.d'), noop)
+
+
+

source

+
+
+

nested_idx

+
+
 nested_idx (coll, *idxs)
+
+

Index into nested collections, dicts, etc, with idxs

+
+
a = {'b':[1,{'c':2}]}
+test_eq(nested_idx(a, 'nope'), None)
+test_eq(nested_idx(a, 'nope', 'nup'), None)
+test_eq(nested_idx(a, 'b', 3), None)
+test_eq(nested_idx(a), a)
+test_eq(nested_idx(a, 'b'), [1,{'c':2}])
+test_eq(nested_idx(a, 'b', 1), {'c':2})
+test_eq(nested_idx(a, 'b', 1, 'c'), 2)
+
+
+
a = SimpleNamespace(b=[1,{'c':2}])
+test_eq(nested_idx(a, 'nope'), None)
+test_eq(nested_idx(a, 'nope', 'nup'), None)
+test_eq(nested_idx(a, 'b', 3), None)
+test_eq(nested_idx(a), a)
+test_eq(nested_idx(a, 'b'), [1,{'c':2}])
+test_eq(nested_idx(a, 'b', 1), {'c':2})
+test_eq(nested_idx(a, 'b', 1, 'c'), 2)
+
+
+

source

+
+
+

set_nested_idx

+
+
 set_nested_idx (coll, value, *idxs)
+
+

Set value indexed like `nested_idx

+
+
set_nested_idx(a, 3, 'b', 0)
+test_eq(nested_idx(a, 'b', 0), 3)
+
+
+

source

+
+
+

val2idx

+
+
 val2idx (x)
+
+

Dict from value to index

+
+
test_eq(val2idx([1,2,3]), {3:2,1:0,2:1})
+
+
+

source

+
+
+

uniqueify

+
+
 uniqueify (x, sort=False, bidir=False, start=None)
+
+

Unique elements in x, optional sort, optional return reverse correspondence, optional prepend with elements.

+
+
t = [1,1,0,5,0,3]
+test_eq(uniqueify(t),[1,0,5,3])
+test_eq(uniqueify(t, sort=True),[0,1,3,5])
+test_eq(uniqueify(t, start=[7,8,6]), [7,8,6,1,0,5,3])
+v,o = uniqueify(t, bidir=True)
+test_eq(v,[1,0,5,3])
+test_eq(o,{1:0, 0: 1, 5: 2, 3: 3})
+v,o = uniqueify(t, sort=True, bidir=True)
+test_eq(v,[0,1,3,5])
+test_eq(o,{0:0, 1: 1, 3: 2, 5: 3})
+
+
+

source

+
+
+

loop_first_last

+
+
 loop_first_last (values)
+
+

Iterate and generate a tuple with a flag for first and last value.

+
+
test_eq(loop_first_last(range(3)), [(True,False,0), (False,False,1), (False,True,2)])
+
+
+

source

+
+
+

loop_first

+
+
 loop_first (values)
+
+

Iterate and generate a tuple with a flag for first value.

+
+
test_eq(loop_first(range(3)), [(True,0), (False,1), (False,2)])
+
+
+

source

+
+
+

loop_last

+
+
 loop_last (values)
+
+

Iterate and generate a tuple with a flag for last value.

+
+
test_eq(loop_last(range(3)), [(False,0), (False,1), (True,2)])
+
+
+

source

+
+
+

first_match

+
+
 first_match (lst, f, default=None)
+
+

First element of lst matching predicate f, or default if none

+
+
a = [0,2,4,5,6,7,10]
+test_eq(first_match(a, lambda o:o%2), 3)
+
+
+

source

+
+
+

last_match

+
+
 last_match (lst, f, default=None)
+
+

Last element of lst matching predicate f, or default if none

+
+
test_eq(last_match(a, lambda o:o%2), 5)
+
+
+
+
+

fastuple

+

A tuple with extended functionality.

+
+

source

+
+

fastuple

+
+
 fastuple (x=None, *rest)
+
+

A tuple with elementwise ops and more friendly init behavior

+
+
+

Friendly init behavior

+

Common failure modes when trying to initialize a tuple in python:

+
tuple(3)
+> TypeError: 'int' object is not iterable
+

or

+
tuple(3, 4)
+> TypeError: tuple expected at most 1 arguments, got 2
+

However, fastuple allows you to define tuples like this and in the usual way:

+
+
test_eq(fastuple(3), (3,))
+test_eq(fastuple(3,4), (3, 4))
+test_eq(fastuple((3,4)), (3, 4))
+
+
+
+

Elementwise operations

+
+

source

+
+
fastuple.add
+
+
 fastuple.add (*args)
+
+

+ is already defined in tuple for concat, so use add instead

+
+
test_eq(fastuple.add((1,1),(2,2)), (3,3))
+test_eq_type(fastuple(1,1).add(2), fastuple(3,3))
+test_eq(fastuple('1','2').add('2'), fastuple('12','22'))
+
+
+

source

+
+
+
fastuple.mul
+
+
 fastuple.mul (*args)
+
+

* is already defined in tuple for replicating, so use mul instead

+
+
test_eq_type(fastuple(1,1).mul(2), fastuple(2,2))
+
+
+
+
+

Other Elementwise Operations

+

Additionally, the following elementwise operations are available: - le: less than or equal - eq: equal - gt: greater than - min: minimum of

+
+
test_eq(fastuple(3,1).le(1), (False, True))
+test_eq(fastuple(3,1).eq(1), (False, True))
+test_eq(fastuple(3,1).gt(1), (True, False))
+test_eq(fastuple(3,1).min(2), (2,1))
+
+

You can also do other elementwise operations like negate a fastuple, or subtract two fastuples:

+
+
test_eq(-fastuple(1,2), (-1,-2))
+test_eq(~fastuple(1,0,1), (False,True,False))
+
+test_eq(fastuple(1,1)-fastuple(2,2), (-1,-1))
+
+
+
test_eq(type(fastuple(1)), fastuple)
+test_eq_type(fastuple(1,2), fastuple(1,2))
+test_ne(fastuple(1,2), fastuple(1,3))
+test_eq(fastuple(), ())
+
+
+
+
+

Functions on Functions

+

Utilities for functional programming or for defining, modifying, or debugging functions.

+
+

source

+
+

bind

+
+
 bind (func, *pargs, **pkwargs)
+
+

Same as partial, except you can use arg0 arg1 etc param placeholders

+

bind is the same as partial, but also allows you to reorder positional arguments using variable name(s) arg{i} where i refers to the zero-indexed positional argument. bind as implemented currently only supports reordering of up to the first 5 positional arguments.

+

Consider the function myfunc below, which has 3 positional arguments. These arguments can be referenced as arg0, arg1, and arg1, respectively.

+
+
def myfn(a,b,c,d=1,e=2): return(a,b,c,d,e)
+
+

In the below example we bind the positional arguments of myfn as follows:

+
    +
  • The second input 14, referenced by arg1, is substituted for the first positional argument.
  • +
  • We supply a default value of 17 for the second positional argument.
  • +
  • The first input 19, referenced by arg0, is subsituted for the third positional argument.
  • +
+
+
test_eq(bind(myfn, arg1, 17, arg0, e=3)(19,14), (14,17,19,1,3))
+
+

In this next example:

+
    +
  • We set the default value to 17 for the first positional argument.
  • +
  • The first input 19 refrenced by arg0, becomes the second positional argument.
  • +
  • The second input 14 becomes the third positional argument.
  • +
  • We override the default the value for named argument e to 3.
  • +
+
+
test_eq(bind(myfn, 17, arg0, e=3)(19,14), (17,19,14,1,3))
+
+

This is an example of using bind like partial and do not reorder any arguments:

+
+
test_eq(bind(myfn)(17,19,14), (17,19,14,1,2))
+
+

bind can also be used to change default values. In the below example, we use the first input 3 to override the default value of the named argument e, and supply default values for the first three positional arguments:

+
+
test_eq(bind(myfn, 17,19,14,e=arg0)(3), (17,19,14,1,3))
+
+
+

source

+
+
+

mapt

+
+
 mapt (func, *iterables)
+
+

Tuplified map

+
+
t = [0,1,2,3]
+test_eq(mapt(operator.neg, t), (0,-1,-2,-3))
+
+
+

source

+
+
+

map_ex

+
+
 map_ex (iterable, f, *args, gen=False, **kwargs)
+
+

Like map, but use bind, and supports str and indexing

+
+
test_eq(map_ex(t,operator.neg), [0,-1,-2,-3])
+
+

If f is a string then it is treated as a format string to create the mapping:

+
+
test_eq(map_ex(t, '#{}#'), ['#0#','#1#','#2#','#3#'])
+
+

If f is a dictionary (or anything supporting __getitem__) then it is indexed to create the mapping:

+
+
test_eq(map_ex(t, list('abcd')), list('abcd'))
+
+

You can also pass the same arg params that bind accepts:

+
+
def f(a=None,b=None): return b
+test_eq(map_ex(t, f, b=arg0), range(4))
+
+
+

source

+
+
+

compose

+
+
 compose (*funcs, order=None)
+
+

Create a function that composes all functions in funcs, passing along remaining *args and **kwargs to all

+
+
f1 = lambda o,p=0: (o*2)+p
+f2 = lambda o,p=1: (o+1)/p
+test_eq(f2(f1(3)), compose(f1,f2)(3))
+test_eq(f2(f1(3,p=3),p=3), compose(f1,f2)(3,p=3))
+test_eq(f2(f1(3,  3),  3), compose(f1,f2)(3,  3))
+
+f1.order = 1
+test_eq(f1(f2(3)), compose(f1,f2, order="order")(3))
+
+
+

source

+
+
+

maps

+
+
 maps (*args, retain=<function noop>)
+
+

Like map, except funcs are composed first

+
+
test_eq(maps([1]), [1])
+test_eq(maps(operator.neg, [1,2]), [-1,-2])
+test_eq(maps(operator.neg, operator.neg, [1,2]), [1,2])
+
+
+

source

+
+
+

partialler

+
+
 partialler (f, *args, order=None, **kwargs)
+
+

Like functools.partial but also copies over docstring

+
+
def _f(x,a=1):
+    "test func"
+    return x-a
+_f.order=1
+
+f = partialler(_f, 2)
+test_eq(f.order, 1)
+test_eq(f(3), -1)
+f = partialler(_f, a=2, order=3)
+test_eq(f.__doc__, "test func")
+test_eq(f.order, 3)
+test_eq(f(3), _f(3,2))
+
+
+
class partial0:
+    "Like `partialler`, but args passed to callable are inserted at started, instead of at end"
+    def __init__(self, f, *args, order=None, **kwargs):
+        self.f,self.args,self.kwargs = f,args,kwargs
+        self.order = ifnone(order, getattr(f,'order',None))
+        self.__doc__ = f.__doc__
+
+    def __call__(self, *args, **kwargs): return self.f(*args, *self.args, **kwargs, **self.kwargs)
+
+
+
f = partial0(_f, 2)
+test_eq(f.order, 1)
+test_eq(f(3), 1) # NB: different to `partialler` example
+
+
+

source

+
+
+

instantiate

+
+
 instantiate (t)
+
+

Instantiate t if it’s a type, otherwise do nothing

+
+
test_eq_type(instantiate(int), 0)
+test_eq_type(instantiate(1), 1)
+
+
+

source

+
+
+

using_attr

+
+
 using_attr (f, attr)
+
+

Construct a function which applies f to the argument’s attribute attr

+
+
t = Path('/a/b.txt')
+f = using_attr(str.upper, 'name')
+test_eq(f(t), 'B.TXT')
+
+
+
+

Self (with an uppercase S)

+

A Concise Way To Create Lambdas

+

This is a concise way to create lambdas that are calling methods on an object (note the capitalization!)

+

Self.sum(), for instance, is a shortcut for lambda o: o.sum().

+
+
f = Self.sum()
+x = np.array([3.,1])
+test_eq(f(x), 4.)
+
+# This is equivalent to above
+f = lambda o: o.sum()
+x = np.array([3.,1])
+test_eq(f(x), 4.)
+
+f = Self.argmin()
+arr = np.array([1,2,3,4,5])
+test_eq(f(arr), arr.argmin())
+
+f = Self.sum().is_integer()
+x = np.array([3.,1])
+test_eq(f(x), True)
+
+f = Self.sum().real.is_integer()
+x = np.array([3.,1])
+test_eq(f(x), True)
+
+f = Self.imag()
+test_eq(f(3), 0)
+
+f = Self[1]
+test_eq(f(x), 1)
+
+

Self is also callable, which creates a function which calls any function passed to it, using the arguments passed to Self:

+
+
def f(a, b=3): return a+b+2
+def g(a, b=3): return a*b
+fg = Self(1,b=2)
+list(map(fg, [f,g]))
+
+
[5, 2]
+
+
+
+
+
+

Patching

+
+

source

+
+

copy_func

+
+
 copy_func (f)
+
+

Copy a non-builtin function (NB copy.copy does not work for this)

+

Sometimes it may be desirable to make a copy of a function that doesn’t point to the original object. When you use Python’s built in copy.copy or copy.deepcopy to copy a function, you get a reference to the original object:

+
+
import copy as cp
+
+
+
def foo(): pass
+a = cp.copy(foo)
+b = cp.deepcopy(foo)
+
+a.someattr = 'hello' # since a and b point at the same object, updating a will update b
+test_eq(b.someattr, 'hello')
+
+assert a is foo and b is foo
+
+

However, with copy_func, you can retrieve a copy of a function without a reference to the original object:

+
+
c = copy_func(foo) # c is an indpendent object
+assert c is not foo
+
+
+
def g(x, *, y=3): return x+y
+test_eq(copy_func(g)(4), 7)
+
+
+

source

+
+
+

patch_to

+
+
 patch_to (cls, as_prop=False, cls_method=False)
+
+

Decorator: add f to cls

+

The @patch_to decorator allows you to monkey patch a function into a class as a method:

+
+
class _T3(int): pass  
+
+@patch_to(_T3)
+def func1(self, a): return self+a
+
+t = _T3(1) # we initilized `t` to a type int = 1
+test_eq(t.func1(2), 3) # we add 2 to `t`, so 2 + 1 = 3
+
+

You can access instance properties in the usual way via self:

+
+
class _T4():
+    def __init__(self, g): self.g = g
+        
+@patch_to(_T4)
+def greet(self, x): return self.g + x
+        
+t = _T4('hello ') # this sets self.g = 'helllo '
+test_eq(t.greet('world'), 'hello world') #t.greet('world') will append 'world' to 'hello '
+
+

You can instead specify that the method should be a class method by setting cls_method=True:

+
+
class _T5(int): attr = 3 # attr is a class attribute we will access in a later method
+    
+@patch_to(_T5, cls_method=True)
+def func(cls, x): return cls.attr + x # you can access class attributes in the normal way
+
+test_eq(_T5.func(4), 7)
+
+

Additionally you can specify that the function you want to patch should be a class attribute with as_prop=True:

+
+
@patch_to(_T5, as_prop=True)
+def add_ten(self): return self + 10
+
+t = _T5(4)
+test_eq(t.add_ten, 14)
+
+

Instead of passing one class to the @patch_to decorator, you can pass multiple classes in a tuple to simulteanously patch more than one class with the same method:

+
+
class _T6(int): pass
+class _T7(int): pass
+
+@patch_to((_T6,_T7))
+def func_mult(self, a): return self*a
+
+t = _T6(2)
+test_eq(t.func_mult(4), 8)
+t = _T7(2)
+test_eq(t.func_mult(4), 8)
+
+
+

source

+
+
+

patch

+
+
 patch (f=None, as_prop=False, cls_method=False)
+
+

Decorator: add f to the first parameter’s class (based on f’s type annotations)

+

@patch is an alternative to @patch_to that allows you similarly monkey patch class(es) by using type annotations:

+
+
class _T8(int): pass  
+
+@patch
+def func(self:_T8, a): return self+a
+
+t = _T8(1)  # we initilized `t` to a type int = 1
+test_eq(t.func(3), 4) # we add 3 to `t`, so 3 + 1 = 4
+test_eq(t.func.__qualname__, '_T8.func')
+
+

Similarly to patch_to, you can supply a union of classes instead of a single class in your type annotations to patch multiple classes:

+
+
class _T9(int): pass 
+
+@patch
+def func2(x:_T8|_T9, a): return x*a # will patch both _T8 and _T9
+
+t = _T8(2)
+test_eq(t.func2(4), 8)
+test_eq(t.func2.__qualname__, '_T8.func2')
+
+t = _T9(2)
+test_eq(t.func2(4), 8)
+test_eq(t.func2.__qualname__, '_T9.func2')
+
+

Just like patch_to decorator you can use as_prop and cls_method parameters with patch decorator:

+
+
@patch(as_prop=True)
+def add_ten(self:_T5): return self + 10
+
+t = _T5(4)
+test_eq(t.add_ten, 14)
+
+
+
class _T5(int): attr = 3 # attr is a class attribute we will access in a later method
+    
+@patch(cls_method=True)
+def func(cls:_T5, x): return cls.attr + x # you can access class attributes in the normal way
+
+test_eq(_T5.func(4), 7)
+
+
+

source

+
+
+

patch_property

+
+
 patch_property (f)
+
+

Deprecated; use patch(as_prop=True) instead

+

Patching classmethod shouldn’t affect how python’s inheritance works

+
+
class FastParent: pass
+
+@patch(cls_method=True)
+def type_cls(cls: FastParent): return cls
+
+class FastChild(FastParent): pass
+
+parent = FastParent()
+test_eq(parent.type_cls(), FastParent)
+
+child = FastChild()
+test_eq(child.type_cls(), FastChild)
+
+
+
+
+

Other Helpers

+
+

source

+
+

compile_re

+
+
 compile_re (pat)
+
+

Compile pat if it’s not None

+
+
assert compile_re(None) is None
+assert compile_re('a').match('ab')
+
+
+

source

+
+

ImportEnum

+
+
 ImportEnum (value, names=None, module=None, qualname=None, type=None,
+             start=1)
+
+

An Enum that can have its values imported

+
+
_T = ImportEnum('_T', {'foobar':1, 'goobar':2})
+_T.imports()
+test_eq(foobar, _T.foobar)
+test_eq(goobar, _T.goobar)
+
+
+

source

+
+
+

StrEnum

+
+
 StrEnum (value, names=None, module=None, qualname=None, type=None,
+          start=1)
+
+

An ImportEnum that behaves like a str

+
+

source

+
+
+
+

str_enum

+
+
 str_enum (name, *vals)
+
+

Simplified creation of StrEnum types

+
+

source

+
+

ValEnum

+
+
 ValEnum (value, names=None, module=None, qualname=None, type=None,
+          start=1)
+
+

An ImportEnum that stringifies using values

+
+
_T = str_enum('_T', 'a', 'b')
+test_eq(f'{_T.a}', 'a')
+test_eq(_T.a, 'a')
+test_eq(list(_T.__members__), ['a','b'])
+print(_T.a, _T.a.upper())
+
+
a A
+
+
+
+

source

+
+
+

Stateful

+
+
 Stateful (*args, **kwargs)
+
+

A base class/mixin for objects that should not serialize all their state

+
+
class _T(Stateful):
+    def __init__(self):
+        super().__init__()
+        self.a=1
+        self._state['test']=2
+
+t = _T()
+t2 = pickle.loads(pickle.dumps(t))
+test_eq(t.a,1)
+test_eq(t._state['test'],2)
+test_eq(t2.a,1)
+test_eq(t2._state,{})
+
+

Override _init_state to do any necessary setup steps that are required during __init__ or during deserialization (e.g. pickle.load). Here’s an example of how Stateful simplifies the official Python example for Handling Stateful Objects.

+
+
class TextReader(Stateful):
+    """Print and number lines in a text file."""
+    _stateattrs=('file',)
+    def __init__(self, filename):
+        self.filename,self.lineno = filename,0
+        super().__init__()
+
+    def readline(self):
+        self.lineno += 1
+        line = self.file.readline()
+        if line: return f"{self.lineno}: {line.strip()}"
+
+    def _init_state(self):
+        self.file = open(self.filename)
+        for _ in range(self.lineno): self.file.readline()
+
+
+
reader = TextReader("00_test.ipynb")
+print(reader.readline())
+print(reader.readline())
+
+new_reader = pickle.loads(pickle.dumps(reader))
+print(reader.readline())
+
+
1: {
+2: "cells": [
+3: {
+
+
+
+

source

+
+
+
+

NotStr

+
+
 NotStr (s)
+
+

Behaves like a str, but isn’t an instance of one

+
+
s = NotStr("hello")
+assert not isinstance(s, str)
+test_eq(s, 'hello')
+test_eq(s*2, 'hellohello')
+test_eq(len(s), 5)
+
+
+

source

+
+

PrettyString

+

Little hack to get strings to show properly in Jupyter.

+

Allow strings with special characters to render properly in Jupyter. Without calling print() strings with special characters are displayed like so:

+
+
with_special_chars='a string\nwith\nnew\nlines and\ttabs'
+with_special_chars
+
+
'a string\nwith\nnew\nlines and\ttabs'
+
+
+

We can correct this with PrettyString:

+
+
PrettyString(with_special_chars)
+
+
a string
+with
+new
+lines and   tabs
+
+
+
+

source

+
+
+
+

even_mults

+
+
 even_mults (start, stop, n)
+
+

Build log-stepped array from start to stop in n steps.

+
+
test_eq(even_mults(2,8,3), [2,4,8])
+test_eq(even_mults(2,32,5), [2,4,8,16,32])
+test_eq(even_mults(2,8,1), 8)
+
+
+

source

+
+
+

num_cpus

+
+
 num_cpus ()
+
+

Get number of cpus

+
+
num_cpus()
+
+
8
+
+
+
+

source

+
+
+

add_props

+
+
 add_props (f, g=None, n=2)
+
+

Create properties passing each of range(n) to f

+
+
class _T(): a,b = add_props(lambda i,x:i*2)
+
+t = _T()
+test_eq(t.a,0)
+test_eq(t.b,2)
+
+
+
class _T(): 
+    def __init__(self, v): self.v=v
+    def _set(i, self, v): self.v[i] = v
+    a,b = add_props(lambda i,x: x.v[i], _set)
+
+t = _T([0,2])
+test_eq(t.a,0)
+test_eq(t.b,2)
+t.a = t.a+1
+t.b = 3
+test_eq(t.a,1)
+test_eq(t.b,3)
+
+
+

source

+
+
+

typed

+
+
 typed (f)
+
+

Decorator to check param and return types at runtime

+

typed validates argument types at runtime. This is in contrast to MyPy which only offers static type checking.

+

For example, a TypeError will be raised if we try to pass an integer into the first argument of the below function:

+
+
@typed
+def discount(price:int, pct:float): 
+    return (1-pct) * price
+
+with ExceptionExpected(TypeError): discount(100.0, .1)
+
+

We can also optionally allow multiple types by enumarating the types in a tuple as illustrated below:

+
+
def discount(price:int|float, pct:float): 
+    return (1-pct) * price
+
+assert 90.0 == discount(100.0, .1)
+
+
+
@typed
+def foo(a:int, b:str='a'): return a
+test_eq(foo(1, '2'), 1)
+
+with ExceptionExpected(TypeError): foo(1,2)
+
+@typed
+def foo()->str: return 1
+with ExceptionExpected(TypeError): foo()
+
+@typed
+def foo()->str: return '1'
+assert foo()
+
+

typed works with classes, too:

+
+
class Foo:
+    @typed
+    def __init__(self, a:int, b: int, c:str): pass
+    @typed
+    def test(cls, d:str): return d
+
+with ExceptionExpected(TypeError): Foo(1, 2, 3) 
+with ExceptionExpected(TypeError): Foo(1,2, 'a string').test(10)
+
+
+

source

+
+
+

exec_new

+
+
 exec_new (code)
+
+

Execute code in a new environment and return it

+
+
g = exec_new('a=1')
+test_eq(g['a'], 1)
+
+
+

source

+
+
+

exec_import

+
+
 exec_import (mod, sym)
+
+

Import sym from mod in a new environment

+
+

source

+
+
+

str2bool

+
+
 str2bool (s)
+
+

Case-insensitive convert string s too a bool (y,yes,t,true,on,1->True)

+

True values are ‘y’, ‘yes’, ‘t’, ‘true’, ‘on’, and ‘1’; false values are ‘n’, ‘no’, ‘f’, ‘false’, ‘off’, and ‘0’. Raises ValueError if ‘val’ is anything else.

+
+
for o in "y YES t True on 1".split(): assert str2bool(o)
+for o in "n no FALSE off 0".split(): assert not str2bool(o)
+for o in 0,None,'',False: assert not str2bool(o)
+for o in 1,True: assert str2bool(o)
+
+
+
+
+

Notebook functions

+
+
+

ipython_shell

+
+
 ipython_shell ()
+
+

Same as get_ipython but returns False if not in IPython

+
+
+
+

in_ipython

+
+
 in_ipython ()
+
+

Check if code is running in some kind of IPython environment

+
+
+
+

in_colab

+
+
 in_colab ()
+
+

Check if the code is running in Google Colaboratory

+
+
+
+

in_jupyter

+
+
 in_jupyter ()
+
+

Check if the code is running in a jupyter notebook

+
+
+
+

in_notebook

+
+
 in_notebook ()
+
+

Check if the code is running in a jupyter notebook

+

These variables are available as booleans in fastcore.basics as IN_IPYTHON, IN_JUPYTER, IN_COLAB and IN_NOTEBOOK.

+
+
IN_IPYTHON, IN_JUPYTER, IN_COLAB, IN_NOTEBOOK
+
+
(True, True, False, True)
+
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/dispatch.html b/dispatch.html new file mode 100644 index 00000000..5904e10f --- /dev/null +++ b/dispatch.html @@ -0,0 +1,1266 @@ + + + + + + + + + + +Type dispatch – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Type dispatch

+
+ +
+
+ Basic single and dual parameter dispatch +
+
+ + +
+ + + + +
+ + + +
+ + + +
+
from nbdev.showdoc import *
+from fastcore.test import *
+from fastcore.nb_imports import *
+
+
+

Helpers

+
+

source

+
+

lenient_issubclass

+
+
 lenient_issubclass (cls, types)
+
+

If possible return whether cls is a subclass of types, otherwise return False.

+
+
assert not lenient_issubclass(typing.Collection, list)
+assert lenient_issubclass(list, typing.Collection)
+assert lenient_issubclass(typing.Collection, object)
+assert lenient_issubclass(typing.List, typing.Collection)
+assert not lenient_issubclass(typing.Collection, typing.List)
+assert not lenient_issubclass(object, typing.Callable)
+
+
+

source

+
+
+

sorted_topologically

+
+
 sorted_topologically (iterable, cmp=<built-in function lt>,
+                       reverse=False)
+
+

Return a new list containing all items from the iterable sorted topologically

+
+
td = [3, 1, 2, 5]
+test_eq(sorted_topologically(td), [1, 2, 3, 5])
+test_eq(sorted_topologically(td, reverse=True), [5, 3, 2, 1])
+
+
+
td = {int:1, numbers.Number:2, numbers.Integral:3}
+test_eq(sorted_topologically(td, cmp=lenient_issubclass), [int, numbers.Integral, numbers.Number])
+
+
+
td = [numbers.Integral, tuple, list, int, dict]
+td = sorted_topologically(td, cmp=lenient_issubclass)
+assert td.index(int) < td.index(numbers.Integral)
+
+
+
+
+

TypeDispatch

+

Type dispatch, or Multiple dispatch, allows you to change the way a function behaves based upon the input types it recevies. This is a prominent feature in some programming languages like Julia. For example, this is a conceptual example of how multiple dispatch works in Julia, returning different values depending on the input types of x and y:

+
collide_with(x::Asteroid, y::Asteroid) = ... 
+# deal with asteroid hitting asteroid
+
+collide_with(x::Asteroid, y::Spaceship) = ... 
+# deal with asteroid hitting spaceship
+
+collide_with(x::Spaceship, y::Asteroid) = ... 
+# deal with spaceship hitting asteroid
+
+collide_with(x::Spaceship, y::Spaceship) = ... 
+# deal with spaceship hitting spaceship
+

Type dispatch can be especially useful in data science, where you might allow different input types (i.e. numpy arrays and pandas dataframes) to function that processes data. Type dispatch allows you to have a common API for functions that do similar tasks.

+

The TypeDispatch class allows us to achieve type dispatch in Python. It contains a dictionary that maps types from type annotations to functions, which ensures that the proper function is called when passed inputs.

+
+

source

+
+

TypeDispatch

+
+
 TypeDispatch (funcs=(), bases=())
+
+

Dictionary-like object; __getitem__ matches keys of types using issubclass

+

To demonstrate how TypeDispatch works, we define a set of functions that accept a variety of input types, specified with different type annotations:

+
+
def f2(x:int, y:float): return x+y              #int and float for 2nd arg
+def f_nin(x:numbers.Integral)->int:  return x+1 #integral numeric
+def f_ni2(x:int): return x                      #integer
+def f_bll(x:bool|list): return x              #bool or list
+def f_num(x:numbers.Number): return x           #Number (root of numerics)
+
+

We can optionally initialize TypeDispatch with a list of functions we want to search. Printing an instance of TypeDispatch will display convenient mapping of types -> functions:

+
+
t = TypeDispatch([f_nin,f_ni2,f_num,f_bll,None])
+t
+
+
(bool,object) -> f_bll
+(int,object) -> f_ni2
+(Integral,object) -> f_nin
+(Number,object) -> f_num
+(list,object) -> f_bll
+(object,object) -> NoneType
+
+
+

Note that only the first two arguments are used for TypeDispatch. If your function only contains one argument, the second parameter will be shown as object. If you pass None into TypeDispatch, then this will be displayed as (object, object) -> NoneType.

+

TypeDispatch is a dictionary-like object, which means that you can retrieve a function by the associated type annotation. For example, the statement:

+
t[float]
+

Will return f_num because that is the matching function that has a type annotation that is a super-class of of float - numbers.Number:

+
+
assert issubclass(float, numbers.Number)
+test_eq(t[float], f_num)
+
+

The same is true for other types as well:

+
+
test_eq(t[np.int32], f_nin)
+test_eq(t[bool], f_bll)
+test_eq(t[list], f_bll)
+test_eq(t[np.int32], f_nin)
+
+

If you try to get a type that doesn’t match, TypeDispatch will return None:

+
+
test_eq(t[str], None)
+
+
+

source

+
+
+

TypeDispatch.add

+
+
 TypeDispatch.add (f)
+
+

Add type t and function f

+

This method allows you to add an additional function to an existing TypeDispatch instance :

+
+
def f_col(x:typing.Collection): return x
+t.add(f_col)
+test_eq(t[str], f_col)
+t
+
+
(bool,object) -> f_bll
+(int,object) -> f_ni2
+(Integral,object) -> f_nin
+(Number,object) -> f_num
+(list,object) -> f_bll
+(typing.Collection,object) -> f_col
+(object,object) -> NoneType
+
+
+

If you accidentally add the same function more than once things will still work as expected:

+
+
t.add(f_ni2) 
+test_eq(t[int], f_ni2)
+
+

However, if you add a function that has a type collision that raises an ambiguity, this will automatically resolve to the latest function added:

+
+
def f_ni3(z:int): return z # collides with f_ni2 with same type annotations
+t.add(f_ni3) 
+test_eq(t[int], f_ni3)
+
+
+

Using bases:

+

The argument bases can optionally accept a single instance of TypeDispatch or a collection (i.e. a tuple or list) of TypeDispatch objects. This can provide functionality similar to multiple inheritance.

+

These are searched for matching functions if no match in your list of functions:

+
+
def f_str(x:str): return x+'1'
+
+t = TypeDispatch([f_nin,f_ni2,f_num,f_bll,None])
+t2 = TypeDispatch(f_str, bases=t) # you can optionally supply a list of TypeDispatch objects for `bases`.
+t2
+
+
(str,object) -> f_str
+(bool,object) -> f_bll
+(int,object) -> f_ni2
+(Integral,object) -> f_nin
+(Number,object) -> f_num
+(list,object) -> f_bll
+(object,object) -> NoneType
+
+
+
+
test_eq(t2[int], f_ni2)       # searches `t` b/c not found in `t2`
+test_eq(t2[np.int32], f_nin)  # searches `t` b/c not found in `t2`
+test_eq(t2[float], f_num)     # searches `t` b/c not found in `t2`
+test_eq(t2[bool], f_bll)      # searches `t` b/c not found in `t2`
+test_eq(t2[str], f_str)       # found in `t`!
+test_eq(t2('a'), 'a1')        # found in `t`!, and uses __call__
+
+o = np.int32(1)
+test_eq(t2(o), 2)             # found in `t2` and uses __call__
+
+
+
+

Up To Two Arguments

+

TypeDispatch supports up to two arguments when searching for the appropriate function. The following functions f1 and f2 both have two parameters:

+
+
def f1(x:numbers.Integral, y): return x+1  #Integral is a numeric type
+def f2(x:int, y:float): return x+y
+t = TypeDispatch([f1,f2])
+t
+
+
(int,float) -> f2
+(Integral,object) -> f1
+
+
+

You can lookup functions from a TypeDispatch instance with two parameters like this:

+
+
test_eq(t[np.int32], f1)
+test_eq(t[int,float], f2)
+
+

Keep in mind that anything beyond the first two parameters are ignored, and any collisions will be resolved in favor of the most recent function added. In the below example, f1 is ignored in favor of f2 because the first two parameters have identical type hints:

+
+
def f1(a:str, b:int, c:list): return a
+def f2(a: str, b:int): return b
+t = TypeDispatch([f1,f2])
+test_eq(t[str, int], f2)
+t
+
+
(str,int) -> f2
+
+
+
+
+

Matching

+

Type Dispatch matches types with functions according to whether the supplied class is a subclass or the same class of the type annotation(s) of associated functions.

+

Let’s consider an example where we try to retrieve the function corresponding to types of [np.int32, float].

+

In this scenario, f2 will not be matched. This is because the first type annotation of f2, int, is not a superclass (or the same class) of np.int32:

+
+
def f1(x:numbers.Integral, y): return x+1
+def f2(x:int, y:float): return x+y
+t = TypeDispatch([f1,f2])
+
+assert not issubclass(np.int32, int)
+
+

Instead, f1 is a valid match, as its first argument is annoted with the type numbers.Integeral, which np.int32 is a subclass of:

+
+
assert issubclass(np.int32, numbers.Integral)
+test_eq(t[np.int32,float], f1)
+
+

In f1 , the 2nd parameter y is not annotated, which means TypeDispatch will match anything where the first argument matches int that is not matched with anything else:

+
+
assert issubclass(int, numbers.Integral) # int is a subclass of numbers.Integral
+test_eq(t[int], f1)
+test_eq(t[int,int], f1)
+
+

If no match is possible, None is returned:

+
+
test_eq(t[float,float], None)
+
+
+

source

+
+
+
+

TypeDispatch.__call__

+
+
 TypeDispatch.__call__ (*args, **kwargs)
+
+

Call self as a function.

+

TypeDispatch is also callable. When you call an instance of TypeDispatch, it will execute the relevant function:

+
+
def f_arr(x:np.ndarray): return x.sum()
+def f_int(x:np.int32): return x+1
+t = TypeDispatch([f_arr, f_int])
+
+arr = np.array([5,4,3,2,1])
+test_eq(t(arr), 15) # dispatches to f_arr
+
+o = np.int32(1)
+test_eq(t(o), 2) # dispatches to f_int
+assert t.first() is not None
+
+

You can also call an instance of of TypeDispatch when there are two parameters:

+
+
def f1(x:numbers.Integral, y): return x+1
+def f2(x:int, y:float): return x+y
+t = TypeDispatch([f1,f2])
+
+test_eq(t(3,2.0), 5)
+test_eq(t(3,2), 4)
+
+

When no match is found, a TypeDispatch instance becomes an identity function. This default behavior is leveraged by fasatai for data transformations to provide a sensible default when a matching function cannot be found.

+
+
test_eq(t('a'), 'a')
+
+
+

source

+
+
+

TypeDispatch.returns

+
+
 TypeDispatch.returns (x)
+
+

Get the return type of annotation of x.

+

You can optionally pass an object to TypeDispatch.returns and get the return type annotation back:

+
+
def f1(x:int) -> np.ndarray: return np.array(x)
+def f2(x:str) -> float: return List
+def f3(x:float): return List # f3 has no return type annotation
+
+t = TypeDispatch([f1, f2, f3])
+
+test_eq(t.returns(1), np.ndarray)  # dispatched to f1
+test_eq(t.returns('Hello'), float) # dispatched to f2
+test_eq(t.returns(1.0), None)      # dispatched to f3
+
+class _Test: pass
+_test = _Test()
+test_eq(t.returns(_test), None) # type `_Test` not found, so None returned
+
+
+

Using TypeDispatch With Methods

+

You can use TypeDispatch when defining methods as well:

+
+
def m_nin(self, x:str|numbers.Integral): return str(x)+'1'
+def m_bll(self, x:bool): self.foo='a'
+def m_num(self, x:numbers.Number): return x*2
+
+t = TypeDispatch([m_nin,m_num,m_bll])
+class A: f = t # set class attribute `f` equal to a TypeDispatch instance
+    
+a = A()
+test_eq(a.f(1), '11')  #dispatch to m_nin
+test_eq(a.f(1.), 2.)   #dispatch to m_num
+test_is(a.f.inst, a)
+
+a.f(False) # this triggers t.m_bll to run, which sets self.foo to 'a'
+test_eq(a.foo, 'a')
+
+

As discussed in TypeDispatch.__call__, when there is not a match, TypeDispatch.__call__ becomes an identity function. In the below example, a tuple does not match any type annotations so a tuple is returned:

+
+
test_eq(a.f(()), ())
+
+

We extend the previous example by using bases to add an additional method that supports tuples:

+
+
def m_tup(self, x:tuple): return x+(1,)
+t2 = TypeDispatch(m_tup, bases=t)
+
+class A2: f = t2
+a2 = A2()
+test_eq(a2.f(1), '11')
+test_eq(a2.f(1.), 2.)
+test_is(a2.f.inst, a2)
+a2.f(False)
+test_eq(a2.foo, 'a')
+test_eq(a2.f(()), (1,))
+
+
+
+

Using TypeDispatch With Class Methods

+

You can use TypeDispatch when defining class methods too:

+
+
def m_nin(cls, x:str|numbers.Integral): return str(x)+'1'
+def m_bll(cls, x:bool): cls.foo='a'
+def m_num(cls, x:numbers.Number): return x*2
+
+t = TypeDispatch([m_nin,m_num,m_bll])
+class A: f = t # set class attribute `f` equal to a TypeDispatch
+
+test_eq(A.f(1), '11')  #dispatch to m_nin
+test_eq(A.f(1.), 2.)   #dispatch to m_num
+test_is(A.f.owner, A)
+
+A.f(False) # this triggers t.m_bll to run, which sets A.foo to 'a'
+test_eq(A.foo, 'a')
+
+
+
+
+
+

typedispatch Decorator

+
+

source

+
+

DispatchReg

+
+
 DispatchReg ()
+
+

A global registry for TypeDispatch objects keyed by function name

+
+
@typedispatch
+def f_td_test(x, y): return f'{x}{y}'
+@typedispatch
+def f_td_test(x:numbers.Integral|int, y): return x+1
+@typedispatch
+def f_td_test(x:int, y:float): return x+y
+@typedispatch
+def f_td_test(x:int, y:int): return x*y
+
+test_eq(f_td_test(3,2.0), 5)
+assert issubclass(int, numbers.Integral)
+test_eq(f_td_test(3,2), 6)
+
+test_eq(f_td_test('a','b'), 'ab')
+
+
+

Using typedispatch With other decorators

+

You can use typedispatch with classmethod and staticmethod decorator

+
+
class A:
+    @typedispatch
+    def f_td_test(self, x:numbers.Integral, y): return x+1
+    @typedispatch
+    @classmethod
+    def f_td_test(cls, x:int, y:float): return x+y
+    @typedispatch
+    @staticmethod
+    def f_td_test(x:int, y:int): return x*y
+    
+test_eq(A.f_td_test(3,2), 6)
+test_eq(A.f_td_test(3,2.0), 5)
+test_eq(A().f_td_test(3,'2.0'), 4)
+
+
+
+
+
+

Casting

+

Now that we can dispatch on types, let’s make it easier to cast objects to a different type.

+
+

source

+
+

retain_meta

+
+
 retain_meta (x, res, as_copy=False)
+
+

Call res.set_meta(x), if it exists

+
+

source

+
+
+

default_set_meta

+
+
 default_set_meta (x, as_copy=False)
+
+

Copy over _meta from x to res, if it’s missing

+
+
+
+

(object,object) -> cast

+

Dictionary-like object; __getitem__ matches keys of types using issubclass

+

This works both for plain python classes:…

+
+
mk_class('_T1', 'a')   # mk_class is a fastai utility that constructs a class.
+class _T2(_T1): pass
+
+t = _T1(a=1)
+t2 = cast(t, _T2)        
+assert t2 is t            # t2 refers to the same object as t
+assert isinstance(t, _T2) # t also changed in-place
+assert isinstance(t2, _T2)
+
+test_eq_type(_T2(a=1), t2)
+
+

…as well as for arrays and tensors.

+
+
class _T1(ndarray): pass
+
+t = array([1])
+t2 = cast(t, _T1)
+test_eq(array([1]), t2)
+test_eq(_T1, type(t2))
+
+

To customize casting for other types, define a separate cast function with typedispatch for your type.

+
+

source

+
+
+

retain_type

+
+
 retain_type (new, old=None, typ=None, as_copy=False)
+
+

Cast new to type of old or typ if it’s a superclass

+
+
class _T(tuple): pass
+a = _T((1,2))
+b = tuple((1,2))
+c = retain_type(b, typ=_T)
+test_eq_type(c, a)
+
+

If old has a _meta attribute, its content is passed when casting new to the type of old. In the below example, only the attribute a, but not other_attr is kept, because other_attr is not in _meta:

+
+
class _A():
+    set_meta = default_set_meta
+    def __init__(self, t): self.t=t
+
+class _B1(_A):
+    def __init__(self, t, a=1):
+        super().__init__(t)
+        self._meta = {'a':a}
+        self.other_attr = 'Hello' # will not be kept after casting.
+        
+x = _B1(1, a=2)
+b = _A(1)
+c = retain_type(b, old=x)
+test_eq(c._meta, {'a': 2})
+assert not getattr(c, 'other_attr', None)
+
+
+

source

+
+
+

retain_types

+
+
 retain_types (new, old=None, typs=None)
+
+

Cast each item of new to type of matching item in old if it’s a superclass

+
+
class T(tuple): pass
+
+t1,t2 = retain_types((1,(1,(1,1))), (2,T((2,T((3,4))))))
+test_eq_type(t1, 1)
+test_eq_type(t2, T((1,T((1,1)))))
+
+t1,t2 = retain_types((1,(1,(1,1))), typs = {tuple: [int, {T: [int, {T: [int,int]}]}]})
+test_eq_type(t1, 1)
+test_eq_type(t2, T((1,T((1,1)))))
+
+
+

source

+
+
+

explode_types

+
+
 explode_types (o)
+
+

Return the type of o, potentially in nested dictionaries for thing that are listy

+
+
test_eq(explode_types((2,T((2,T((3,4)))))), {tuple: [int, {T: [int, {T: [int,int]}]}]})
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/docments.html b/docments.html new file mode 100644 index 00000000..780acf49 --- /dev/null +++ b/docments.html @@ -0,0 +1,1036 @@ + + + + + + + + + + +Docments – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Docments

+
+ +
+
+ Document parameters using comments. +
+
+ + +
+ + + + +
+ + + +
+ + + +

docments provides programmatic access to comments in function parameters and return types. It can be used to create more developer-friendly documentation, CLI, etc tools.

+
+

Why?

+

Without docments, if you want to document your parameters, you have to repeat param names in docstrings, since they’re already in the function signature. The parameters have to be kept synchronized in the two places as you change your code. Readers of your code have to look back and forth between two places to understand what’s happening. So it’s more work for you, and for your users.

+

Furthermore, to have parameter documentation formatted nicely without docments, you have to use special magic docstring formatting, often with odd quirks, which is a pain to create and maintain, and awkward to read in code. For instance, using numpy-style documentation:

+
+
def add_np(a:int, b:int=0)->int:
+    """The sum of two numbers.
+    
+    Used to demonstrate numpy-style docstrings.
+
+Parameters
+----------
+a : int
+    the 1st number to add
+b : int
+    the 2nd number to add (default: 0)
+
+Returns
+-------
+int
+    the result of adding `a` to `b`"""
+    return a+b
+
+

By comparison, here’s the same thing using docments:

+
+
def add(
+    a:int, # the 1st number to add
+    b=0,   # the 2nd number to add
+)->int:    # the result of adding `a` to `b`
+    "The sum of two numbers."
+    return a+b
+
+
+
+

Numpy docstring helper functions

+

docments also supports numpy-style docstrings, or a mix or numpy-style and docments parameter documentation. The functions in this section help get and parse this information.

+
+

source

+
+

docstring

+
+
 docstring (sym)
+
+

Get docstring for sym for functions ad classes

+
+
test_eq(docstring(add), "The sum of two numbers.")
+
+
+

source

+
+
+

parse_docstring

+
+
 parse_docstring (sym)
+
+

Parse a numpy-style docstring in sym

+
+
# parse_docstring(add_np)
+
+
+

source

+
+
+

isdataclass

+
+
 isdataclass (s)
+
+

Check if s is a dataclass but not a dataclass’ instance

+
+

source

+
+
+

get_dataclass_source

+
+
 get_dataclass_source (s)
+
+

Get source code for dataclass s

+
+

source

+
+
+

get_source

+
+
 get_source (s)
+
+

Get source code for string, function object or dataclass s

+
+

source

+
+
+

get_name

+
+
 get_name (obj)
+
+

Get the name of obj

+
+
test_eq(get_name(in_ipython), 'in_ipython')
+test_eq(get_name(L.map), 'map')
+
+
+

source

+
+
+

qual_name

+
+
 qual_name (obj)
+
+

Get the qualified name of obj

+
+
assert qual_name(docscrape) == 'fastcore.docscrape'
+
+
+
+
+

Docments

+
+

source

+
+

docments

+
+
 docments (elt, full=False, returns=True, eval_str=False)
+
+

Generates a docment

+

The returned dict has parameter names as keys, docments as values. The return value comment appears in the return, unless returns=False. Using the add definition above, we get:

+
+
def add(
+    a:int, # the 1st number to add
+    b=0,   # the 2nd number to add
+)->int:    # the result of adding `a` to `b`
+    "The sum of two numbers."
+    return a+b
+
+docments(add)
+
+
{ 'a': 'the 1st number to add',
+  'b': 'the 2nd number to add',
+  'return': 'the result of adding `a` to `b`'}
+
+
+

If you pass full=True, the values are dict of defaults, types, and docments as values. Note that the type annotation is inferred from the default value, if the annotation is empty and a default is supplied.

+
+
docments(add, full=True)
+
+
{ 'a': { 'anno': 'int',
+         'default': <class 'inspect._empty'>,
+         'docment': 'the 1st number to add'},
+  'b': { 'anno': <class 'int'>,
+         'default': 0,
+         'docment': 'the 2nd number to add'},
+  'return': { 'anno': 'int',
+              'default': <class 'inspect._empty'>,
+              'docment': 'the result of adding `a` to `b`'}}
+
+
+

To evaluate stringified annotations (from python 3.10), use eval_str:

+
+
docments(add, full=True, eval_str=True)['a']
+
+
{ 'anno': <class 'int'>,
+  'default': <class 'inspect._empty'>,
+  'docment': 'the 1st number to add'}
+
+
+

If you need more space to document a parameter, place one or more lines of comments above the parameter, or above the return type. You can mix-and-match these docment styles:

+
+
def add(
+    # The first operand
+    a:int,
+    # This is the second of the operands to the *addition* operator.
+    # Note that passing a negative value here is the equivalent of the *subtraction* operator.
+    b:int,
+)->int: # The result is calculated using Python's builtin `+` operator.
+    "Add `a` to `b`"
+    return a+b
+
+
+
docments(add)
+
+
{ 'a': 'The first operand',
+  'b': 'This is the second of the operands to the *addition* operator.\n'
+       'Note that passing a negative value here is the equivalent of the '
+       '*subtraction* operator.',
+  'return': "The result is calculated using Python's builtin `+` operator."}
+
+
+

Docments works with async functions, too:

+
+
async def add_async(
+    # The first operand
+    a:int,
+    # This is the second of the operands to the *addition* operator.
+    # Note that passing a negative value here is the equivalent of the *subtraction* operator.
+    b:int,
+)->int: # The result is calculated using Python's builtin `+` operator.
+    "Add `a` to `b`"
+    return a+b
+
+
+
test_eq(docments(add_async), docments(add))
+
+

You can also use docments with classes and methods:

+
+
class Adder:
+    "An addition calculator"
+    def __init__(self,
+        a:int, # First operand
+        b:int, # 2nd operand
+    ): self.a,self.b = a,b
+    
+    def calculate(self
+                 )->int: # Integral result of addition operator
+        "Add `a` to `b`"
+        return a+b
+
+
+
docments(Adder)
+
+
{'a': 'First operand', 'b': '2nd operand', 'return': None}
+
+
+
+
docments(Adder.calculate)
+
+
{'return': 'Integral result of addition operator', 'self': None}
+
+
+

docments can also be extracted from numpy-style docstrings:

+
+
print(add_np.__doc__)
+
+
The sum of two numbers.
+    
+    Used to demonstrate numpy-style docstrings.
+
+Parameters
+----------
+a : int
+    the 1st number to add
+b : int
+    the 2nd number to add (default: 0)
+
+Returns
+-------
+int
+    the result of adding `a` to `b`
+
+
+
+
docments(add_np)
+
+
{ 'a': 'the 1st number to add',
+  'b': 'the 2nd number to add (default: 0)',
+  'return': 'the result of adding `a` to `b`'}
+
+
+

You can even mix and match docments and numpy parameters:

+
+
def add_mixed(a:int, # the first number to add
+              b
+             )->int: # the result
+    """The sum of two numbers.
+
+Parameters
+----------
+b : int
+    the 2nd number to add (default: 0)"""
+    return a+b
+
+
+
docments(add_mixed, full=True)
+
+
{ 'a': { 'anno': 'int',
+         'default': <class 'inspect._empty'>,
+         'docment': 'the first number to add'},
+  'b': { 'anno': 'int',
+         'default': <class 'inspect._empty'>,
+         'docment': 'the 2nd number to add (default: 0)'},
+  'return': { 'anno': 'int',
+              'default': <class 'inspect._empty'>,
+              'docment': 'the result'}}
+
+
+

You can use docments with dataclasses, however if the class was defined in online notebook, docments will not contain parameters’ comments. This is because the source code is not available in the notebook. After converting the notebook to a module, the docments will be available. Thus, documentation will have correct parameters’ comments.

+

Docments even works with delegates:

+
+
from fastcore.meta import delegates
+
+
+
def _a(a:int=2): return a # First
+
+@delegates(_a)
+def _b(b:str, **kwargs): return b, (_a(**kwargs)) # Second
+
+docments(_b)
+
+
{'a': 'First', 'b': 'Second', 'return': None}
+
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/foundation.html b/foundation.html new file mode 100644 index 00000000..8ea75b12 --- /dev/null +++ b/foundation.html @@ -0,0 +1,1522 @@ + + + + + + + + + + +Foundation – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Foundation

+
+ +
+
+ The L class and helpers for it +
+
+ + +
+ + + + +
+ + + +
+ + + +
+

Foundational Functions

+
+

source

+
+

working_directory

+
+
 working_directory (path)
+
+

Change working directory to path and return to previous on exit.

+
+

source

+
+
+

add_docs

+
+
 add_docs (cls, cls_doc=None, **docs)
+
+

Copy values from docs to cls docstrings, and confirm all public methods are documented

+

add_docs allows you to add docstrings to a class and its associated methods. This function allows you to group docstrings together seperate from your code, which enables you to define one-line functions as well as organize your code more succintly. We believe this confers a number of benefits which we discuss in our style guide.

+

Suppose you have the following undocumented class:

+
+
class T:
+    def foo(self): pass
+    def bar(self): pass
+
+

You can add documentation to this class like so:

+
+
add_docs(T, cls_doc="A docstring for the class.",
+            foo="The foo method.",
+            bar="The bar method.")
+
+

Now, docstrings will appear as expected:

+
+
test_eq(T.__doc__, "A docstring for the class.")
+test_eq(T.foo.__doc__, "The foo method.")
+test_eq(T.bar.__doc__, "The bar method.")
+
+

add_docs also validates that all of your public methods contain a docstring. If one of your methods is not documented, it will raise an error:

+
+
class T:
+    def foo(self): pass
+    def bar(self): pass
+
+f=lambda: add_docs(T, "A docstring for the class.", foo="The foo method.")
+test_fail(f, contains="Missing docs")
+
+
+

source

+
+
+

docs

+
+
 docs (cls)
+
+

Decorator version of add_docs, using _docs dict

+

Instead of using add_docs, you can use the decorator docs as shown below. Note that the docstring for the class can be set with the argument cls_doc:

+
+
@docs
+class _T:
+    def f(self): pass
+    def g(cls): pass
+    
+    _docs = dict(cls_doc="The class docstring", 
+                 f="The docstring for method f.",
+                 g="A different docstring for method g.")
+
+    
+test_eq(_T.__doc__, "The class docstring")
+test_eq(_T.f.__doc__, "The docstring for method f.")
+test_eq(_T.g.__doc__, "A different docstring for method g.")
+
+

For either the docs decorator or the add_docs function, you can still define your docstrings in the normal way. Below we set the docstring for the class as usual, but define the method docstrings through the _docs attribute:

+
+
@docs
+class _T:
+    "The class docstring"
+    def f(self): pass
+    _docs = dict(f="The docstring for method f.")
+
+    
+test_eq(_T.__doc__, "The class docstring")
+test_eq(_T.f.__doc__, "The docstring for method f.")
+
+
+
+
+

is_iter

+
+
 is_iter (o)
+
+

Test whether o can be used in a for loop

+
+
assert is_iter([1])
+assert not is_iter(array(1))
+assert is_iter(array([1,2]))
+assert (o for o in range(3))
+
+
+

source

+
+
+

coll_repr

+
+
 coll_repr (c, max_n=10)
+
+

String repr of up to max_n items of (possibly lazy) collection c

+

coll_repr is used to provide a more informative __repr__ about list-like objects. coll_repr and is used by L to build a __repr__ that displays the length of a list in addition to a preview of a list.

+

Below is an example of the __repr__ string created for a list of 1000 elements:

+
+
test_eq(coll_repr(range(1000)),    '(#1000) [0,1,2,3,4,5,6,7,8,9...]')
+test_eq(coll_repr(range(1000), 5), '(#1000) [0,1,2,3,4...]')
+test_eq(coll_repr(range(10),   5),   '(#10) [0,1,2,3,4...]')
+test_eq(coll_repr(range(5),    5),    '(#5) [0,1,2,3,4]')
+
+

We can set the option max_n to optionally preview a specified number of items instead of the default:

+
+
test_eq(coll_repr(range(1000), max_n=5), '(#1000) [0,1,2,3,4...]')
+
+
+

source

+
+
+

is_bool

+
+
 is_bool (x)
+
+

Check whether x is a bool or None

+
+

source

+
+
+

mask2idxs

+
+
 mask2idxs (mask)
+
+

Convert bool mask or index list to index L

+
+
test_eq(mask2idxs([False,True,False,True]), [1,3])
+test_eq(mask2idxs(array([False,True,False,True])), [1,3])
+test_eq(mask2idxs(array([1,2,3])), [1,2,3])
+
+
+

source

+
+
+

cycle

+
+
 cycle (o)
+
+

Like itertools.cycle except creates list of Nones if o is empty

+
+
test_eq(itertools.islice(cycle([1,2,3]),5), [1,2,3,1,2])
+test_eq(itertools.islice(cycle([]),3), [None]*3)
+test_eq(itertools.islice(cycle(None),3), [None]*3)
+test_eq(itertools.islice(cycle(1),3), [1,1,1])
+
+
+

source

+
+
+

zip_cycle

+
+
 zip_cycle (x, *args)
+
+

Like itertools.zip_longest but cycles through elements of all but first argument

+
+
test_eq(zip_cycle([1,2,3,4],list('abc')), [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'a')])
+
+
+

source

+
+
+

is_indexer

+
+
 is_indexer (idx)
+
+

Test whether idx will index a single item in a list

+

You can, for example index a single item in a list with an integer or a 0-dimensional numpy array:

+
+
assert is_indexer(1)
+assert is_indexer(np.array(1))
+
+

However, you cannot index into single item in a list with another list or a numpy array with ndim > 0.

+
+
assert not is_indexer([1, 2])
+assert not is_indexer(np.array([[1, 2], [3, 4]]))
+
+
+
+
+

L helpers

+
+

source

+
+

CollBase

+
+
 CollBase (items)
+
+

Base class for composing a list of items

+

ColBase is a base class that emulates the functionality of a python list:

+
+
class _T(CollBase): pass
+l = _T([1,2,3,4,5])
+
+test_eq(len(l), 5) # __len__
+test_eq(l[-1], 5); test_eq(l[0], 1) #__getitem__
+l[2] = 100; test_eq(l[2], 100)      # __set_item__
+del l[0]; test_eq(len(l), 4)        # __delitem__
+test_eq(str(l), '[2, 100, 4, 5]')   # __repr__
+
+
+

source

+
+
+

L

+
+
 L (x=None, *args, **kwargs)
+
+

Behaves like a list of items but can also index with list of indices or masks

+

L is a drop in replacement for a python list. Inspired by NumPy, L, supports advanced indexing and has additional methods (outlined below) that provide additional functionality and encourage simple expressive code. For example, the code below takes a list of pairs, selects the second item of each pair, takes its absolute value, filters items greater than 4, and adds them up:

+
+
from fastcore.utils import gt
+
+
+
d = dict(a=1,b=-5,d=6,e=9).items()
+test_eq(L(d).itemgot(1).map(abs).filter(gt(4)).sum(), 20) # abs(-5) + abs(6) + abs(9) = 20; 1 was filtered out.
+
+

Read this overview section for a quick tutorial of L, as well as background on the name.

+

You can create an L from an existing iterable (e.g. a list, range, etc) and access or modify it with an int list/tuple index, mask, int, or slice. All list methods can also be used with L.

+
+
t = L(range(12))
+test_eq(t, list(range(12)))
+test_ne(t, list(range(11)))
+t.reverse()
+test_eq(t[0], 11)
+t[3] = "h"
+test_eq(t[3], "h")
+t[3,5] = ("j","k")
+test_eq(t[3,5], ["j","k"])
+test_eq(t, L(t))
+test_eq(L(L(1,2),[3,4]), ([1,2],[3,4]))
+t
+
+
(#12) [11,10,9,'j',7,'k',5,4,3,2...]
+
+
+

Any L is a Sequence so you can use it with methods like random.sample:

+
+
assert isinstance(t, Sequence)
+
+
+
import random
+
+
+
random.seed(0)
+random.sample(t, 3)
+
+
[5, 0, 11]
+
+
+

There are optimized indexers for arrays, tensors, and DataFrames.

+
+
import pandas as pd
+
+
+
arr = np.arange(9).reshape(3,3)
+t = L(arr, use_list=None)
+test_eq(t[1,2], arr[[1,2]])
+
+df = pd.DataFrame({'a':[1,2,3]})
+t = L(df, use_list=None)
+test_eq(t[1,2], L(pd.DataFrame({'a':[2,3]}, index=[1,2]), use_list=None))
+
+

You can also modify an L with append, +, and *.

+
+
t = L()
+test_eq(t, [])
+t.append(1)
+test_eq(t, [1])
+t += [3,2]
+test_eq(t, [1,3,2])
+t = t + [4]
+test_eq(t, [1,3,2,4])
+t = 5 + t
+test_eq(t, [5,1,3,2,4])
+test_eq(L(1,2,3), [1,2,3])
+test_eq(L(1,2,3), L(1,2,3))
+t = L(1)*5
+t = t.map(operator.neg)
+test_eq(t,[-1]*5)
+test_eq(~L([True,False,False]), L([False,True,True]))
+t = L(range(4))
+test_eq(zip(t, L(1).cycle()), zip(range(4),(1,1,1,1)))
+t = L.range(100)
+test_shuffled(t,t.shuffle())
+
+
+
test_eq(L([]).sum(), 0)
+test_eq(L([]).product(), 1)
+
+
+
def _f(x,a=0): return x+a
+t = L(1)*5
+test_eq(t.map(_f), t)
+test_eq(t.map(_f,1), [2]*5)
+test_eq(t.map(_f,a=2), [3]*5)
+
+

An L can be constructed from anything iterable, although tensors and arrays will not be iterated over on construction, unless you pass use_list to the constructor.

+
+
test_eq(L([1,2,3]),[1,2,3])
+test_eq(L(L([1,2,3])),[1,2,3])
+test_ne(L([1,2,3]),[1,2,])
+test_eq(L('abc'),['abc'])
+test_eq(L(range(0,3)),[0,1,2])
+test_eq(L(o for o in range(0,3)),[0,1,2])
+test_eq(L(array(0)),[array(0)])
+test_eq(L([array(0),array(1)]),[array(0),array(1)])
+test_eq(L(array([0.,1.1]))[0],array([0.,1.1]))
+test_eq(L(array([0.,1.1]), use_list=True), [array(0.),array(1.1)])  # `use_list=True` to unwrap arrays/arrays
+
+

If match is not None then the created list is same len as match, either by:

+
    +
  • If len(items)==1 then items is replicated,
  • +
  • Otherwise an error is raised if match and items are not already the same size.
  • +
+
+
test_eq(L(1,match=[1,2,3]),[1,1,1])
+test_eq(L([1,2],match=[2,3]),[1,2])
+test_fail(lambda: L([1,2],match=[1,2,3]))
+
+

If you create an L from an existing L then you’ll get back the original object (since L uses the NewChkMeta metaclass).

+
+
test_is(L(t), t)
+
+

An L is considred equal to a list if they have the same elements. It’s never considered equal to a str a set or a dict even if they have the same elements/keys.

+
+
test_eq(L(['a', 'b']), ['a', 'b'])
+test_ne(L(['a', 'b']), 'ab')
+test_ne(L(['a', 'b']), {'a':1, 'b':2})
+
+
+
+

L Methods

+
+

source

+
+
+

L.__getitem__

+
+
 L.__getitem__ (idx)
+
+

Retrieve idx (can be list of indices, or mask, or int) items

+
+
t = L(range(12))
+test_eq(t[1,2], [1,2])                # implicit tuple
+test_eq(t[[1,2]], [1,2])              # list
+test_eq(t[:3], [0,1,2])               # slice
+test_eq(t[[False]*11 + [True]], [11]) # mask
+test_eq(t[array(3)], 3)
+
+
+

source

+
+
+

L.__setitem__

+
+
 L.__setitem__ (idx, o)
+
+

Set idx (can be list of indices, or mask, or int) items to o (which is broadcast if not iterable)

+
+
t[4,6] = 0
+test_eq(t[4,6], [0,0])
+t[4,6] = [1,2]
+test_eq(t[4,6], [1,2])
+
+
+

source

+
+
+

L.unique

+
+
 L.unique (sort=False, bidir=False, start=None)
+
+

Unique items, in stable order

+
+
test_eq(L(4,1,2,3,4,4).unique(), [4,1,2,3])
+
+
+

source

+
+
+

L.val2idx

+
+
 L.val2idx ()
+
+

Dict from value to index

+
+
test_eq(L(1,2,3).val2idx(), {3:2,1:0,2:1})
+
+
+

source

+
+
+

L.filter

+
+
 L.filter (f=<function noop>, negate=False, **kwargs)
+
+

Create new L filtered by predicate f, passing args and kwargs to f

+
+
list(t)
+
+
[0, 1, 2, 3, 1, 5, 2, 7, 8, 9, 10, 11]
+
+
+
+
test_eq(t.filter(lambda o:o<5), [0,1,2,3,1,2])
+test_eq(t.filter(lambda o:o<5, negate=True), [5,7,8,9,10,11])
+
+
+

source

+
+
+

L.argwhere

+
+
 L.argwhere (f, negate=False, **kwargs)
+
+

Like filter, but return indices for matching items

+
+
test_eq(t.argwhere(lambda o:o<5), [0,1,2,3,4,6])
+
+
+

source

+
+
+

L.argfirst

+
+
 L.argfirst (f, negate=False)
+
+

Return index of first matching item

+
+
test_eq(t.argfirst(lambda o:o>4), 5)
+test_eq(t.argfirst(lambda o:o>4,negate=True),0)
+
+
+

source

+
+
+

L.map

+
+
 L.map (f, *args, **kwargs)
+
+

Create new L with f applied to all items, passing args and kwargs to f

+
+
test_eq(L.range(4).map(operator.neg), [0,-1,-2,-3])
+
+

If f is a string then it is treated as a format string to create the mapping:

+
+
test_eq(L.range(4).map('#{}#'), ['#0#','#1#','#2#','#3#'])
+
+

If f is a dictionary (or anything supporting __getitem__) then it is indexed to create the mapping:

+
+
test_eq(L.range(4).map(list('abcd')), list('abcd'))
+
+

You can also pass the same arg params that bind accepts:

+
+
def f(a=None,b=None): return b
+test_eq(L.range(4).map(f, b=arg0), range(4))
+
+
+

source

+
+
+

L.map_dict

+
+
 L.map_dict (f=<function noop>, *args, **kwargs)
+
+

Like map, but creates a dict from items to function results

+
+
test_eq(L(range(1,5)).map_dict(), {1:1, 2:2, 3:3, 4:4})
+test_eq(L(range(1,5)).map_dict(operator.neg), {1:-1, 2:-2, 3:-3, 4:-4})
+
+
+

source

+
+
+

L.zip

+
+
 L.zip (cycled=False)
+
+

Create new L with zip(*items)

+
+
t = L([[1,2,3],'abc'])
+test_eq(t.zip(), [(1, 'a'),(2, 'b'),(3, 'c')])
+
+
+
t = L([[1,2,3,4],['a','b','c']])
+test_eq(t.zip(cycled=True ), [(1, 'a'),(2, 'b'),(3, 'c'),(4, 'a')])
+test_eq(t.zip(cycled=False), [(1, 'a'),(2, 'b'),(3, 'c')])
+
+
+

source

+
+
+

L.map_zip

+
+
 L.map_zip (f, *args, cycled=False, **kwargs)
+
+

Combine zip and starmap

+
+
t = L([1,2,3],[2,3,4])
+test_eq(t.map_zip(operator.mul), [2,6,12])
+
+
+

source

+
+
+

L.zipwith

+
+
 L.zipwith (*rest, cycled=False)
+
+

Create new L with self zip with each of *rest

+
+
b = [[0],[1],[2,2]]
+t = L([1,2,3]).zipwith(b)
+test_eq(t, [(1,[0]), (2,[1]), (3,[2,2])])
+
+
+

source

+
+
+

L.map_zipwith

+
+
 L.map_zipwith (f, *rest, cycled=False, **kwargs)
+
+

Combine zipwith and starmap

+
+
test_eq(L(1,2,3).map_zipwith(operator.mul, [2,3,4]), [2,6,12])
+
+
+

source

+
+
+

L.itemgot

+
+
 L.itemgot (*idxs)
+
+

Create new L with item idx of all items

+
+
test_eq(t.itemgot(1), b)
+
+
+

source

+
+
+

L.attrgot

+
+
 L.attrgot (k, default=None)
+
+

Create new L with attr k (or value k for dicts) of all items.

+
+
# Example when items are not a dict
+a = [SimpleNamespace(a=3,b=4),SimpleNamespace(a=1,b=2)]
+test_eq(L(a).attrgot('b'), [4,2])
+
+#Example of when items are a dict
+b =[{'id': 15, 'name': 'nbdev'}, {'id': 17, 'name': 'fastcore'}]
+test_eq(L(b).attrgot('id'), [15, 17])
+
+
+

source

+
+
+

L.sorted

+
+
 L.sorted (key=None, reverse=False)
+
+

New L sorted by key. If key is str use attrgetter; if int use itemgetter

+
+
test_eq(L(a).sorted('a').attrgot('b'), [2,4])
+
+
+

source

+
+
+

L.split

+
+
 L.split (s, sep=None, maxsplit=-1)
+
+

Class Method: Same as str.split, but returns an L

+
+
test_eq(L.split('a b c'), list('abc'))
+
+
+

source

+
+
+

L.range

+
+
 L.range (a, b=None, step=None)
+
+

Class Method: Same as range, but returns L. Can pass collection for a, to use len(a)

+
+
test_eq_type(L.range([1,1,1]), L(range(3)))
+test_eq_type(L.range(5,2,2), L(range(5,2,2)))
+
+
+

source

+
+
+

L.concat

+
+
 L.concat ()
+
+

Concatenate all elements of list

+
+
test_eq(L([0,1,2,3],4,L(5,6)).concat(), range(7))
+
+
+

source

+
+
+

L.copy

+
+
 L.copy ()
+
+

Same as list.copy, but returns an L

+
+
t = L([0,1,2,3],4,L(5,6)).copy()
+test_eq(t.concat(), range(7))
+
+
+

source

+
+
+

L.map_first

+
+
 L.map_first (f=<function noop>, g=<function noop>, *args, **kwargs)
+
+

First element of map_filter

+
+
t = L(0,1,2,3)
+test_eq(t.map_first(lambda o:o*2 if o>2 else None), 6)
+
+
+

source

+
+
+

L.setattrs

+
+
 L.setattrs (attr, val)
+
+

Call setattr on all items

+
+
t = L(SimpleNamespace(),SimpleNamespace())
+t.setattrs('foo', 'bar')
+test_eq(t.attrgot('foo'), ['bar','bar'])
+
+
+
+
+

Config

+
+

source

+
+

save_config_file

+
+
 save_config_file (file, d, **kwargs)
+
+

Write settings dict to a new config file, or overwrite the existing one.

+
+

source

+
+
+

read_config_file

+
+
 read_config_file (file, **kwargs)
+
+

Config files are saved and read using Python’s configparser.ConfigParser, inside the DEFAULT section.

+
+
_d = dict(user='fastai', lib_name='fastcore', some_path='test', some_bool=True, some_num=3)
+try:
+    save_config_file('tmp.ini', _d)
+    res = read_config_file('tmp.ini')
+finally: os.unlink('tmp.ini')
+dict(res)
+
+
{'user': 'fastai',
+ 'lib_name': 'fastcore',
+ 'some_path': 'test',
+ 'some_bool': 'True',
+ 'some_num': '3'}
+
+
+
+

source

+
+
+

Config

+
+
 Config (cfg_path, cfg_name, create=None, save=True, extra_files=None,
+         types=None)
+
+

Reading and writing ConfigParser ini files

+

Config is a convenient wrapper around ConfigParser ini files with a single section (DEFAULT).

+

Instantiate a Config from an ini file at cfg_path/cfg_name:

+
+
save_config_file('../tmp.ini', _d)
+try: cfg = Config('..', 'tmp.ini')
+finally: os.unlink('../tmp.ini')
+cfg
+
+
{'user': 'fastai', 'lib_name': 'fastcore', 'some_path': 'test', 'some_bool': 'True', 'some_num': '3'}
+
+
+

You can create a new file if one doesn’t exist by providing a create dict:

+
+
try: cfg = Config('..', 'tmp.ini', create=_d)
+finally: os.unlink('../tmp.ini')
+cfg
+
+
{'user': 'fastai', 'lib_name': 'fastcore', 'some_path': 'test', 'some_bool': 'True', 'some_num': '3'}
+
+
+

If you additionally pass save=False, the Config will contain the items from create without writing a new file:

+
+
cfg = Config('..', 'tmp.ini', create=_d, save=False)
+test_eq(cfg.user,'fastai')
+assert not Path('../tmp.ini').exists()
+
+

Keys can be accessed as attributes, items, or with get and an optional default:

+
+
test_eq(cfg.user,'fastai')
+test_eq(cfg['some_path'], 'test')
+test_eq(cfg.get('foo','bar'),'bar')
+
+

Extra files can be read before cfg_path/cfg_name using extra_files, in the order they appear:

+
+
with tempfile.TemporaryDirectory() as d:
+    a = Config(d, 'a.ini', {'a':0,'b':0})
+    b = Config(d, 'b.ini', {'a':1,'c':0})
+    c = Config(d, 'c.ini', {'a':2,'d':0}, extra_files=[a.config_file,b.config_file])
+    test_eq(c.d, {'a':'2','b':'0','c':'0','d':'0'})
+
+

If you pass a dict types, then the values of that dict will be used as types to instantiate all values returned. Path is a special case – in that case, the path returned will be relative to the path containing the config file (assuming the value is relative). bool types use str2bool to convert to boolean.

+
+
_types = dict(some_path=Path, some_bool=bool, some_num=int)
+cfg = Config('..', 'tmp.ini', create=_d, save=False, types=_types)
+
+test_eq(cfg.user,'fastai')
+test_eq(cfg['some_path'].resolve(), (Path('..')/'test').resolve())
+test_eq(cfg.get('some_num'), 3)
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/images/att_00000.png b/images/att_00000.png new file mode 100644 index 00000000..7d44d3f4 Binary files /dev/null and b/images/att_00000.png differ diff --git a/images/att_00005.png b/images/att_00005.png new file mode 100644 index 00000000..de857c98 Binary files /dev/null and b/images/att_00005.png differ diff --git a/images/att_00006.png b/images/att_00006.png new file mode 100644 index 00000000..eaa1d257 Binary files /dev/null and b/images/att_00006.png differ diff --git a/images/att_00007.png b/images/att_00007.png new file mode 100644 index 00000000..b21a11b0 Binary files /dev/null and b/images/att_00007.png differ diff --git a/index.html b/index.html new file mode 100644 index 00000000..c09d5612 --- /dev/null +++ b/index.html @@ -0,0 +1,712 @@ + + + + + + + + + + +Welcome to fastcore – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Welcome to fastcore

+
+ +
+
+ Python goodies to make your coding faster, easier, and more maintainable +
+
+ + +
+ + + + +
+ + + +
+ + + +

Python is a powerful, dynamic language. Rather than bake everything into the language, it lets the programmer customize it to make it work for them. fastcore uses this flexibility to add to Python features inspired by other languages we’ve loved, like multiple dispatch from Julia, mixins from Ruby, and currying, binding, and more from Haskell. It also adds some “missing features” and clean up some rough edges in the Python standard library, such as simplifying parallel processing, and bringing ideas from NumPy over to Python’s list type.

+
+

Getting started

+

To install fastcore run: conda install fastcore -c fastai (if you use Anaconda, which we recommend) or pip install fastcore. For an editable install, clone this repo and run: pip install -e ".[dev]". fastcore is tested to work on Ubuntu, macOS and Windows (versions tested are those shown with the -latest suffix here).

+

fastcore contains many features, including:

+
    +
  • fastcore.test: Simple testing functions
  • +
  • fastcore.foundation: Mixins, delegation, composition, and more
  • +
  • fastcore.xtras: Utility functions to help with functional-style programming, parallel processing, and more
  • +
  • fastcore.dispatch: Multiple dispatch methods
  • +
  • fastcore.transform: Pipelines of composed partially reversible transformations
  • +
+

To get started, we recommend you read through the fastcore tour.

+
+
+

Contributing

+

After you clone this repository, please run nbdev_install_hooks in your terminal. This sets up git hooks, which clean up the notebooks to remove the extraneous stuff stored in the notebooks (e.g. which cells you ran) which causes unnecessary merge conflicts.

+

To run the tests in parallel, launch nbdev_test.

+

Before submitting a PR, check that the local library and notebooks match.

+
    +
  • If you made a change to the notebooks in one of the exported cells, you can export it to the library with nbdev_prepare.
  • +
  • If you made a change to the library, you can export it back to the notebooks with nbdev_update.
  • +
+ + +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/meta.html b/meta.html new file mode 100644 index 00000000..4c054ef2 --- /dev/null +++ b/meta.html @@ -0,0 +1,1292 @@ + + + + + + + + + + +Meta – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Meta

+
+ +
+
+ Metaclasses +
+
+ + +
+ + + + +
+ + + +
+ + + +
+
from fastcore.foundation import *
+from nbdev.showdoc import *
+from fastcore.nb_imports import *
+
+

See this blog post for more information about metaclasses.

+ +
+

source

+
+

test_sig

+
+
 test_sig (f, b)
+
+

Test the signature of an object

+
+
def func_1(h,i,j): pass
+def func_2(h,i=3, j=[5,6]): pass
+
+class T:
+    def __init__(self, a, b): pass
+
+test_sig(func_1, '(h, i, j)')
+test_sig(func_2, '(h, i=3, j=[5, 6])')
+test_sig(T, '(a, b)')
+
+
+

source

+
+
+

FixSigMeta

+
+
 FixSigMeta (name, bases, dict)
+
+

A metaclass that fixes the signature on classes that override __new__

+

When you inherit from a class that defines __new__, or a metaclass that defines __call__, the signature of your __init__ method is obfuscated such that tab completion no longer works. FixSigMeta fixes this issue and restores signatures.

+

To understand what FixSigMeta does, it is useful to inspect an object’s signature. You can inspect the signature of an object with inspect.signature:

+
+
class T:
+    def __init__(self, a, b, c): pass
+    
+inspect.signature(T)
+
+
<Signature (a, b, c)>
+
+
+

This corresponds to tab completion working in the normal way:

+

Tab completion in a Jupyter Notebook.

+

However, when you inherhit from a class that defines __new__ or a metaclass that defines __call__ this obfuscates the signature by overriding your class with the signature of __new__, which prevents tab completion from displaying useful information:

+
+
class Foo:
+    def __new__(self, **args): pass
+
+class Bar(Foo):
+    def __init__(self, d, e, f): pass
+    
+inspect.signature(Bar)
+
+
<Signature (d, e, f)>
+
+
+

Tab completion in a Jupyter Notebook.

+

Finally, the signature and tab completion can be restored by inheriting from the metaclass FixSigMeta as shown below:

+
+
class Bar(Foo, metaclass=FixSigMeta):
+    def __init__(self, d, e, f): pass
+    
+test_sig(Bar, '(d, e, f)')
+inspect.signature(Bar)
+
+
<Signature (d, e, f)>
+
+
+

Tab completion in a Jupyter Notebook.

+

If you need to define a metaclass that overrides __call__ (as done in PrePostInitMeta), you need to inherit from FixSigMeta instead of type when constructing the metaclass to preserve the signature in __init__. Be careful not to override __new__ when doing this:

+
+
class TestMeta(FixSigMeta):
+    # __new__ comes from FixSigMeta
+    def __call__(cls, *args, **kwargs): pass
+    
+class T(metaclass=TestMeta):
+    def __init__(self, a, b): pass
+    
+test_sig(T, '(a, b)')
+
+

On the other hand, if you fail to inherit from FixSigMeta when inheriting from a metaclass that overrides __call__, your signature will reflect that of __call__ instead (which is often undesirable):

+
+
class GenericMeta(type):
+    "A boilerplate metaclass that doesn't do anything for testing."
+    def __new__(cls, name, bases, dict):
+        return super().__new__(cls, name, bases, dict)
+    def __call__(cls, *args, **kwargs): pass
+
+class T2(metaclass=GenericMeta):
+    def __init__(self, a, b): pass
+
+# We can avoid this by inheriting from the metaclass `FixSigMeta`
+test_sig(T2, '(*args, **kwargs)')
+
+
+

source

+
+
+

PrePostInitMeta

+
+
 PrePostInitMeta (name, bases, dict)
+
+

A metaclass that calls optional __pre_init__ and __post_init__ methods

+

__pre_init__ and __post_init__ are useful for initializing variables or performing tasks prior to or after __init__ being called, respectively. Fore example:

+
+
class _T(metaclass=PrePostInitMeta):
+    def __pre_init__(self):  self.a  = 0; 
+    def __init__(self,b=0):  self.b = self.a + 1; assert self.b==1
+    def __post_init__(self): self.c = self.b + 2; assert self.c==3
+
+t = _T()
+test_eq(t.a, 0) # set with __pre_init__
+test_eq(t.b, 1) # set with __init__
+test_eq(t.c, 3) # set with __post_init__
+
+

One use for PrePostInitMeta is avoiding the __super__().__init__() boilerplate associated with subclassing, such as used in AutoInit.

+
+

source

+
+
+

AutoInit

+
+
 AutoInit (*args, **kwargs)
+
+

Same as object, but no need for subclasses to call super().__init__

+

This is normally used as a mixin, eg:

+
+
class TestParent():
+    def __init__(self): self.h = 10
+        
+class TestChild(AutoInit, TestParent):
+    def __init__(self): self.k = self.h + 2
+    
+t = TestChild()
+test_eq(t.h, 10) # h=10 is initialized in the parent class
+test_eq(t.k, 12)
+
+
+

source

+
+
+

NewChkMeta

+
+
 NewChkMeta (name, bases, dict)
+
+

Metaclass to avoid recreating object passed to constructor

+

NewChkMeta is used when an object of the same type is the first argument to your class’s constructor (i.e. the __init__ function), and you would rather it not create a new object but point to the same exact object.

+

This is used in L, for example, to avoid creating a new object when the object is already of type L. This allows the users to defenisvely instantiate an L object and just return a reference to the same object if it already happens to be of type L.

+

For example, the below class _T optionally accepts an object o as its first argument. A new object is returned upon instantiation per usual:

+
+
class _T():
+    "Testing"
+    def __init__(self, o): 
+        # if `o` is not an object without an attribute `foo`, set foo = 1
+        self.foo = getattr(o,'foo',1)
+
+
+
t = _T(3)
+test_eq(t.foo,1) # 1 was not of type _T, so foo = 1
+
+t2 = _T(t) #t1 is of type _T
+assert t is not t2 # t1 and t2 are different objects
+
+

However, if we want _T to return a reference to the same object when passed an an object of type _T we can inherit from the NewChkMeta class as illustrated below:

+
+
class _T(metaclass=NewChkMeta):
+    "Testing with metaclass NewChkMeta"
+    def __init__(self, o=None, b=1):
+        # if `o` is not an object without an attribute `foo`, set foo = 1
+        self.foo = getattr(o,'foo',1)
+        self.b = b
+
+

We can now test t and t2 are now pointing at the same object when using this new definition of _T:

+
+
t = _T(3)
+test_eq(t.foo,1) # 1 was not of type _T, so foo = 1
+
+t2 = _T(t) # t2 will now reference t
+
+test_is(t, t2) # t and t2 are the same object
+t2.foo = 5 # this will also change t.foo to 5 because it is the same object
+test_eq(t.foo, 5)
+test_eq(t2.foo, 5)
+
+

However, there is one exception to how NewChkMeta works. If you pass any additional arguments in the constructor a new object is returned, even if the first object is of the same type. For example, consider the below example where we pass the additional argument b into the constructor:

+
+
t3 = _T(t, b=1)
+assert t3 is not t
+
+t4 = _T(t) # without any arguments the constructor will return a reference to the same object
+assert t4 is t
+
+

Finally, it should be noted that NewChkMeta as well as all other metaclases in this section, inherit from FixSigMeta. This means class signatures will always be preserved when inheriting from this metaclass (see docs for FixSigMeta for more details):

+
+
test_sig(_T, '(o=None, b=1)')
+
+
+

source

+
+
+

BypassNewMeta

+
+
 BypassNewMeta (name, bases, dict)
+
+

Metaclass: casts x to this class if it’s of type cls._bypass_type

+

BypassNewMeta is identical to NewChkMeta, except for checking for a class as the same type, we instead check for a class of type specified in attribute _bypass_type.

+

In NewChkMeta, objects of the same type passed to the constructor (without arguments) would result into a new variable referencing the same object. However, with BypassNewMeta this only occurs if the type matches the _bypass_type of the class you are defining:

+
+
class _TestA: pass
+class _TestB: pass
+
+class _T(_TestA, metaclass=BypassNewMeta):
+    _bypass_type=_TestB
+    def __init__(self,x): self.x=x
+
+

In the below example, t does not refer to t2 because t is of type _TestA while _T._bypass_type is of type TestB:

+
+
t = _TestA()
+t2 = _T(t)
+assert t is not t2
+
+

However, if t is set to _TestB to match _T._bypass_type, then both t and t2 will refer to the same object.

+
+
t = _TestB()
+t2 = _T(t)
+t2.new_attr = 15
+
+test_is(t, t2)
+# since t2 just references t these will be the same
+test_eq(t.new_attr, t2.new_attr)
+
+# likewise, chaning an attribute on t will also affect t2 because they both point to the same object.
+t.new_attr = 9
+test_eq(t2.new_attr, 9)
+
+
+
+

Metaprogramming

+
+

source

+
+

empty2none

+
+
 empty2none (p)
+
+

Replace Parameter.empty with None

+
+

source

+
+
+

anno_dict

+
+
 anno_dict (f)
+
+

__annotation__ dictionary withemptycast toNone`, returning empty if doesn’t exist

+
+
def _f(a:int, b:L)->str: ...
+test_eq(anno_dict(_f), {'a': int, 'b': L, 'return': str})
+
+
+

source

+
+
+

use_kwargs_dict

+
+
 use_kwargs_dict (keep=False, **kwargs)
+
+

Decorator: replace **kwargs in signature with names params

+

Replace all **kwargs with named arguments like so:

+
+
@use_kwargs_dict(y=1,z=None)
+def foo(a, b=1, **kwargs): pass
+
+test_sig(foo, '(a, b=1, *, y=1, z=None)')
+
+

Add named arguments, but optionally keep **kwargs by setting keep=True:

+
+
@use_kwargs_dict(y=1,z=None, keep=True)
+def foo(a, b=1, **kwargs): pass
+
+test_sig(foo, '(a, b=1, *, y=1, z=None, **kwargs)')
+
+
+

source

+
+
+

use_kwargs

+
+
 use_kwargs (names, keep=False)
+
+

Decorator: replace **kwargs in signature with names params

+

use_kwargs is different than use_kwargs_dict as it only replaces **kwargs with named parameters without any default values:

+
+
@use_kwargs(['y', 'z'])
+def foo(a, b=1, **kwargs): pass
+
+test_sig(foo, '(a, b=1, *, y=None, z=None)')
+
+

You may optionally keep the **kwargs argument in your signature by setting keep=True:

+
+
@use_kwargs(['y', 'z'], keep=True)
+def foo(a, *args, b=1, **kwargs): pass
+test_sig(foo, '(a, *args, b=1, y=None, z=None, **kwargs)')
+
+
+

source

+
+
+

delegates

+
+
 delegates (to:function=None, keep=False, but:list=None)
+
+

Decorator: replace **kwargs in signature with params from to

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
tofunctionNoneDelegatee
keepboolFalseKeep kwargs in decorated function?
butlistNoneExclude these parameters from signature
+

A common Python idiom is to accept **kwargs in addition to named parameters that are passed onto other function calls. It is especially common to use **kwargs when you want to give the user an option to override default parameters of any functions or methods being called by the parent function.

+

For example, suppose we have have a function foo that passes arguments to baz like so:

+
+
def baz(a, b:int=2, c:int=3): return a + b + c
+
+def foo(c, a, **kwargs):
+    return c + baz(a, **kwargs)
+
+assert foo(c=1, a=1) == 7
+
+

The problem with this approach is the api for foo is obfuscated. Users cannot introspect what the valid arguments for **kwargs are without reading the source code. When a user tries tries to introspect the signature of foo, they are presented with this:

+
+
inspect.signature(foo)
+
+
<Signature (c, a, **kwargs)>
+
+
+

We can address this issue by using the decorator delegates to include parameters from other functions. For example, if we apply the delegates decorator to foo to include parameters from baz:

+
+
@delegates(baz)
+def foo(c, a, **kwargs):
+    return c + baz(a, **kwargs)
+
+test_sig(foo, '(c, a, *, b: int = 2)')
+inspect.signature(foo)
+
+
<Signature (c, a, *, b: int = 2)>
+
+
+

We can optionally decide to keep **kwargs by setting keep=True:

+
+
@delegates(baz, keep=True)
+def foo(c, a, **kwargs):
+    return c + baz(a, **kwargs)
+
+inspect.signature(foo)
+
+
<Signature (c, a, *, b: int = 2, **kwargs)>
+
+
+

It is important to note that only parameters with default parameters are included. For example, in the below scenario only c, but NOT e and d are included in the signature of foo after applying delegates:

+
+
def basefoo(e, d, c=2): pass
+
+@delegates(basefoo)
+def foo(a, b=1, **kwargs): pass
+inspect.signature(foo) # e and d are not included b/c they don't have default parameters.
+
+
<Signature (a, b=1, *, c=2)>
+
+
+

The reason that required arguments (i.e. those without default parameters) are automatically excluded is that you should be explicitly implementing required arguments into your function’s signature rather than relying on delegates.

+

Additionally, you can exclude specific parameters from being included in the signature with the but parameter. In the example below, we exclude the parameter d:

+
+
def basefoo(e, c=2, d=3): pass
+
+@delegates(basefoo, but= ['d'])
+def foo(a, b=1, **kwargs): pass
+
+test_sig(foo, '(a, b=1, *, c=2)')
+inspect.signature(foo)
+
+
<Signature (a, b=1, *, c=2)>
+
+
+

You can also use delegates between methods in a class. Here is an example of delegates with class methods:

+
+
# example 1: class methods
+class _T():
+    @classmethod
+    def foo(cls, a=1, b=2):
+        pass
+    
+    @classmethod
+    @delegates(foo)
+    def bar(cls, c=3, **kwargs):
+        pass
+
+test_sig(_T.bar, '(c=3, *, a=1, b=2)')
+
+

Here is the same example with instance methods:

+
+
# example 2: instance methods
+class _T():
+    def foo(self, a=1, b=2):
+        pass
+    
+    @delegates(foo)
+    def bar(self, c=3, **kwargs):
+        pass
+
+t = _T()
+test_sig(t.bar, '(c=3, *, a=1, b=2)')
+
+

You can also delegate between classes. By default, the delegates decorator will delegate to the superclass:

+
+
class BaseFoo:
+    def __init__(self, e, c=2): pass
+
+@delegates()# since no argument was passsed here we delegate to the superclass
+class Foo(BaseFoo):
+    def __init__(self, a, b=1, **kwargs): super().__init__(**kwargs)
+
+test_sig(Foo, '(a, b=1, *, c=2)')
+
+
+

source

+
+
+

method

+
+
 method (f)
+
+

Mark f as a method

+

The method function is used to change a function’s type to a method. In the below example we change the type of a from a function to a method:

+
+
def a(x=2): return x + 1
+assert type(a).__name__ == 'function'
+
+a = method(a)
+assert type(a).__name__ == 'method'
+
+
+

source

+
+
+

funcs_kwargs

+
+
 funcs_kwargs (as_method=False)
+
+

Replace methods in cls._methods with those from kwargs

+

The func_kwargs decorator allows you to add a list of functions or methods to an existing class. You must set this list as a class attribute named _methods when defining your class. Additionally, you must incldue the **kwargs argument in the ___init__ method of your class.

+

After defining your class this way, you can add functions to your class upon instantation as illusrated below.

+

For example, we define class T to allow adding the function b to class T as follows (note that this function is stored as an attribute of T and doesn’t have access to cls or self):

+
+
@funcs_kwargs
+class T:
+    _methods=['b'] # allows you to add method b upon instantiation
+    def __init__(self, f=1, **kwargs): pass # don't forget to include **kwargs in __init__
+    def a(self): return 1
+    def b(self): return 2
+    
+t = T()
+test_eq(t.a(), 1)
+test_eq(t.b(), 2)
+
+

Because we defined the class T this way, the signature of T indicates the option to add the function or method(s) specified in _methods. In this example, b is added to the signature:

+
+
test_sig(T, '(f=1, *, b=None)')
+inspect.signature(T)
+
+
<Signature (f=1, *, b=None)>
+
+
+

You can now add the function b to class T upon instantiation:

+
+
def _new_func(): return 5
+
+t = T(b = _new_func)
+test_eq(t.b(), 5)
+
+

If you try to add a function with a name not listed in _methods it will be ignored. In the below example, the attempt to add a function named a is ignored:

+
+
t = T(a = lambda:3)
+test_eq(t.a(), 1) # the attempt to add a is ignored and uses the original method instead.
+
+

Note that you can also add methods not defined in the original class as long it is specified in the _methods attribute:

+
+
@funcs_kwargs
+class T:
+    _methods=['c']
+    def __init__(self, f=1, **kwargs): pass
+
+t = T(c = lambda: 4)
+test_eq(t.c(), 4)
+
+

Until now, these examples showed how to add functions stored as an instance attribute without access to self. However, if you need access to self you can set as_method=True in the func_kwargs decorator to add a method instead:

+
+
def _f(self,a=1): return self.num + a # access the num attribute from the instance
+
+@funcs_kwargs(as_method=True)
+class T: 
+    _methods=['b']
+    num = 5
+    
+t = T(b = _f) # adds method b
+test_eq(t.b(5), 10) # self.num + 5 = 10
+
+

Here is an example of how you might use this functionality with inheritence:

+
+
def _f(self,a=1): return self.num * a #multiply instead of add 
+
+class T2(T):
+    def __init__(self,num):
+        super().__init__(b = _f) # add method b from the super class
+        self.num=num
+        
+t = T2(num=3)
+test_eq(t.b(a=5), 15) # 3 * 5 = 15
+test_sig(T2, '(num)')
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/net.html b/net.html new file mode 100644 index 00000000..45d8ca6f --- /dev/null +++ b/net.html @@ -0,0 +1,1042 @@ + + + + + + + + + + +Network functionality – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Network functionality

+
+ +
+
+ Network, HTTP, and URL functions +
+
+ + +
+ + + + +
+ + + +
+ + + +
+
from fastcore.test import *
+from nbdev.showdoc import *
+from fastcore.nb_imports import *
+
+
+

URLs

+
+

source

+
+

urlquote

+
+
 urlquote (url)
+
+

Update url’s path with urllib.parse.quote

+
+
urlquote("https://github.com/fastai/fastai/compare/master@{1.day.ago}…master")
+
+
'https://github.com/fastai/fastai/compare/master@%7B1.day.ago%7D%E2%80%A6master'
+
+
+
+
urlquote("https://www.google.com/search?q=你好")
+
+
'https://www.google.com/search?q=%E4%BD%A0%E5%A5%BD'
+
+
+
+

source

+
+
+

urlwrap

+
+
 urlwrap (url, data=None, headers=None)
+
+

Wrap url in a urllib Request with urlquote

+
+

source

+
+

HTTP4xxClientError

+
+
 HTTP4xxClientError (url, code, msg, hdrs, fp)
+
+

Base class for client exceptions (code 4xx) from url* functions

+
+

source

+
+
+

HTTP5xxServerError

+
+
 HTTP5xxServerError (url, code, msg, hdrs, fp)
+
+

Base class for server exceptions (code 5xx) from url* functions

+
+

source

+
+
+
+

urlopener

+
+
 urlopener ()
+
+
+

source

+
+
+

urlopen

+
+
 urlopen (url, data=None, headers=None, timeout=None, **kwargs)
+
+

Like urllib.request.urlopen, but first urlwrap the url, and encode data

+

With urlopen, the body of the response will also be returned in addition to the message if there is an error:

+
+
try: urlopen('https://api.github.com/v3')
+except HTTPError as e: 
+    print(e.code, e.msg)
+    assert 'documentation_url' in e.msg
+
+
404 Not Found
+====Error Body====
+{
+  "message": "Not Found",
+  "documentation_url": "https://docs.github.com/rest"
+}
+
+
+
+
+

source

+
+
+

urlread

+
+
 urlread (url, data=None, headers=None, decode=True, return_json=False,
+          return_headers=False, timeout=None, **kwargs)
+
+

Retrieve url, using data dict or kwargs to POST if present

+
+

source

+
+
+

urljson

+
+
 urljson (url, data=None, timeout=None)
+
+

Retrieve url and decode json

+
+
test_eq(urljson('https://httpbin.org/get')['headers']['User-Agent'], url_default_headers['User-Agent'])
+
+
+

source

+
+
+

urlcheck

+
+
 urlcheck (url, headers=None, timeout=10)
+
+
+

source

+
+
+

urlclean

+
+
 urlclean (url)
+
+

Remove fragment, params, and querystring from url if present

+
+
test_eq(urlclean('http://a.com/b?c=1#d'), 'http://a.com/b')
+
+
+

source

+
+
+

urlretrieve

+
+
 urlretrieve (url, filename=None, reporthook=None, data=None,
+              headers=None, timeout=None)
+
+

Same as urllib.request.urlretrieve but also works with Request objects

+
+

source

+
+
+

urldest

+
+
 urldest (url, dest=None)
+
+
+

source

+
+
+

urlsave

+
+
 urlsave (url, dest=None, reporthook=None, headers=None, timeout=None)
+
+

Retrieve url and save based on its name

+
+
#skip
+with tempfile.TemporaryDirectory() as d: urlsave('http://www.google.com/index.html', d)
+
+
+

source

+
+
+

urlvalid

+
+
 urlvalid (x)
+
+

Test if x is a valid URL

+
+
assert urlvalid('http://www.google.com/')
+assert not urlvalid('www.google.com/')
+assert not urlvalid(1)
+
+
+

source

+
+
+

urlrequest

+
+
 urlrequest (url, verb, headers=None, route=None, query=None, data=None,
+             json_data=True)
+
+

Request for url with optional route params replaced by route, plus query string, and post data

+
+
hdr = {'Hdr1':'1', 'Hdr2':'2'}
+req = urlrequest('http://example.com/{foo}/1', 'POST',
+                 headers=hdr, route={'foo':'3'}, query={'q':'4'}, data={'d':'5'})
+
+test_eq(req.headers, hdr)
+test_eq(req.full_url, 'http://example.com/3/1?q=4')
+test_eq(req.method, 'POST')
+test_eq(req.data, b'{"d": "5"}')
+
+
+
req = urlrequest('http://example.com/{foo}/1', 'POST', data={'d':'5','e':'6'}, headers=hdr, json_data=False)
+test_eq(req.data, b'd=5&e=6')
+
+
+

source

+
+
+

Request.summary

+
+
 Request.summary (skip=None)
+
+

Summary containing full_url, headers, method, and data, removing skip from headers

+
+
req.summary(skip='Hdr1')
+
+
{'full_url': 'http://example.com/{foo}/1',
+ 'method': 'POST',
+ 'data': b'd=5&e=6',
+ 'headers': {'Hdr2': '2'}}
+
+
+
+

source

+
+
+

urlsend

+
+
 urlsend (url, verb, headers=None, route=None, query=None, data=None,
+          json_data=True, return_json=True, return_headers=False,
+          debug=None, timeout=None)
+
+

Send request with urlrequest, converting result to json if return_json

+
+

source

+
+
+

do_request

+
+
 do_request (url, post=False, headers=None, **data)
+
+

Call GET or json-encoded POST on url, depending on post

+
+
+
+

Basic client/server

+
+

source

+
+

start_server

+
+
 start_server (port, host=None, dgram=False, reuse_addr=True,
+               n_queue=None)
+
+

Create a socket server on port, with optional host, of type dgram

+

You can create a TCP client and server pass an int as port and optional host. host defaults to your main network interface if not provided. You can create a Unix socket client and server by passing a string to port. A SOCK_STREAM socket is created by default, unless you pass dgram=True, in which case a SOCK_DGRAM socket is created. n_queue sets the listening queue size.

+
+

source

+
+
+

start_client

+
+
 start_client (port, host=None, dgram=False)
+
+

Create a socket client on port, with optional host, of type dgram

+
+

source

+
+
+

tobytes

+
+
 tobytes (s:str)
+
+

Convert s into HTTP-ready bytes format

+
+
test_eq(tobytes('foo\nbar'), b'foo\r\nbar')
+
+
+

source

+
+
+

http_response

+
+
 http_response (body=None, status=200, hdrs=None, **kwargs)
+
+

Create an HTTP-ready response, adding kwargs to hdrs

+
+
exp = b'HTTP/1.1 200 OK\r\nUser-Agent: me\r\nContent-Length: 4\r\n\r\nbody'
+test_eq(http_response('body', 200, User_Agent='me'), exp)
+
+
+

source

+
+
+

recv_once

+
+
 recv_once (host:str='localhost', port:int=8000)
+
+

Spawn a thread to receive a single HTTP request and store in d['r']

+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/parallel.html b/parallel.html new file mode 100644 index 00000000..c4a55dd6 --- /dev/null +++ b/parallel.html @@ -0,0 +1,976 @@ + + + + + + + + + + +Parallel – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Parallel

+
+ +
+
+ Threading and multiprocessing functions +
+
+ + +
+ + + + +
+ + + +
+ + + +
+
from fastcore.test import *
+from nbdev.showdoc import *
+from fastcore.nb_imports import *
+
+
+

source

+
+

threaded

+
+
 threaded (process=False)
+
+

Run f in a Thread (or Process if process=True), and returns it

+
+
@threaded
+def _1():
+    time.sleep(0.05)
+    print("second")
+    return 5
+
+@threaded
+def _2():
+    time.sleep(0.01)
+    print("first")
+
+a = _1()
+_2()
+time.sleep(0.1)
+
+
first
+second
+
+
+

After the thread is complete, the return value is stored in the result attr.

+
+
a.result
+
+
5
+
+
+
+

source

+
+
+

startthread

+
+
 startthread (f)
+
+

Like threaded, but start thread immediately

+
+
@startthread
+def _():
+    time.sleep(0.05)
+    print("second")
+
+@startthread
+def _():
+    time.sleep(0.01)
+    print("first")
+
+time.sleep(0.1)
+
+
first
+second
+
+
+
+

source

+
+
+

startproc

+
+
 startproc (f)
+
+

Like threaded(True), but start Process immediately

+
+
@startproc
+def _():
+    time.sleep(0.05)
+    print("second")
+
+@startproc
+def _():
+    time.sleep(0.01)
+    print("first")
+
+time.sleep(0.1)
+
+
first
+second
+
+
+
+

source

+
+
+

parallelable

+
+
 parallelable (param_name, num_workers, f=None)
+
+
+

source

+
+

ThreadPoolExecutor

+
+
 ThreadPoolExecutor (max_workers=4, on_exc=<built-in function print>,
+                     pause=0, **kwargs)
+
+

Same as Python’s ThreadPoolExecutor, except can pass max_workers==0 for serial execution

+
+

source

+
+
+

ProcessPoolExecutor

+
+
 ProcessPoolExecutor (max_workers=4, on_exc=<built-in function print>,
+                      pause=0, mp_context=None, initializer=None,
+                      initargs=())
+
+

Same as Python’s ProcessPoolExecutor, except can pass max_workers==0 for serial execution

+
+

source

+
+
+
+

parallel

+
+
 parallel (f, items, *args, n_workers=4, total=None, progress=None,
+           pause=0, method=None, threadpool=False, timeout=None,
+           chunksize=1, **kwargs)
+
+

Applies func in parallel to items, using n_workers

+
+

source

+
+
+

add_one

+
+
 add_one (x, a=1)
+
+
+
inp,exp = range(50),range(1,51)
+
+test_eq(parallel(add_one, inp, n_workers=2, progress=False), exp)
+test_eq(parallel(add_one, inp, threadpool=True, n_workers=2, progress=False), exp)
+test_eq(parallel(add_one, inp, n_workers=1, a=2), range(2,52))
+test_eq(parallel(add_one, inp, n_workers=0), exp)
+test_eq(parallel(add_one, inp, n_workers=0, a=2), range(2,52))
+
+

Use the pause parameter to ensure a pause of pause seconds between processes starting. This is in case there are race conditions in starting some process, or to stagger the time each process starts, for example when making many requests to a webserver. Set threadpool=True to use ThreadPoolExecutor instead of ProcessPoolExecutor.

+
+
from datetime import datetime
+
+
+
def print_time(i): 
+    time.sleep(random.random()/1000)
+    print(i, datetime.now())
+
+parallel(print_time, range(5), n_workers=2, pause=0.25);
+
+
0 2022-08-07 05:10:05.999916
+1 2022-08-07 05:10:06.252031
+2 2022-08-07 05:10:06.503603
+3 2022-08-07 05:10:06.755216
+4 2022-08-07 05:10:07.006702
+
+
+
+

source

+
+
+

run_procs

+
+
 run_procs (f, f_done, args)
+
+

Call f for each item in args in parallel, yielding f_done

+
+

source

+
+
+

parallel_gen

+
+
 parallel_gen (cls, items, n_workers=4, **kwargs)
+
+

Instantiate cls in n_workers procs & call each on a subset of items in parallel.

+
+
# class _C:
+#     def __call__(self, o): return ((i+1) for i in o)
+
+# items = range(5)
+
+# res = L(parallel_gen(_C, items, n_workers=0))
+# idxs,dat1 = zip(*res.sorted(itemgetter(0)))
+# test_eq(dat1, range(1,6))
+
+# res = L(parallel_gen(_C, items, n_workers=3))
+# idxs,dat2 = zip(*res.sorted(itemgetter(0)))
+# test_eq(dat2, dat1)
+
+

cls is any class with __call__. It will be passed args and kwargs when initialized. Note that n_workers instances of cls are created, one in each process. items are then split in n_workers batches and one is sent to each cls. The function then returns a generator of tuples of item indices and results.

+
+
class TestSleepyBatchFunc:
+    "For testing parallel processes that run at different speeds"
+    def __init__(self): self.a=1
+    def __call__(self, batch):
+        for k in batch:
+            time.sleep(random.random()/4)
+            yield k+self.a
+
+x = np.linspace(0,0.99,20)
+
+res = L(parallel_gen(TestSleepyBatchFunc, x, n_workers=2))
+test_eq(res.sorted().itemgot(1), x+1)
+
+ + +
+
+ +
+
+
+
# #|hide
+# from subprocess import Popen, PIPE
+# # test num_workers > 0 in scripts works when python process start method is spawn
+# process = Popen(["python", "parallel_test.py"], stdout=PIPE)
+# _, err = process.communicate(timeout=10)
+# exit_code = process.wait()
+# test_eq(exit_code, 0)
+
+ + +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/py2pyi.html b/py2pyi.html new file mode 100644 index 00000000..52e110f6 --- /dev/null +++ b/py2pyi.html @@ -0,0 +1,1123 @@ + + + + + + + + + +Create delegated pyi – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Create delegated pyi

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

Setup

+
+
+

Basics

+
+

source

+
+

imp_mod

+
+
 imp_mod (module_path, package=None)
+
+

Import dynamically the module referenced in fn

+
+
fn = Path('test_py2pyi.py')
+
+
+
mod = imp_mod(fn)
+a = mod.A()
+a.h()
+
+
1
+
+
+
+
tree = _get_tree(mod)
+
+
+
+
+

AST.__repr__

+
+
 AST.__repr__ ()
+
+
+
# for o in enumerate(tree.body): print(o)
+
+
+
node = tree.body[4]
+node
+
+
def f(a: int, b: str='a') -> str:
+    """I am f"""
+    return 1
+
+
+
+
isinstance(node, functypes)
+
+
True
+
+
+
+

source

+
+
+

has_deco

+
+
 has_deco (node:Union[ast.FunctionDef,ast.AsyncFunctionDef], name:str)
+
+

Check if a function node node has a decorator named name

+
+
nm = 'delegates'
+has_deco(node, nm)
+
+
False
+
+
+
+
node = tree.body[5]
+node
+
+
@delegates(f)
+def g(c, d: X, **kwargs) -> str:
+    """I am g"""
+    return 2
+
+
+
+
has_deco(node, nm)
+
+
True
+
+
+
+
+
+

Function processing

+
+
def _proc_body   (node, mod): print('_proc_body', type(node))
+def _proc_func   (node, mod): print('_proc_func', type(node))
+def _proc_class  (node, mod): print('_proc_class', type(node))
+def _proc_patched(node, mod): print('_proc_patched', type(node))
+
+
+
_proc_mod(mod);
+
+
_proc_class <class 'ast.ClassDef'>
+_proc_body <class 'ast.FunctionDef'>
+_proc_func <class 'ast.FunctionDef'>
+_proc_body <class 'ast.FunctionDef'>
+_proc_class <class 'ast.ClassDef'>
+_proc_class <class 'ast.ClassDef'>
+_proc_patched <class 'ast.FunctionDef'>
+_proc_patched <class 'ast.FunctionDef'>
+_proc_body <class 'ast.FunctionDef'>
+
+
+
+
node.name
+
+
'g'
+
+
+
+
sym = getattr(mod, node.name)
+sym
+
+
<function test_py2pyi.g(c, d: test_py2pyi.X, *, b: str = 'a') -> str>
+
+
+
+
sig = signature(sym)
+print(sig)
+
+
(c, d: test_py2pyi.X, *, b: str = 'a') -> str
+
+
+
+

source

+
+

sig2str

+
+
 sig2str (sig)
+
+
+

source

+
+
+

ast_args

+
+
 ast_args (func)
+
+
+
newargs = ast_args(sym)
+newargs
+
+
c, d: test_py2pyi.X, *, b: str='a'
+
+
+
+
node.args
+
+
c, d: X, **kwargs
+
+
+
+
node.args = newargs
+node
+
+
@delegates(f)
+def g(c, d: test_py2pyi.X, *, b: str='a') -> str:
+    """I am g"""
+    return 2
+
+
+
+
_body_ellip(node)
+node
+
+
@delegates(f)
+def g(c, d: test_py2pyi.X, *, b: str='a') -> str:
+    """I am g"""
+    ...
+
+
+
+
tree = _get_tree(mod)
+node = tree.body[5]
+node
+
+
@delegates(f)
+def g(c, d: X, **kwargs) -> str:
+    """I am g"""
+    return 2
+
+
+
+
_update_func(node, sym)
+node
+
+
def g(c, d: test_py2pyi.X, *, b: str='a') -> str:
+    """I am g"""
+    ...
+
+
+
+
tree = _proc_mod(mod)
+tree.body[5]
+
+
_proc_class <class 'ast.ClassDef'>
+_proc_class <class 'ast.ClassDef'>
+_proc_class <class 'ast.ClassDef'>
+_proc_patched <class 'ast.FunctionDef'>
+_proc_patched <class 'ast.FunctionDef'>
+
+
+
def g(c, d: test_py2pyi.X, *, b: str='a') -> str:
+    """I am g"""
+    ...
+
+
+
+
+
+

Patch

+
+
node = tree.body[9]
+node
+
+
@patch
+@delegates(j)
+def k(self: (A, B), b: bool=False, **kwargs):
+    return 1
+
+
+
+
ann = node.args.args[0].annotation
+
+
+
if hasattr(ann, 'elts'): ann = ann.elts[0]
+
+
+
nm = ann.id
+nm
+
+
'A'
+
+
+
+
cls = getattr(mod, nm)
+sym = getattr(cls, node.name)
+
+
+
sig2str(signature(sym))
+
+
"(self: (test_py2pyi.A, test_py2pyi.B), b: bool = False, *, d: str = 'a')"
+
+
+
+
_update_func(node, sym)
+
+
+
node
+
+
@patch
+def k(self: (test_py2pyi.A, test_py2pyi.B), b: bool=False, *, d: str='a'):
+    ...
+
+
+
+
tree = _proc_mod(mod)
+tree.body[9]
+
+
_proc_class <class 'ast.ClassDef'>
+_proc_class <class 'ast.ClassDef'>
+_proc_class <class 'ast.ClassDef'>
+
+
+
@patch
+def k(self: (test_py2pyi.A, test_py2pyi.B), b: bool=False, *, d: str='a'):
+    ...
+
+
+
+
+

Class and file

+
+
tree = _get_tree(mod)
+node = tree.body[7]
+node
+
+
class A:
+
+    @delegates(j)
+    def h(self, b: bool=False, **kwargs):
+        a = 1
+        return a
+
+
+
+
node.body
+
+
[@delegates(j)
+ def h(self, b: bool=False, **kwargs):
+     a = 1
+     return a]
+
+
+
+
tree = _proc_mod(mod)
+tree.body[7]
+
+
class A:
+
+    def h(self, b: bool=False, *, d: str='a'):
+        ...
+
+
+
+

source

+
+

create_pyi

+
+
 create_pyi (fn, package=None)
+
+

Convert fname.py to fname.pyi by removing function bodies and expanding delegates kwargs

+
+
create_pyi(fn)
+
+
+
# fn = Path('/Users/jhoward/git/fastcore/fastcore/docments.py')
+# create_pyi(fn, 'fastcore')
+
+
+
+
+

Script

+
+

source

+
+

py2pyi

+
+
 py2pyi (fname:str, package:str=None)
+
+

Convert fname.py to fname.pyi by removing function bodies and expanding delegates kwargs

+ + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
fnamestrThe file name to convert
packagestrNoneThe parent package
+
+

source

+
+
+

replace_wildcards

+
+
 replace_wildcards (path:str)
+
+

Expand wildcard imports in the specified Python file.

+ + + + + + + + + + + + + + + +
TypeDetails
pathstrPath to the Python file to process
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/robots.txt b/robots.txt new file mode 100644 index 00000000..7b04fdf9 --- /dev/null +++ b/robots.txt @@ -0,0 +1 @@ +Sitemap: https://fastcore.fast.ai/sitemap.xml diff --git a/script.html b/script.html new file mode 100644 index 00000000..b53a7efc --- /dev/null +++ b/script.html @@ -0,0 +1,999 @@ + + + + + + + + + + +Script - CLI – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Script - CLI

+
+ +
+
+ A fast way to turn your python function into a script. +
+
+ + +
+ + + + +
+ + + +
+ + + +

Part of fast.ai’s toolkit for delightful developer experiences.

+
+

Overview

+

Sometimes, you want to create a quick script, either for yourself, or for others. But in Python, that involves a whole lot of boilerplate and ceremony, especially if you want to support command line arguments, provide help, and other niceties. You can use argparse for this purpose, which comes with Python, but it’s complex and verbose.

+

fastcore.script makes life easier. There are much fancier modules to help you write scripts (we recommend Python Fire, and Click is also popular), but fastcore.script is very fast and very simple. In fact, it’s <50 lines of code! Basically, it’s just a little wrapper around argparse that uses modern Python features and some thoughtful defaults to get rid of the boilerplate.

+

For full details, see the docs for core.

+
+
+

Example

+

Here’s a complete example (available in examples/test_fastcore.py):

+
from fastcore.script import *
+@call_parse
+def main(msg:str,     # The message
+         upper:bool): # Convert to uppercase?
+    "Print `msg`, optionally converting to uppercase"
+    print(msg.upper() if upper else msg)
+

If you copy that info a file and run it, you’ll see:

+
$ examples/test_fastcore.py --help
+usage: test_fastcore.py [-h] [--upper] msg
+
+Print `msg`, optionally converting to uppercase
+
+positional arguments:
+  msg          The message
+
+optional arguments:
+  -h, --help   show this help message and exit
+  --upper      Convert to uppercase? (default: False)
+

As you see, we didn’t need any if __name__ == "__main__", we didn’t have to parse arguments, we just wrote a function, added a decorator to it, and added some annotations to our function’s parameters. As a bonus, we can also use this function directly from a REPL such as Jupyter Notebook - it’s not just for command line scripts!

+

You should provide a default (after the =) for any optional parameters. If you don’t provide a default for a parameter, then it will be a positional parameter.

+
+
+

Param annotations

+

If you want to use the full power of argparse, you can do so by using Param annotations instead of type annotations and docments, like so:

+
from fastcore.script import *
+@call_parse
+def main(msg:Param("The message", str),
+         upper:Param("Convert to uppercase?", store_true)):
+    "Print `msg`, optionally converting to uppercase"
+    print(msg.upper() if upper else msg)
+

If you use this approach, then each parameter in your function should have an annotation Param(...) (as in the example above). You can pass the following when calling Param: help,type,opt,action,nargs,const,choices,required . Except for opt, all of these are just passed directly to argparse, so you have all the power of that module at your disposal. Generally you’ll want to pass at least help (since this is provided as the help string for that parameter) and type (to ensure that you get the type of data you expect). opt is a bool that defines whether a param is optional or required (positional) - but you’ll generally not need to set this manually, because fastcore.script will set it for you automatically based on default values.

+
+
+

setuptools scripts

+

There’s a really nice feature of pip/setuptools that lets you create commandline scripts directly from functions, makes them available in the PATH, and even makes your scripts cross-platform (e.g. in Windows it creates an exe). fastcore.script supports this feature too. The trick to making a function available as a script is to add a console_scripts section to your setup file, of the form: script_name=module:function_name. E.g. in this case we use: test_fastcore.script=fastcore.script.test_cli:main. With this, you can then just type test_fastcore.script at any time, from any directory, and your script will be called (once it’s installed using one of the methods below).

+

You don’t actually have to write a setup.py yourself. Instead, just use nbdev. Then modify settings.ini as appropriate for your module/script. To install your script directly, you can type pip install -e .. Your script, when installed this way (it’s called an editable install), will automatically be up to date even if you edit it - there’s no need to reinstall it after editing. With nbdev you can even make your module and script available for installation directly from pip and conda by running make release.

+
+
+

API details

+
+

source

+
+

store_true

+
+
 store_true ()
+
+

Placeholder to pass to Param for store_true action

+
+

source

+
+
+

store_false

+
+
 store_false ()
+
+

Placeholder to pass to Param for store_false action

+
+

source

+
+
+

bool_arg

+
+
 bool_arg (v)
+
+

Use as type for Param to get bool behavior

+
+

source

+
+
+

clean_type_str

+
+
 clean_type_str (x:str)
+
+
+
class Test: pass
+
+test_eq(clean_type_str(argparse.ArgumentParser), 'argparse.ArgumentParser')
+test_eq(clean_type_str(Test), 'Test')
+test_eq(clean_type_str(int), 'int')
+test_eq(clean_type_str(float), 'float')
+test_eq(clean_type_str(store_false), 'store_false')
+
+
+

source

+
+
+

Param

+
+
 Param (help='', type=None, opt=True, action=None, nargs=None, const=None,
+        choices=None, required=None, default=None)
+
+

A parameter in a function used in anno_parser or call_parse

+
+
test_eq(repr(Param("Help goes here")), '<Help goes here>')
+test_eq(repr(Param("Help", int)), 'int <Help>')
+test_eq(repr(Param(help=None, type=int)), 'int')
+test_eq(repr(Param(help=None, type=None)), '')
+
+

Each parameter in your function should have an annotation Param(...). You can pass the following when calling Param: help,type,opt,action,nargs,const,choices,required (i.e. it takes the same parameters as argparse.ArgumentParser.add_argument, plus opt). Except for opt, all of these are just passed directly to argparse, so you have all the power of that module at your disposal. Generally you’ll want to pass at least help (since this is provided as the help string for that parameter) and type (to ensure that you get the type of data you expect).

+

opt is a bool that defines whether a param is optional or required (positional) - but you’ll generally not need to set this manually, because fastcore.script will set it for you automatically based on default values. You should provide a default (after the =) for any optional parameters. If you don’t provide a default for a parameter, then it will be a positional parameter.

+

Param’s __repr__ also allows for more informative function annotation when looking up the function’s doc using shift+tab. You see the type annotation (if there is one) and the accompanying help documentation with it.

+
+
def f(required:Param("Required param", int),
+      a:Param("param 1", bool_arg),
+      b:Param("param 2", str)="test"):
+    "my docs"
+    ...
+
+
+
help(f)
+
+
Help on function f in module __main__:
+
+f(required: int <Required param>, a: bool_arg <param 1>, b: str <param 2> = 'test')
+    my docs
+
+
+
+
+
p = Param(help="help", type=int)
+p.set_default(1)
+test_eq(p.kwargs, {'help': 'help (default: 1)', 'type': int, 'default': 1})
+
+
+

source

+
+
+

anno_parser

+
+
 anno_parser (func, prog:str=None)
+
+

Look at params (annotated with Param) in func and return an ArgumentParser

+ + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
funcFunction to get arguments from
progstrNoneThe name of the program
+

This converts a function with parameter annotations of type Param into an argparse.ArgumentParser object. Function arguments with a default provided are optional, and other arguments are positional.

+
+
_en = str_enum('_en', 'aa','bb','cc')
+def f(required:Param("Required param", int),
+      a:Param("param 1", bool_arg),
+      b:Param("param 2", str)="test",
+      c:Param("param 3", _en)=_en.aa):
+    "my docs"
+    ...
+
+p = anno_parser(f, 'progname')
+p.print_help()
+
+
usage: progname [-h] [--b B] [--c {aa,bb,cc}] required a
+
+my docs
+
+positional arguments:
+  required        Required param
+  a               param 1
+
+optional arguments:
+  -h, --help      show this help message and exit
+  --b B           param 2 (default: test)
+  --c {aa,bb,cc}  param 3 (default: aa)
+
+
+

It also works with type annotations and docments:

+
+
def g(required:int,  # Required param
+      a:bool_arg,    # param 1
+      b="test",      # param 2
+      c:_en=_en.aa): # param 3
+    "my docs"
+    ...
+
+p = anno_parser(g, 'progname')
+p.print_help()
+
+
usage: progname [-h] [--b B] [--c {aa,bb,cc}] required a
+
+my docs
+
+positional arguments:
+  required        Required param
+  a               param 1
+
+optional arguments:
+  -h, --help      show this help message and exit
+  --b B           param 2 (default: test)
+  --c {aa,bb,cc}  param 3 (default: aa)
+
+
+
+

source

+
+
+

args_from_prog

+
+
 args_from_prog (func, prog)
+
+

Extract args from prog

+

Sometimes it’s convenient to extract arguments from the actual name of the called program. args_from_prog will do this, assuming that names and values of the params are separated by a #. Optionally there can also be a prefix separated by ## (double underscore).

+
+
exp = {'a': False, 'b': 'baa'}
+test_eq(args_from_prog(f, 'foo##a#0#b#baa'), exp)
+test_eq(args_from_prog(f, 'a#0#b#baa'), exp)
+
+
+

source

+
+
+

call_parse

+
+
 call_parse (func=None, nested=False)
+
+

Decorator to create a simple CLI from func using anno_parser

+
+
@call_parse
+def test_add(
+    a:int=0,  # param a
+    b:int=0  # param 1
+):
+    "Add up `a` and `b`"
+    return a + b
+
+

call_parse decorated functions work as regular functions and also as command-line interface functions.

+
+
test_eq(test_add(1,2), 3)
+
+

This is the main way to use fastcore.script; decorate your function with call_parse, add Param annotations (as shown above) or type annotations and docments, and it can then be used as a script.

+

Use the nested keyword argument to create nested parsers, where earlier parsers consume only their known args from sys.argv before later parsers are used. This is useful to create one command line application that executes another. For example:

+
myrunner --keyword 1 script.py -- <script.py args>
+

A separating -- after the first application’s args is recommended though not always required, otherwise args may be parsed in unexpected ways. For example:

+
myrunner script.py -h
+

would display myrunner’s help and not script.py’s.

+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/search.json b/search.json new file mode 100644 index 00000000..f2e2d427 --- /dev/null +++ b/search.json @@ -0,0 +1,632 @@ +[ + { + "objectID": "xml.html", + "href": "xml.html", + "title": "XML", + "section": "", + "text": "from IPython.display import Markdown\nfrom pprint import pprint\n\n\nsource\n\nFT\n\n FT (tag, cs, attrs=None, void_=False, **kwargs)\n\nA ‘Fast Tag’ structure, which is a list of [tag,children,attrs]\n\nsource\n\n\nattrmap\n\n attrmap (o)\n\n\nsource\n\n\nvalmap\n\n valmap (o)\n\n\nsource\n\n\nft\n\n ft (tag:str, *c, void_=False, attrmap=<function attrmap>,\n valmap=<function valmap>, **kw)\n\nCreate an FT structure for to_xml()\nThe main HTML tags are exported as ft partials.\nAttributes are passed as keywords. Use ‘klass’ and ‘fr’ instead of ‘class’ and ‘for’, to avoid Python reserved word clashes.\n\nsource\n\n\nHtml\n\n Html (*c, doctype=True, **kwargs)\n\nAn HTML tag, optionally preceeded by !DOCTYPE HTML\n\nsamp = Html(\n Head(Title('Some page')),\n Body(Div('Some text\\nanother line', Input(name='me'), Img(src=\"filename\", data=1),\n cls=['myclass', 'another'],\n style={'padding':1, 'margin':2}))\n)\npprint(samp)\n\n(['!doctype', (), {'html': True}],\n ['html',\n (['head', (['title', ('Some page',), {}],), {}],\n ['body',\n (['div',\n ('Some text\\nanother line',\n ['input', (), {'name': 'me'}],\n ['img', (), {'data': 1, 'src': 'filename'}]),\n {'class': 'myclass another', 'style': 'padding:1; margin:2'}],),\n {}]),\n {}])\n\n\nThe three elements of the list can also be accessed with property names, so you don’t have to remember their order.\n\nelem = P('Some text', id=\"myid\")\nprint(elem.tag)\nprint(elem.children)\nprint(elem.attrs)\n\np\n('Some text',)\n{'id': 'myid'}\n\n\nYou can also get and set attrs directly:\n\nelem.id = 'newid'\nprint(elem.id, elem.get('id'), elem.get('foo', 'missing'))\nelem\n\nnewid newid missing\n\n\n['p', ('Some text',), {'id': 'newid'}]\n\n\n\nsource\n\n\nSafe\n*str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str\nCreate a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.*\n\nsource\n\n\nto_xml\n\n to_xml (elm, lvl=0, indent:bool=True)\n\nConvert ft element tree into an XML string\n\nh = to_xml(samp)\nprint(h)\n\n<!doctype html>\n\n<html>\n <head>\n <title>Some page</title>\n </head>\n <body>\n <div class=\"myclass another\" style=\"padding:1; margin:2\">\nSome text\nanother line\n <input name=\"me\">\n <img src=\"filename\" data=\"1\">\n </div>\n </body>\n</html>\n\n\n\n\nh = to_xml(samp, indent=False)\nprint(h)\n\n<!doctype html><html><head><title>Some page</title></head><body><div class=\"myclass another\" style=\"padding:1; margin:2\">Some text\nanother line<input name=\"me\"><img src=\"filename\" data=\"1\"></div></body></html>\n\n\nInteroperability both directions with Django and Jinja using the html() protocol:\n\ndef _esc(s): return s.__html__() if hasattr(s, '__html__') else Safe(escape(s))\n\nr = Safe('<b>Hello from Django</b>')\nprint(to_xml(Div(r)))\nprint(_esc(Div(P('Hello from fastcore <3'))))\n\n<div><b>Hello from Django</b></div>\n\n<div>\n <p>Hello from fastcore <3</p>\n</div>\n\n\n\n\nsource\n\n\nhighlight\n\n highlight (s, lang='html')\n\nMarkdown to syntax-highlight s in language lang\n\nsource\n\n\nshowtags\n\n showtags (s)\n\n\nsource\n\n\ngetattr\n\n __getattr__ (tag)\n\n\nsource\n\n\nFT.__call__\n\n FT.__call__ (*c, **kw)\n\nCall self as a function.\nYou can also reorder the children to come after the attrs, if you use this alternative syntax for FT where the children are in a second pair of () (behind the scenes this is because FT implements __call__ to add children).\n\nBody(klass='myclass')(\n Div(style='padding:3px')(\n 'Some text ',\n I(spurious=True)('in italics'),\n Input(name='me'),\n Img(src=\"filename\", data=1)\n )\n)\n\n<body class=\"myclass\">\n <div style=\"padding:3px\">\nSome text \n <i spurious>in italics</i>\n <input name=\"me\">\n <img src=\"filename\" data=\"1\">\n </div>\n</body>", + "crumbs": [ + "XML" + ] + }, + { + "objectID": "net.html", + "href": "net.html", + "title": "Network functionality", + "section": "", + "text": "from fastcore.test import *\nfrom nbdev.showdoc import *\nfrom fastcore.nb_imports import *", + "crumbs": [ + "Network functionality" + ] + }, + { + "objectID": "net.html#urls", + "href": "net.html#urls", + "title": "Network functionality", + "section": "URLs", + "text": "URLs\n\nsource\n\nurlquote\n\n urlquote (url)\n\nUpdate url’s path with urllib.parse.quote\n\nurlquote(\"https://github.com/fastai/fastai/compare/master@{1.day.ago}…master\")\n\n'https://github.com/fastai/fastai/compare/master@%7B1.day.ago%7D%E2%80%A6master'\n\n\n\nurlquote(\"https://www.google.com/search?q=你好\")\n\n'https://www.google.com/search?q=%E4%BD%A0%E5%A5%BD'\n\n\n\nsource\n\n\nurlwrap\n\n urlwrap (url, data=None, headers=None)\n\nWrap url in a urllib Request with urlquote\n\nsource\n\nHTTP4xxClientError\n\n HTTP4xxClientError (url, code, msg, hdrs, fp)\n\nBase class for client exceptions (code 4xx) from url* functions\n\nsource\n\n\nHTTP5xxServerError\n\n HTTP5xxServerError (url, code, msg, hdrs, fp)\n\nBase class for server exceptions (code 5xx) from url* functions\n\nsource\n\n\n\nurlopener\n\n urlopener ()\n\n\nsource\n\n\nurlopen\n\n urlopen (url, data=None, headers=None, timeout=None, **kwargs)\n\nLike urllib.request.urlopen, but first urlwrap the url, and encode data\nWith urlopen, the body of the response will also be returned in addition to the message if there is an error:\n\ntry: urlopen('https://api.github.com/v3')\nexcept HTTPError as e: \n print(e.code, e.msg)\n assert 'documentation_url' in e.msg\n\n404 Not Found\n====Error Body====\n{\n \"message\": \"Not Found\",\n \"documentation_url\": \"https://docs.github.com/rest\"\n}\n\n\n\n\nsource\n\n\nurlread\n\n urlread (url, data=None, headers=None, decode=True, return_json=False,\n return_headers=False, timeout=None, **kwargs)\n\nRetrieve url, using data dict or kwargs to POST if present\n\nsource\n\n\nurljson\n\n urljson (url, data=None, timeout=None)\n\nRetrieve url and decode json\n\ntest_eq(urljson('https://httpbin.org/get')['headers']['User-Agent'], url_default_headers['User-Agent'])\n\n\nsource\n\n\nurlcheck\n\n urlcheck (url, headers=None, timeout=10)\n\n\nsource\n\n\nurlclean\n\n urlclean (url)\n\nRemove fragment, params, and querystring from url if present\n\ntest_eq(urlclean('http://a.com/b?c=1#d'), 'http://a.com/b')\n\n\nsource\n\n\nurlretrieve\n\n urlretrieve (url, filename=None, reporthook=None, data=None,\n headers=None, timeout=None)\n\nSame as urllib.request.urlretrieve but also works with Request objects\n\nsource\n\n\nurldest\n\n urldest (url, dest=None)\n\n\nsource\n\n\nurlsave\n\n urlsave (url, dest=None, reporthook=None, headers=None, timeout=None)\n\nRetrieve url and save based on its name\n\n#skip\nwith tempfile.TemporaryDirectory() as d: urlsave('http://www.google.com/index.html', d)\n\n\nsource\n\n\nurlvalid\n\n urlvalid (x)\n\nTest if x is a valid URL\n\nassert urlvalid('http://www.google.com/')\nassert not urlvalid('www.google.com/')\nassert not urlvalid(1)\n\n\nsource\n\n\nurlrequest\n\n urlrequest (url, verb, headers=None, route=None, query=None, data=None,\n json_data=True)\n\nRequest for url with optional route params replaced by route, plus query string, and post data\n\nhdr = {'Hdr1':'1', 'Hdr2':'2'}\nreq = urlrequest('http://example.com/{foo}/1', 'POST',\n headers=hdr, route={'foo':'3'}, query={'q':'4'}, data={'d':'5'})\n\ntest_eq(req.headers, hdr)\ntest_eq(req.full_url, 'http://example.com/3/1?q=4')\ntest_eq(req.method, 'POST')\ntest_eq(req.data, b'{\"d\": \"5\"}')\n\n\nreq = urlrequest('http://example.com/{foo}/1', 'POST', data={'d':'5','e':'6'}, headers=hdr, json_data=False)\ntest_eq(req.data, b'd=5&e=6')\n\n\nsource\n\n\nRequest.summary\n\n Request.summary (skip=None)\n\nSummary containing full_url, headers, method, and data, removing skip from headers\n\nreq.summary(skip='Hdr1')\n\n{'full_url': 'http://example.com/{foo}/1',\n 'method': 'POST',\n 'data': b'd=5&e=6',\n 'headers': {'Hdr2': '2'}}\n\n\n\nsource\n\n\nurlsend\n\n urlsend (url, verb, headers=None, route=None, query=None, data=None,\n json_data=True, return_json=True, return_headers=False,\n debug=None, timeout=None)\n\nSend request with urlrequest, converting result to json if return_json\n\nsource\n\n\ndo_request\n\n do_request (url, post=False, headers=None, **data)\n\nCall GET or json-encoded POST on url, depending on post", + "crumbs": [ + "Network functionality" + ] + }, + { + "objectID": "net.html#basic-clientserver", + "href": "net.html#basic-clientserver", + "title": "Network functionality", + "section": "Basic client/server", + "text": "Basic client/server\n\nsource\n\nstart_server\n\n start_server (port, host=None, dgram=False, reuse_addr=True,\n n_queue=None)\n\nCreate a socket server on port, with optional host, of type dgram\nYou can create a TCP client and server pass an int as port and optional host. host defaults to your main network interface if not provided. You can create a Unix socket client and server by passing a string to port. A SOCK_STREAM socket is created by default, unless you pass dgram=True, in which case a SOCK_DGRAM socket is created. n_queue sets the listening queue size.\n\nsource\n\n\nstart_client\n\n start_client (port, host=None, dgram=False)\n\nCreate a socket client on port, with optional host, of type dgram\n\nsource\n\n\ntobytes\n\n tobytes (s:str)\n\nConvert s into HTTP-ready bytes format\n\ntest_eq(tobytes('foo\\nbar'), b'foo\\r\\nbar')\n\n\nsource\n\n\nhttp_response\n\n http_response (body=None, status=200, hdrs=None, **kwargs)\n\nCreate an HTTP-ready response, adding kwargs to hdrs\n\nexp = b'HTTP/1.1 200 OK\\r\\nUser-Agent: me\\r\\nContent-Length: 4\\r\\n\\r\\nbody'\ntest_eq(http_response('body', 200, User_Agent='me'), exp)\n\n\nsource\n\n\nrecv_once\n\n recv_once (host:str='localhost', port:int=8000)\n\nSpawn a thread to receive a single HTTP request and store in d['r']", + "crumbs": [ + "Network functionality" + ] + }, + { + "objectID": "test.html", + "href": "test.html", + "title": "Test", + "section": "", + "text": "We can check that code raises an exception when that’s expected (test_fail).\nTo test for equality or inequality (with different types of things) we define a simple function test that compares two objects with a given cmp operator.\n\nsource\n\n\n\n test_fail (f, msg='', contains='', args=None, kwargs=None)\n\nFails with msg unless f() raises an exception and (optionally) has contains in e.args\n\ndef _fail(): raise Exception(\"foobar\")\ntest_fail(_fail, contains=\"foo\")\n\ndef _fail(): raise Exception()\ntest_fail(_fail)\n\nWe can also pass args and kwargs to function to check if it fails with special inputs.\n\ndef _fail_args(a):\n if a == 5:\n raise ValueError\ntest_fail(_fail_args, args=(5,))\ntest_fail(_fail_args, kwargs=dict(a=5))\n\n\nsource\n\n\n\n\n test (a, b, cmp, cname=None)\n\nassert that cmp(a,b); display inputs and cname or cmp.__name__ if it fails\n\ntest([1,2],[1,2], operator.eq)\ntest_fail(lambda: test([1,2],[1], operator.eq))\ntest([1,2],[1], operator.ne)\ntest_fail(lambda: test([1,2],[1,2], operator.ne))\n\n\n\n\n\n\n all_equal (a, b)\n\nCompares whether a and b are the same length and have the same contents\n\ntest(['abc'], ['abc'], all_equal)\ntest_fail(lambda: test(['abc'],['cab'], all_equal))\n\n\n\n\n\n\n equals (a, b)\n\nCompares a and b for equality; supports sublists, tensors and arrays too\n\ntest([['abc'],['a']], [['abc'],['a']], equals)\ntest([['abc'],['a'],'b', [['x']]], [['abc'],['a'],'b', [['x']]], equals) # supports any depth and nested structure\n\n\nsource\n\n\n\n\n nequals (a, b)\n\nCompares a and b for not equals\n\ntest(['abc'], ['ab' ], nequals)", + "crumbs": [ + "Test" + ] + }, + { + "objectID": "test.html#simple-test-functions", + "href": "test.html#simple-test-functions", + "title": "Test", + "section": "", + "text": "We can check that code raises an exception when that’s expected (test_fail).\nTo test for equality or inequality (with different types of things) we define a simple function test that compares two objects with a given cmp operator.\n\nsource\n\n\n\n test_fail (f, msg='', contains='', args=None, kwargs=None)\n\nFails with msg unless f() raises an exception and (optionally) has contains in e.args\n\ndef _fail(): raise Exception(\"foobar\")\ntest_fail(_fail, contains=\"foo\")\n\ndef _fail(): raise Exception()\ntest_fail(_fail)\n\nWe can also pass args and kwargs to function to check if it fails with special inputs.\n\ndef _fail_args(a):\n if a == 5:\n raise ValueError\ntest_fail(_fail_args, args=(5,))\ntest_fail(_fail_args, kwargs=dict(a=5))\n\n\nsource\n\n\n\n\n test (a, b, cmp, cname=None)\n\nassert that cmp(a,b); display inputs and cname or cmp.__name__ if it fails\n\ntest([1,2],[1,2], operator.eq)\ntest_fail(lambda: test([1,2],[1], operator.eq))\ntest([1,2],[1], operator.ne)\ntest_fail(lambda: test([1,2],[1,2], operator.ne))\n\n\n\n\n\n\n all_equal (a, b)\n\nCompares whether a and b are the same length and have the same contents\n\ntest(['abc'], ['abc'], all_equal)\ntest_fail(lambda: test(['abc'],['cab'], all_equal))\n\n\n\n\n\n\n equals (a, b)\n\nCompares a and b for equality; supports sublists, tensors and arrays too\n\ntest([['abc'],['a']], [['abc'],['a']], equals)\ntest([['abc'],['a'],'b', [['x']]], [['abc'],['a'],'b', [['x']]], equals) # supports any depth and nested structure\n\n\nsource\n\n\n\n\n nequals (a, b)\n\nCompares a and b for not equals\n\ntest(['abc'], ['ab' ], nequals)", + "crumbs": [ + "Test" + ] + }, + { + "objectID": "test.html#test_eq-test_ne-etc", + "href": "test.html#test_eq-test_ne-etc", + "title": "Test", + "section": "test_eq test_ne, etc…", + "text": "test_eq test_ne, etc…\nJust use test_eq/test_ne to test for ==/!=. test_eq_type checks things are equal and of the same type. We define them using test:\n\nsource\n\ntest_eq\n\n test_eq (a, b)\n\ntest that a==b\n\ntest_eq([1,2],[1,2])\ntest_eq([1,2],map(int,[1,2]))\ntest_eq(array([1,2]),array([1,2]))\ntest_eq(array([1,2]),array([1,2]))\ntest_eq([array([1,2]),3],[array([1,2]),3])\ntest_eq(dict(a=1,b=2), dict(b=2,a=1))\ntest_fail(lambda: test_eq([1,2], 1), contains=\"==\")\ntest_fail(lambda: test_eq(None, np.array([1,2])), contains=\"==\")\ntest_eq({'a', 'b', 'c'}, {'c', 'a', 'b'})\n\n\ndf1 = pd.DataFrame(dict(a=[1,2],b=['a','b']))\ndf2 = pd.DataFrame(dict(a=[1,2],b=['a','b']))\ndf3 = pd.DataFrame(dict(a=[1,2],b=['a','c']))\n\ntest_eq(df1,df2)\ntest_eq(df1.a,df2.a)\ntest_fail(lambda: test_eq(df1,df3), contains='==')\nclass T(pd.Series): pass\ntest_eq(df1.iloc[0], T(df2.iloc[0])) # works with subclasses\n\n\ntest_eq(torch.zeros(10), torch.zeros(10, dtype=torch.float64))\ntest_eq(torch.zeros(10), torch.ones(10)-1)\ntest_fail(lambda:test_eq(torch.zeros(10), torch.ones(1, 10)), contains='==')\ntest_eq(torch.zeros(3), [0,0,0])\n\n\nsource\n\n\ntest_eq_type\n\n test_eq_type (a, b)\n\ntest that a==b and are same type\n\ntest_eq_type(1,1)\ntest_fail(lambda: test_eq_type(1,1.))\ntest_eq_type([1,1],[1,1])\ntest_fail(lambda: test_eq_type([1,1],(1,1)))\ntest_fail(lambda: test_eq_type([1,1],[1,1.]))\n\n\nsource\n\n\ntest_ne\n\n test_ne (a, b)\n\ntest that a!=b\n\ntest_ne([1,2],[1])\ntest_ne([1,2],[1,3])\ntest_ne(array([1,2]),array([1,1]))\ntest_ne(array([1,2]),array([1,1]))\ntest_ne([array([1,2]),3],[array([1,2])])\ntest_ne([3,4],array([3]))\ntest_ne([3,4],array([3,5]))\ntest_ne(dict(a=1,b=2), ['a', 'b'])\ntest_ne(['a', 'b'], dict(a=1,b=2))\n\n\nsource\n\n\nis_close\n\n is_close (a, b, eps=1e-05)\n\nIs a within eps of b\n\nsource\n\n\ntest_close\n\n test_close (a, b, eps=1e-05)\n\ntest that a is within eps of b\n\ntest_close(1,1.001,eps=1e-2)\ntest_fail(lambda: test_close(1,1.001))\ntest_close([-0.001,1.001], [0.,1.], eps=1e-2)\ntest_close(np.array([-0.001,1.001]), np.array([0.,1.]), eps=1e-2)\ntest_close(array([-0.001,1.001]), array([0.,1.]), eps=1e-2)\n\n\nsource\n\n\ntest_is\n\n test_is (a, b)\n\ntest that a is b\n\ntest_fail(lambda: test_is([1], [1]))\na = [1]\ntest_is(a, a)\nb = [2]; test_fail(lambda: test_is(a, b))\n\n\nsource\n\n\ntest_shuffled\n\n test_shuffled (a, b)\n\ntest that a and b are shuffled versions of the same sequence of items\n\na = list(range(50))\nb = copy(a)\nrandom.shuffle(b)\ntest_shuffled(a,b)\ntest_fail(lambda:test_shuffled(a,a))\n\n\na = 'abc'\nb = 'abcabc'\ntest_fail(lambda:test_shuffled(a,b))\n\n\na = ['a', 42, True] \nb = [42, True, 'a']\ntest_shuffled(a,b)\n\n\nsource\n\n\ntest_stdout\n\n test_stdout (f, exp, regex=False)\n\nTest that f prints exp to stdout, optionally checking as regex\n\ntest_stdout(lambda: print('hi'), 'hi')\ntest_fail(lambda: test_stdout(lambda: print('hi'), 'ho'))\ntest_stdout(lambda: 1+1, '')\ntest_stdout(lambda: print('hi there!'), r'^hi.*!$', regex=True)\n\n\nsource\n\n\ntest_warns\n\n test_warns (f, show=False)\n\n\ntest_warns(lambda: warnings.warn(\"Oh no!\"))\ntest_fail(lambda: test_warns(lambda: 2+2), contains='No warnings raised')\n\n\ntest_warns(lambda: warnings.warn(\"Oh no!\"), show=True)\n\n<class 'UserWarning'>: Oh no!\n\n\n\nim = Image.open(TEST_IMAGE).resize((128,128)); im\n\n\n\n\n\n\n\n\n\nim = Image.open(TEST_IMAGE_BW).resize((128,128)); im\n\n\n\n\n\n\n\n\n\nsource\n\n\ntest_fig_exists\n\n test_fig_exists (ax)\n\nTest there is a figure displayed in ax\n\nfig,ax = plt.subplots()\nax.imshow(array(im));\n\n\n\n\n\n\n\n\n\ntest_fig_exists(ax)\n\n\nsource\n\n\nExceptionExpected\n\n ExceptionExpected (ex=<class 'Exception'>, regex='')\n\nContext manager that tests if an exception is raised\n\ndef _tst_1(): assert False, \"This is a test\"\ndef _tst_2(): raise SyntaxError\n\nwith ExceptionExpected(): _tst_1()\nwith ExceptionExpected(ex=AssertionError, regex=\"This is a test\"): _tst_1()\nwith ExceptionExpected(ex=SyntaxError): _tst_2()\n\nexception is an abbreviation for ExceptionExpected().\n\nwith exception: _tst_1()", + "crumbs": [ + "Test" + ] + }, + { + "objectID": "xdg.html", + "href": "xdg.html", + "title": "XDG", + "section": "", + "text": "See the XDG Base Directory Specification for more information.", + "crumbs": [ + "XDG" + ] + }, + { + "objectID": "xdg.html#overview", + "href": "xdg.html#overview", + "title": "XDG", + "section": "Overview", + "text": "Overview\nxdg_cache_home, xdg_config_home, xdg_data_home, and xdg_state_home return pathlib.Path objects containing the value of the environment variable named XDG_CACHE_HOME, XDG_CONFIG_HOME, XDG_DATA_HOME, and XDG_STATE_HOME respectively, or the default defined in the specification if the environment variable is unset, empty, or contains a relative path rather than absolute path.\nxdg_config_dirs and xdg_data_dirs return a list of pathlib.Path objects containing the value, split on colons, of the environment variable named XDG_CONFIG_DIRS and XDG_DATA_DIRS respectively, or the default defined in the specification if the environment variable is unset or empty. Relative paths are ignored, as per the specification.\nxdg_runtime_dir returns a pathlib.Path object containing the value of the XDG_RUNTIME_DIR environment variable, or None if the environment variable is not set, or contains a relative path rather than absolute path.", + "crumbs": [ + "XDG" + ] + }, + { + "objectID": "xdg.html#helpers", + "href": "xdg.html#helpers", + "title": "XDG", + "section": "Helpers", + "text": "Helpers\nWe’ll start by defining a context manager that temporarily sets an environment variable to demonstrate the behaviour of each helper function:\n\nfrom contextlib import contextmanager\n\n\n@contextmanager\ndef env(variable, value):\n old = os.environ.get(variable, None)\n try:\n os.environ[variable] = value\n yield\n finally:\n if old is None: del os.environ[variable]\n else: os.environ[variable] = old\n\n\nsource\n\nxdg_cache_home\n\n xdg_cache_home ()\n\nPath corresponding to XDG_CACHE_HOME\n\nfrom fastcore.test import *\n\n\ntest_eq(xdg_cache_home(), Path.home()/'.cache')\nwith env('XDG_CACHE_HOME', '/home/fastai/.cache'):\n test_eq(xdg_cache_home(), Path('/home/fastai/.cache'))\n\n\nsource\n\n\nxdg_config_dirs\n\n xdg_config_dirs ()\n\nPaths corresponding to XDG_CONFIG_DIRS\n\ntest_eq(xdg_config_dirs(), [Path('/etc/xdg')])\nwith env('XDG_CONFIG_DIRS', '/home/fastai/.xdg:/home/fastai/.config'):\n test_eq(xdg_config_dirs(), [Path('/home/fastai/.xdg'), Path('/home/fastai/.config')])\n\n\nsource\n\n\nxdg_config_home\n\n xdg_config_home ()\n\nPath corresponding to XDG_CONFIG_HOME\n\ntest_eq(xdg_config_home(), Path.home()/'.config')\nwith env('XDG_CONFIG_HOME', '/home/fastai/.config'):\n test_eq(xdg_config_home(), Path('/home/fastai/.config'))\n\n\nsource\n\n\nxdg_data_dirs\n\n xdg_data_dirs ()\n\nPaths corresponding to XDG_DATA_DIRS`\n\nsource\n\n\nxdg_data_home\n\n xdg_data_home ()\n\nPath corresponding to XDG_DATA_HOME\n\ntest_eq(xdg_data_home(), Path.home()/'.local/share')\nwith env('XDG_DATA_HOME', '/home/fastai/.data'):\n test_eq(xdg_data_home(), Path('/home/fastai/.data'))\n\n\nsource\n\n\nxdg_runtime_dir\n\n xdg_runtime_dir ()\n\nPath corresponding to XDG_RUNTIME_DIR\n\nsource\n\n\nxdg_state_home\n\n xdg_state_home ()\n\nPath corresponding to XDG_STATE_HOME\n\ntest_eq(xdg_state_home(), Path.home()/'.local/state')\nwith env('XDG_STATE_HOME', '/home/fastai/.state'):\n test_eq(xdg_state_home(), Path('/home/fastai/.state'))\n\n\nCopyright © 2016-2021 Scott Stevenson scott@stevenson.io\nModifications copyright © 2022 onwards Jeremy Howard", + "crumbs": [ + "XDG" + ] + }, + { + "objectID": "meta.html", + "href": "meta.html", + "title": "Meta", + "section": "", + "text": "from fastcore.foundation import *\nfrom nbdev.showdoc import *\nfrom fastcore.nb_imports import *\nSee this blog post for more information about metaclasses.\nsource", + "crumbs": [ + "Meta" + ] + }, + { + "objectID": "meta.html#metaprogramming", + "href": "meta.html#metaprogramming", + "title": "Meta", + "section": "Metaprogramming", + "text": "Metaprogramming\n\nsource\n\nempty2none\n\n empty2none (p)\n\nReplace Parameter.empty with None\n\nsource\n\n\nanno_dict\n\n anno_dict (f)\n\n__annotation__ dictionary withemptycast toNone`, returning empty if doesn’t exist\n\ndef _f(a:int, b:L)->str: ...\ntest_eq(anno_dict(_f), {'a': int, 'b': L, 'return': str})\n\n\nsource\n\n\nuse_kwargs_dict\n\n use_kwargs_dict (keep=False, **kwargs)\n\nDecorator: replace **kwargs in signature with names params\nReplace all **kwargs with named arguments like so:\n\n@use_kwargs_dict(y=1,z=None)\ndef foo(a, b=1, **kwargs): pass\n\ntest_sig(foo, '(a, b=1, *, y=1, z=None)')\n\nAdd named arguments, but optionally keep **kwargs by setting keep=True:\n\n@use_kwargs_dict(y=1,z=None, keep=True)\ndef foo(a, b=1, **kwargs): pass\n\ntest_sig(foo, '(a, b=1, *, y=1, z=None, **kwargs)')\n\n\nsource\n\n\nuse_kwargs\n\n use_kwargs (names, keep=False)\n\nDecorator: replace **kwargs in signature with names params\nuse_kwargs is different than use_kwargs_dict as it only replaces **kwargs with named parameters without any default values:\n\n@use_kwargs(['y', 'z'])\ndef foo(a, b=1, **kwargs): pass\n\ntest_sig(foo, '(a, b=1, *, y=None, z=None)')\n\nYou may optionally keep the **kwargs argument in your signature by setting keep=True:\n\n@use_kwargs(['y', 'z'], keep=True)\ndef foo(a, *args, b=1, **kwargs): pass\ntest_sig(foo, '(a, *args, b=1, y=None, z=None, **kwargs)')\n\n\nsource\n\n\ndelegates\n\n delegates (to:function=None, keep=False, but:list=None)\n\nDecorator: replace **kwargs in signature with params from to\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nto\nfunction\nNone\nDelegatee\n\n\nkeep\nbool\nFalse\nKeep kwargs in decorated function?\n\n\nbut\nlist\nNone\nExclude these parameters from signature\n\n\n\nA common Python idiom is to accept **kwargs in addition to named parameters that are passed onto other function calls. It is especially common to use **kwargs when you want to give the user an option to override default parameters of any functions or methods being called by the parent function.\nFor example, suppose we have have a function foo that passes arguments to baz like so:\n\ndef baz(a, b:int=2, c:int=3): return a + b + c\n\ndef foo(c, a, **kwargs):\n return c + baz(a, **kwargs)\n\nassert foo(c=1, a=1) == 7\n\nThe problem with this approach is the api for foo is obfuscated. Users cannot introspect what the valid arguments for **kwargs are without reading the source code. When a user tries tries to introspect the signature of foo, they are presented with this:\n\ninspect.signature(foo)\n\n<Signature (c, a, **kwargs)>\n\n\nWe can address this issue by using the decorator delegates to include parameters from other functions. For example, if we apply the delegates decorator to foo to include parameters from baz:\n\n@delegates(baz)\ndef foo(c, a, **kwargs):\n return c + baz(a, **kwargs)\n\ntest_sig(foo, '(c, a, *, b: int = 2)')\ninspect.signature(foo)\n\n<Signature (c, a, *, b: int = 2)>\n\n\nWe can optionally decide to keep **kwargs by setting keep=True:\n\n@delegates(baz, keep=True)\ndef foo(c, a, **kwargs):\n return c + baz(a, **kwargs)\n\ninspect.signature(foo)\n\n<Signature (c, a, *, b: int = 2, **kwargs)>\n\n\nIt is important to note that only parameters with default parameters are included. For example, in the below scenario only c, but NOT e and d are included in the signature of foo after applying delegates:\n\ndef basefoo(e, d, c=2): pass\n\n@delegates(basefoo)\ndef foo(a, b=1, **kwargs): pass\ninspect.signature(foo) # e and d are not included b/c they don't have default parameters.\n\n<Signature (a, b=1, *, c=2)>\n\n\nThe reason that required arguments (i.e. those without default parameters) are automatically excluded is that you should be explicitly implementing required arguments into your function’s signature rather than relying on delegates.\nAdditionally, you can exclude specific parameters from being included in the signature with the but parameter. In the example below, we exclude the parameter d:\n\ndef basefoo(e, c=2, d=3): pass\n\n@delegates(basefoo, but= ['d'])\ndef foo(a, b=1, **kwargs): pass\n\ntest_sig(foo, '(a, b=1, *, c=2)')\ninspect.signature(foo)\n\n<Signature (a, b=1, *, c=2)>\n\n\nYou can also use delegates between methods in a class. Here is an example of delegates with class methods:\n\n# example 1: class methods\nclass _T():\n @classmethod\n def foo(cls, a=1, b=2):\n pass\n \n @classmethod\n @delegates(foo)\n def bar(cls, c=3, **kwargs):\n pass\n\ntest_sig(_T.bar, '(c=3, *, a=1, b=2)')\n\nHere is the same example with instance methods:\n\n# example 2: instance methods\nclass _T():\n def foo(self, a=1, b=2):\n pass\n \n @delegates(foo)\n def bar(self, c=3, **kwargs):\n pass\n\nt = _T()\ntest_sig(t.bar, '(c=3, *, a=1, b=2)')\n\nYou can also delegate between classes. By default, the delegates decorator will delegate to the superclass:\n\nclass BaseFoo:\n def __init__(self, e, c=2): pass\n\n@delegates()# since no argument was passsed here we delegate to the superclass\nclass Foo(BaseFoo):\n def __init__(self, a, b=1, **kwargs): super().__init__(**kwargs)\n\ntest_sig(Foo, '(a, b=1, *, c=2)')\n\n\nsource\n\n\nmethod\n\n method (f)\n\nMark f as a method\nThe method function is used to change a function’s type to a method. In the below example we change the type of a from a function to a method:\n\ndef a(x=2): return x + 1\nassert type(a).__name__ == 'function'\n\na = method(a)\nassert type(a).__name__ == 'method'\n\n\nsource\n\n\nfuncs_kwargs\n\n funcs_kwargs (as_method=False)\n\nReplace methods in cls._methods with those from kwargs\nThe func_kwargs decorator allows you to add a list of functions or methods to an existing class. You must set this list as a class attribute named _methods when defining your class. Additionally, you must incldue the **kwargs argument in the ___init__ method of your class.\nAfter defining your class this way, you can add functions to your class upon instantation as illusrated below.\nFor example, we define class T to allow adding the function b to class T as follows (note that this function is stored as an attribute of T and doesn’t have access to cls or self):\n\n@funcs_kwargs\nclass T:\n _methods=['b'] # allows you to add method b upon instantiation\n def __init__(self, f=1, **kwargs): pass # don't forget to include **kwargs in __init__\n def a(self): return 1\n def b(self): return 2\n \nt = T()\ntest_eq(t.a(), 1)\ntest_eq(t.b(), 2)\n\nBecause we defined the class T this way, the signature of T indicates the option to add the function or method(s) specified in _methods. In this example, b is added to the signature:\n\ntest_sig(T, '(f=1, *, b=None)')\ninspect.signature(T)\n\n<Signature (f=1, *, b=None)>\n\n\nYou can now add the function b to class T upon instantiation:\n\ndef _new_func(): return 5\n\nt = T(b = _new_func)\ntest_eq(t.b(), 5)\n\nIf you try to add a function with a name not listed in _methods it will be ignored. In the below example, the attempt to add a function named a is ignored:\n\nt = T(a = lambda:3)\ntest_eq(t.a(), 1) # the attempt to add a is ignored and uses the original method instead.\n\nNote that you can also add methods not defined in the original class as long it is specified in the _methods attribute:\n\n@funcs_kwargs\nclass T:\n _methods=['c']\n def __init__(self, f=1, **kwargs): pass\n\nt = T(c = lambda: 4)\ntest_eq(t.c(), 4)\n\nUntil now, these examples showed how to add functions stored as an instance attribute without access to self. However, if you need access to self you can set as_method=True in the func_kwargs decorator to add a method instead:\n\ndef _f(self,a=1): return self.num + a # access the num attribute from the instance\n\n@funcs_kwargs(as_method=True)\nclass T: \n _methods=['b']\n num = 5\n \nt = T(b = _f) # adds method b\ntest_eq(t.b(5), 10) # self.num + 5 = 10\n\nHere is an example of how you might use this functionality with inheritence:\n\ndef _f(self,a=1): return self.num * a #multiply instead of add \n\nclass T2(T):\n def __init__(self,num):\n super().__init__(b = _f) # add method b from the super class\n self.num=num\n \nt = T2(num=3)\ntest_eq(t.b(a=5), 15) # 3 * 5 = 15\ntest_sig(T2, '(num)')", + "crumbs": [ + "Meta" + ] + }, + { + "objectID": "script.html", + "href": "script.html", + "title": "Script - CLI", + "section": "", + "text": "Part of fast.ai’s toolkit for delightful developer experiences.", + "crumbs": [ + "Script - CLI" + ] + }, + { + "objectID": "script.html#overview", + "href": "script.html#overview", + "title": "Script - CLI", + "section": "Overview", + "text": "Overview\nSometimes, you want to create a quick script, either for yourself, or for others. But in Python, that involves a whole lot of boilerplate and ceremony, especially if you want to support command line arguments, provide help, and other niceties. You can use argparse for this purpose, which comes with Python, but it’s complex and verbose.\nfastcore.script makes life easier. There are much fancier modules to help you write scripts (we recommend Python Fire, and Click is also popular), but fastcore.script is very fast and very simple. In fact, it’s <50 lines of code! Basically, it’s just a little wrapper around argparse that uses modern Python features and some thoughtful defaults to get rid of the boilerplate.\nFor full details, see the docs for core.", + "crumbs": [ + "Script - CLI" + ] + }, + { + "objectID": "script.html#example", + "href": "script.html#example", + "title": "Script - CLI", + "section": "Example", + "text": "Example\nHere’s a complete example (available in examples/test_fastcore.py):\nfrom fastcore.script import *\n@call_parse\ndef main(msg:str, # The message\n upper:bool): # Convert to uppercase?\n \"Print `msg`, optionally converting to uppercase\"\n print(msg.upper() if upper else msg)\nIf you copy that info a file and run it, you’ll see:\n$ examples/test_fastcore.py --help\nusage: test_fastcore.py [-h] [--upper] msg\n\nPrint `msg`, optionally converting to uppercase\n\npositional arguments:\n msg The message\n\noptional arguments:\n -h, --help show this help message and exit\n --upper Convert to uppercase? (default: False)\nAs you see, we didn’t need any if __name__ == \"__main__\", we didn’t have to parse arguments, we just wrote a function, added a decorator to it, and added some annotations to our function’s parameters. As a bonus, we can also use this function directly from a REPL such as Jupyter Notebook - it’s not just for command line scripts!\nYou should provide a default (after the =) for any optional parameters. If you don’t provide a default for a parameter, then it will be a positional parameter.", + "crumbs": [ + "Script - CLI" + ] + }, + { + "objectID": "script.html#param-annotations", + "href": "script.html#param-annotations", + "title": "Script - CLI", + "section": "Param annotations", + "text": "Param annotations\nIf you want to use the full power of argparse, you can do so by using Param annotations instead of type annotations and docments, like so:\nfrom fastcore.script import *\n@call_parse\ndef main(msg:Param(\"The message\", str),\n upper:Param(\"Convert to uppercase?\", store_true)):\n \"Print `msg`, optionally converting to uppercase\"\n print(msg.upper() if upper else msg)\nIf you use this approach, then each parameter in your function should have an annotation Param(...) (as in the example above). You can pass the following when calling Param: help,type,opt,action,nargs,const,choices,required . Except for opt, all of these are just passed directly to argparse, so you have all the power of that module at your disposal. Generally you’ll want to pass at least help (since this is provided as the help string for that parameter) and type (to ensure that you get the type of data you expect). opt is a bool that defines whether a param is optional or required (positional) - but you’ll generally not need to set this manually, because fastcore.script will set it for you automatically based on default values.", + "crumbs": [ + "Script - CLI" + ] + }, + { + "objectID": "script.html#setuptools-scripts", + "href": "script.html#setuptools-scripts", + "title": "Script - CLI", + "section": "setuptools scripts", + "text": "setuptools scripts\nThere’s a really nice feature of pip/setuptools that lets you create commandline scripts directly from functions, makes them available in the PATH, and even makes your scripts cross-platform (e.g. in Windows it creates an exe). fastcore.script supports this feature too. The trick to making a function available as a script is to add a console_scripts section to your setup file, of the form: script_name=module:function_name. E.g. in this case we use: test_fastcore.script=fastcore.script.test_cli:main. With this, you can then just type test_fastcore.script at any time, from any directory, and your script will be called (once it’s installed using one of the methods below).\nYou don’t actually have to write a setup.py yourself. Instead, just use nbdev. Then modify settings.ini as appropriate for your module/script. To install your script directly, you can type pip install -e .. Your script, when installed this way (it’s called an editable install), will automatically be up to date even if you edit it - there’s no need to reinstall it after editing. With nbdev you can even make your module and script available for installation directly from pip and conda by running make release.", + "crumbs": [ + "Script - CLI" + ] + }, + { + "objectID": "script.html#api-details", + "href": "script.html#api-details", + "title": "Script - CLI", + "section": "API details", + "text": "API details\n\nsource\n\nstore_true\n\n store_true ()\n\nPlaceholder to pass to Param for store_true action\n\nsource\n\n\nstore_false\n\n store_false ()\n\nPlaceholder to pass to Param for store_false action\n\nsource\n\n\nbool_arg\n\n bool_arg (v)\n\nUse as type for Param to get bool behavior\n\nsource\n\n\nclean_type_str\n\n clean_type_str (x:str)\n\n\nclass Test: pass\n\ntest_eq(clean_type_str(argparse.ArgumentParser), 'argparse.ArgumentParser')\ntest_eq(clean_type_str(Test), 'Test')\ntest_eq(clean_type_str(int), 'int')\ntest_eq(clean_type_str(float), 'float')\ntest_eq(clean_type_str(store_false), 'store_false')\n\n\nsource\n\n\nParam\n\n Param (help='', type=None, opt=True, action=None, nargs=None, const=None,\n choices=None, required=None, default=None)\n\nA parameter in a function used in anno_parser or call_parse\n\ntest_eq(repr(Param(\"Help goes here\")), '<Help goes here>')\ntest_eq(repr(Param(\"Help\", int)), 'int <Help>')\ntest_eq(repr(Param(help=None, type=int)), 'int')\ntest_eq(repr(Param(help=None, type=None)), '')\n\nEach parameter in your function should have an annotation Param(...). You can pass the following when calling Param: help,type,opt,action,nargs,const,choices,required (i.e. it takes the same parameters as argparse.ArgumentParser.add_argument, plus opt). Except for opt, all of these are just passed directly to argparse, so you have all the power of that module at your disposal. Generally you’ll want to pass at least help (since this is provided as the help string for that parameter) and type (to ensure that you get the type of data you expect).\nopt is a bool that defines whether a param is optional or required (positional) - but you’ll generally not need to set this manually, because fastcore.script will set it for you automatically based on default values. You should provide a default (after the =) for any optional parameters. If you don’t provide a default for a parameter, then it will be a positional parameter.\nParam’s __repr__ also allows for more informative function annotation when looking up the function’s doc using shift+tab. You see the type annotation (if there is one) and the accompanying help documentation with it.\n\ndef f(required:Param(\"Required param\", int),\n a:Param(\"param 1\", bool_arg),\n b:Param(\"param 2\", str)=\"test\"):\n \"my docs\"\n ...\n\n\nhelp(f)\n\nHelp on function f in module __main__:\n\nf(required: int <Required param>, a: bool_arg <param 1>, b: str <param 2> = 'test')\n my docs\n\n\n\n\np = Param(help=\"help\", type=int)\np.set_default(1)\ntest_eq(p.kwargs, {'help': 'help (default: 1)', 'type': int, 'default': 1})\n\n\nsource\n\n\nanno_parser\n\n anno_parser (func, prog:str=None)\n\nLook at params (annotated with Param) in func and return an ArgumentParser\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nfunc\n\n\nFunction to get arguments from\n\n\nprog\nstr\nNone\nThe name of the program\n\n\n\nThis converts a function with parameter annotations of type Param into an argparse.ArgumentParser object. Function arguments with a default provided are optional, and other arguments are positional.\n\n_en = str_enum('_en', 'aa','bb','cc')\ndef f(required:Param(\"Required param\", int),\n a:Param(\"param 1\", bool_arg),\n b:Param(\"param 2\", str)=\"test\",\n c:Param(\"param 3\", _en)=_en.aa):\n \"my docs\"\n ...\n\np = anno_parser(f, 'progname')\np.print_help()\n\nusage: progname [-h] [--b B] [--c {aa,bb,cc}] required a\n\nmy docs\n\npositional arguments:\n required Required param\n a param 1\n\noptional arguments:\n -h, --help show this help message and exit\n --b B param 2 (default: test)\n --c {aa,bb,cc} param 3 (default: aa)\n\n\nIt also works with type annotations and docments:\n\ndef g(required:int, # Required param\n a:bool_arg, # param 1\n b=\"test\", # param 2\n c:_en=_en.aa): # param 3\n \"my docs\"\n ...\n\np = anno_parser(g, 'progname')\np.print_help()\n\nusage: progname [-h] [--b B] [--c {aa,bb,cc}] required a\n\nmy docs\n\npositional arguments:\n required Required param\n a param 1\n\noptional arguments:\n -h, --help show this help message and exit\n --b B param 2 (default: test)\n --c {aa,bb,cc} param 3 (default: aa)\n\n\n\nsource\n\n\nargs_from_prog\n\n args_from_prog (func, prog)\n\nExtract args from prog\nSometimes it’s convenient to extract arguments from the actual name of the called program. args_from_prog will do this, assuming that names and values of the params are separated by a #. Optionally there can also be a prefix separated by ## (double underscore).\n\nexp = {'a': False, 'b': 'baa'}\ntest_eq(args_from_prog(f, 'foo##a#0#b#baa'), exp)\ntest_eq(args_from_prog(f, 'a#0#b#baa'), exp)\n\n\nsource\n\n\ncall_parse\n\n call_parse (func=None, nested=False)\n\nDecorator to create a simple CLI from func using anno_parser\n\n@call_parse\ndef test_add(\n a:int=0, # param a\n b:int=0 # param 1\n):\n \"Add up `a` and `b`\"\n return a + b\n\ncall_parse decorated functions work as regular functions and also as command-line interface functions.\n\ntest_eq(test_add(1,2), 3)\n\nThis is the main way to use fastcore.script; decorate your function with call_parse, add Param annotations (as shown above) or type annotations and docments, and it can then be used as a script.\nUse the nested keyword argument to create nested parsers, where earlier parsers consume only their known args from sys.argv before later parsers are used. This is useful to create one command line application that executes another. For example:\nmyrunner --keyword 1 script.py -- <script.py args>\nA separating -- after the first application’s args is recommended though not always required, otherwise args may be parsed in unexpected ways. For example:\nmyrunner script.py -h\nwould display myrunner’s help and not script.py’s.", + "crumbs": [ + "Script - CLI" + ] + }, + { + "objectID": "parallel.html", + "href": "parallel.html", + "title": "Parallel", + "section": "", + "text": "from fastcore.test import *\nfrom nbdev.showdoc import *\nfrom fastcore.nb_imports import *\n\n\nsource\n\nthreaded\n\n threaded (process=False)\n\nRun f in a Thread (or Process if process=True), and returns it\n\n@threaded\ndef _1():\n time.sleep(0.05)\n print(\"second\")\n return 5\n\n@threaded\ndef _2():\n time.sleep(0.01)\n print(\"first\")\n\na = _1()\n_2()\ntime.sleep(0.1)\n\nfirst\nsecond\n\n\nAfter the thread is complete, the return value is stored in the result attr.\n\na.result\n\n5\n\n\n\nsource\n\n\nstartthread\n\n startthread (f)\n\nLike threaded, but start thread immediately\n\n@startthread\ndef _():\n time.sleep(0.05)\n print(\"second\")\n\n@startthread\ndef _():\n time.sleep(0.01)\n print(\"first\")\n\ntime.sleep(0.1)\n\nfirst\nsecond\n\n\n\nsource\n\n\nstartproc\n\n startproc (f)\n\nLike threaded(True), but start Process immediately\n\n@startproc\ndef _():\n time.sleep(0.05)\n print(\"second\")\n\n@startproc\ndef _():\n time.sleep(0.01)\n print(\"first\")\n\ntime.sleep(0.1)\n\nfirst\nsecond\n\n\n\nsource\n\n\nparallelable\n\n parallelable (param_name, num_workers, f=None)\n\n\nsource\n\nThreadPoolExecutor\n\n ThreadPoolExecutor (max_workers=4, on_exc=<built-in function print>,\n pause=0, **kwargs)\n\nSame as Python’s ThreadPoolExecutor, except can pass max_workers==0 for serial execution\n\nsource\n\n\nProcessPoolExecutor\n\n ProcessPoolExecutor (max_workers=4, on_exc=<built-in function print>,\n pause=0, mp_context=None, initializer=None,\n initargs=())\n\nSame as Python’s ProcessPoolExecutor, except can pass max_workers==0 for serial execution\n\nsource\n\n\n\nparallel\n\n parallel (f, items, *args, n_workers=4, total=None, progress=None,\n pause=0, method=None, threadpool=False, timeout=None,\n chunksize=1, **kwargs)\n\nApplies func in parallel to items, using n_workers\n\nsource\n\n\nadd_one\n\n add_one (x, a=1)\n\n\ninp,exp = range(50),range(1,51)\n\ntest_eq(parallel(add_one, inp, n_workers=2, progress=False), exp)\ntest_eq(parallel(add_one, inp, threadpool=True, n_workers=2, progress=False), exp)\ntest_eq(parallel(add_one, inp, n_workers=1, a=2), range(2,52))\ntest_eq(parallel(add_one, inp, n_workers=0), exp)\ntest_eq(parallel(add_one, inp, n_workers=0, a=2), range(2,52))\n\nUse the pause parameter to ensure a pause of pause seconds between processes starting. This is in case there are race conditions in starting some process, or to stagger the time each process starts, for example when making many requests to a webserver. Set threadpool=True to use ThreadPoolExecutor instead of ProcessPoolExecutor.\n\nfrom datetime import datetime\n\n\ndef print_time(i): \n time.sleep(random.random()/1000)\n print(i, datetime.now())\n\nparallel(print_time, range(5), n_workers=2, pause=0.25);\n\n0 2022-08-07 05:10:05.999916\n1 2022-08-07 05:10:06.252031\n2 2022-08-07 05:10:06.503603\n3 2022-08-07 05:10:06.755216\n4 2022-08-07 05:10:07.006702\n\n\n\nsource\n\n\nrun_procs\n\n run_procs (f, f_done, args)\n\nCall f for each item in args in parallel, yielding f_done\n\nsource\n\n\nparallel_gen\n\n parallel_gen (cls, items, n_workers=4, **kwargs)\n\nInstantiate cls in n_workers procs & call each on a subset of items in parallel.\n\n# class _C:\n# def __call__(self, o): return ((i+1) for i in o)\n\n# items = range(5)\n\n# res = L(parallel_gen(_C, items, n_workers=0))\n# idxs,dat1 = zip(*res.sorted(itemgetter(0)))\n# test_eq(dat1, range(1,6))\n\n# res = L(parallel_gen(_C, items, n_workers=3))\n# idxs,dat2 = zip(*res.sorted(itemgetter(0)))\n# test_eq(dat2, dat1)\n\ncls is any class with __call__. It will be passed args and kwargs when initialized. Note that n_workers instances of cls are created, one in each process. items are then split in n_workers batches and one is sent to each cls. The function then returns a generator of tuples of item indices and results.\n\nclass TestSleepyBatchFunc:\n \"For testing parallel processes that run at different speeds\"\n def __init__(self): self.a=1\n def __call__(self, batch):\n for k in batch:\n time.sleep(random.random()/4)\n yield k+self.a\n\nx = np.linspace(0,0.99,20)\n\nres = L(parallel_gen(TestSleepyBatchFunc, x, n_workers=2))\ntest_eq(res.sorted().itemgot(1), x+1)\n\n\n\n\n\n\n\n\n\n# #|hide\n# from subprocess import Popen, PIPE\n# # test num_workers > 0 in scripts works when python process start method is spawn\n# process = Popen([\"python\", \"parallel_test.py\"], stdout=PIPE)\n# _, err = process.communicate(timeout=10)\n# exit_code = process.wait()\n# test_eq(exit_code, 0)", + "crumbs": [ + "Parallel" + ] + }, + { + "objectID": "tour.html", + "href": "tour.html", + "title": "A tour of fastcore", + "section": "", + "text": "Here’s a (somewhat) quick tour of a few higlights from fastcore.\n\nDocumentation\nAll fast.ai projects, including this one, are built with nbdev, which is a full literate programming environment built on Jupyter Notebooks. That means that every piece of documentation, including the page you’re reading now, can be accessed as interactive Jupyter notebooks. In fact, you can even grab a link directly to a notebook running interactively on Google Colab - if you want to follow along with this tour, click the link below:\n\ncolab_link('index')\n\nOpen index in Colab\n\n\nThe full docs are available at fastcore.fast.ai. The code in the examples and in all fast.ai libraries follow the fast.ai style guide. In order to support interactive programming, all fast.ai libraries are designed to allow for import * to be used safely, particular by ensuring that __all__ is defined in all packages. In order to see where a function is from, just type it:\n\ncoll_repr\n\n<function fastcore.foundation.coll_repr(c, max_n=10)>\n\n\nFor more details, including a link to the full documentation and source code, use doc, which pops up a window with this information:\ndoc(coll_repr)\n\nThe documentation also contains links to any related functions or classes, which appear like this: coll_repr (in the notebook itself you will just see a word with back-ticks around it; the links are auto-generated in the documentation site). The documentation will generally show one or more examples of use, along with any background context necessary to understand them. As you’ll see, the examples for each function and method are shown as tests, rather than example outputs, so let’s start by explaining that.\n\n\nTesting\nfastcore’s testing module is designed to work well with nbdev, which is a full literate programming environment built on Jupyter Notebooks. That means that your tests, docs, and code all live together in the same notebook. fastcore and nbdev’s approach to testing starts with the premise that all your tests should pass. If one fails, no more tests in a notebook are run.\nTests look like this:\n\ntest_eq(coll_repr(range(1000), 5), '(#1000) [0,1,2,3,4...]')\n\nThat’s an example from the docs for coll_repr. As you see, it’s not showing you the output directly. Here’s what that would look like:\n\ncoll_repr(range(1000), 5)\n\n'(#1000) [0,1,2,3,4...]'\n\n\nSo, the test is actually showing you what the output looks like, because if the function call didn’t return '(#1000) [0,1,2,3,4...]', then the test would have failed.\nSo every test shown in the docs is also showing you the behavior of the library — and vice versa!\nTest functions always start with test_, and then follow with the operation being tested. So test_eq tests for equality (as you saw in the example above). This includes tests for equality of arrays and tensors, lists and generators, and many more:\n\ntest_eq([0,1,2,3], np.arange(4))\n\nWhen a test fails, it prints out information about what was expected:\ntest_eq([0,1,2,3], np.arange(3))\n----\n AssertionError: ==:\n [0, 1, 2, 3]\n [0 1 2]\nIf you want to check that objects are the same type, rather than the just contain the same collection, use test_eq_type.\nYou can test with any comparison function using test, e.g test whether an object is less than:\n\ntest(2, 3, operator.lt)\n\nYou can even test that exceptions are raised:\n\ndef divide_zero(): return 1/0\ntest_fail(divide_zero)\n\n…and test that things are printed to stdout:\n\ntest_stdout(lambda: print('hi'), 'hi')\n\n\n\nFoundations\nfast.ai is unusual in that we often use mixins in our code. Mixins are widely used in many programming languages, such as Ruby, but not so much in Python. We use mixins to attach new behavior to existing libraries, or to allow modules to add new behavior to our own classes, such as in extension modules. One useful example of a mixin we define is Path.ls, which lists a directory and returns an L (an extended list class which we’ll discuss shortly):\n\np = Path('images')\np.ls()\n\n(#6) [Path('images/mnist3.png'),Path('images/att_00000.png'),Path('images/puppy.jpg'),Path('images/att_00005.png'),Path('images/att_00007.png'),Path('images/att_00006.png')]\n\n\nYou can easily add you own mixins with the patch decorator, which takes advantage of Python 3 function annotations to say what class to patch:\n\n@patch\ndef num_items(self:Path): return len(self.ls())\n\np.num_items()\n\n6\n\n\nWe also use **kwargs frequently. In python **kwargs in a parameter like means “put any additional keyword arguments into a dict called kwargs”. Normally, using kwargs makes an API quite difficult to work with, because it breaks things like tab-completion and popup lists of signatures. utils provides use_kwargs and delegates to avoid this problem. See our detailed article on delegation on this topic.\nGetAttr solves a similar problem (and is also discussed in the article linked above): it’s allows you to use Python’s exceptionally useful __getattr__ magic method, but avoids the problem that normally in Python tab-completion and docs break when using this. For instance, you can see here that Python’s dir function, which is used to find the attributes of a python object, finds everything inside the self.default attribute here:\n\nclass Author:\n def __init__(self, name): self.name = name\n\nclass ProductPage(GetAttr):\n _default = 'author'\n def __init__(self,author,price,cost): self.author,self.price,self.cost = author,price,cost\n\np = ProductPage(Author(\"Jeremy\"), 1.50, 0.50)\n[o for o in dir(p) if not o.startswith('_')]\n\n['author', 'cost', 'name', 'price']\n\n\nLooking at that ProductPage example, it’s rather verbose and duplicates a lot of attribute names, which can lead to bugs later if you change them only in one place. fastcore provides store_attr to simplify this common pattern. It also provides basic_repr to give simple objects a useful repr:\n\nclass ProductPage:\n def __init__(self,author,price,cost): store_attr()\n __repr__ = basic_repr('author,price,cost')\n\nProductPage(\"Jeremy\", 1.50, 0.50)\n\n__main__.ProductPage(author='Jeremy', price=1.5, cost=0.5)\n\n\nOne of the most interesting fastcore functions is the funcs_kwargs decorator. This allows class behavior to be modified without sub-classing. This can allow folks that aren’t familiar with object-oriented programming to customize your class more easily. Here’s an example of a class that uses funcs_kwargs:\n\n@funcs_kwargs\nclass T:\n _methods=['some_method']\n def __init__(self, **kwargs): assert not kwargs, f'Passed unknown args: {kwargs}'\n\np = T(some_method = print)\np.some_method(\"hello\")\n\nhello\n\n\nThe assert not kwargs above is used to ensure that the user doesn’t pass an unknown parameter (i.e one that’s not in _methods). fastai uses funcs_kwargs in many places, for instance, you can customize any part of a DataLoader by passing your own methods.\nfastcore also provides many utility functions that make a Python programmer’s life easier, in fastcore.utils. We won’t look at many here, since you can easily look at the docs yourself. To get you started, have a look at the docs for chunked (remember, if you’re in a notebook, type doc(chunked)), which is a handy function for creating lazily generated batches from a collection.\nPython’s ProcessPoolExecutor is extended to allow max_workers to be set to 0, to easily turn off parallel processing. This makes it easy to debug your code in serial, then run it in parallel. It also allows you to pass arguments to your parallel function, and to ensure there’s a pause between calls, in case the process you are running has race conditions. parallel makes parallel processing even easier to use, and even adds an optional progress bar.\n\n\nL\nLike most languages, Python allows for very concise syntax for some very common types, such as list, which can be constructed with [1,2,3]. Perl’s designer Larry Wall explained the reasoning for this kind of syntax:\n\nIn metaphorical honor of Huffman’s compression code that assigns smaller numbers of bits to more common bytes. In terms of syntax, it simply means that commonly used things should be shorter, but you shouldn’t waste short sequences on less common constructs.\n\nOn this basis, fastcore has just one type that has a single letter name: L. The reason for this is that it is designed to be a replacement for list, so we want it to be just as easy to use as [1,2,3]. Here’s how to create that as an L:\n\nL(1,2,3)\n\n(#3) [1,2,3]\n\n\nThe first thing to notice is that an L object includes in its representation its number of elements; that’s the (#3) in the output above. If there’s more than 10 elements, it will automatically truncate the list:\n\np = L.range(20).shuffle()\np\n\n(#20) [5,1,9,10,18,13,6,17,3,16...]\n\n\nL contains many of the same indexing ideas that NumPy’s array does, including indexing with a list of indexes, or a boolean mask list:\n\np[2,4,6]\n\n(#3) [9,18,6]\n\n\nIt also contains other methods used in array, such as L.argwhere:\n\np.argwhere(ge(15))\n\n(#5) [4,7,9,18,19]\n\n\nAs you can see from this example, fastcore also includes a number of features that make a functional style of programming easier, such as a full range of boolean functions (e.g ge, gt, etc) which give the same answer as the functions from Python’s operator module if given two parameters, but return a curried function if given one parameter.\nThere’s too much functionality to show it all here, so be sure to check the docs. Many little things are added that we thought should have been in list in the first place, such as making this do what you’d expect (which is an error with list, but works fine with L):\n\n1 + L(2,3,4)\n\n(#4) [1,2,3,4]\n\n\n\n\nTransforms\nA Transform is the main building block of the fastai data pipelines. In the most general terms a transform can be any function you want to apply to your data, however the Transform class provides several mechanisms that make the process of building them easy and flexible (see the docs for information about each of these):\n\nType dispatch\nDispatch over tuples\nReversability\nType propagation\nPreprocessing\nFiltering based on the dataset type\nOrdering\nAppending new behavior with decorators\n\nTransform looks for three special methods, encodes, decodes, and setups, which provide the implementation for __call__, decode, and setup respectively. For instance:\n\nclass A(Transform):\n def encodes(self, x): return x+1\n\nA()(1)\n\n2\n\n\nFor simple transforms like this, you can also use Transform as a decorator:\n\n@Transform\ndef f(x): return x+1\n\nf(1)\n\n2\n\n\nTransforms can be composed into a Pipeline:\n\n@Transform\ndef g(x): return x/2\n\npipe = Pipeline([f,g])\npipe(3)\n\n2.0\n\n\nThe power of Transform and Pipeline is best understood by seeing how they’re used to create a complete data processing pipeline. This is explained in chapter 11 of the fastai book, which is available for free in Jupyter Notebook format.", + "crumbs": [ + "A tour of fastcore" + ] + }, + { + "objectID": "style.html", + "href": "style.html", + "title": "Style", + "section": "", + "text": "Note\n\n\n\nStyled outputs don’t show in Quarto documentation. Please use a notebook editor to correctly view this page.\n\n\n\nsource\n\nStyleCode\n\n StyleCode (name, code, typ)\n\nAn escape sequence for styling terminal text.\nThe primary building block of the S API.\n\nprint(str(StyleCode('blue', 34, 'fg')) + 'hello' + str(StyleCode('default', 39, 'fg')) + ' world')\n\nhello world\n\n\n\nsource\n\n\nStyle\n\n Style (codes=None)\n\nA minimal terminal text styler.\nThe main way to use it is via the exported S object.\n\n\nExported source\nS = Style()\n\n\nWe start with an empty style:\n\nS\n\n<Style: none>\n\n\nDefine a new style by chaining attributes:\n\ns = S.blue.bold.underline\ns\n\n<Style: blue bold underline>\n\n\nYou can see a full list of available styles with auto-complete by typing S . Tab.\nApply a style by calling it with a string:\n\ns('hello world')\n\n'\\x1b[34m\\x1b[1m\\x1b[4mhello world\\x1b[22m\\x1b[24m\\x1b[39m'\n\n\nThat’s a raw string with the underlying escape sequences that tell the terminal how to format text. To see the styled version we have to print it:\n\nprint(s('hello world'))\n\nhello world\n\n\nYou can also nest styles:\n\nprint(S.bold(S.blue('key') + ' = value ') + S.light_gray(' ' + S.underline('# With a comment')) + ' and unstyled text')\n\nkey = value # With a comment and unstyled text\n\n\n\nprint(S.blue('this '+S.bold('is')+' a test'))\n\nthis is a test\n\n\n\nsource\n\n\ndemo\n\n demo ()\n\nDemonstrate all available styles and their codes.\n\ndemo()\n\n 30 black \n 31 red \n 32 green \n 33 yellow \n 34 blue \n 35 magenta \n 36 cyan \n 37 light_gray \n 39 default \n 90 dark_gray \n 91 light_red \n 92 light_green \n 93 light_yellow \n 94 light_blue \n 95 light_magenta \n 96 light_cyan \n 97 white \n 40 black_bg \n 41 red_bg \n 42 green_bg \n 43 yellow_bg \n 44 blue_bg \n 45 magenta_bg \n 46 cyan_bg \n 47 light_gray_bg \n 49 default_bg \n100 dark_gray_bg \n101 light_red_bg \n102 light_green_bg \n103 light_yellow_bg \n104 light_blue_bg \n105 light_magenta_bg\n106 light_cyan_bg \n107 white_bg \n 1 bold \n 2 dim \n 3 italic \n 4 underline \n 5 blink \n 7 invert \n 8 hidden \n 9 strikethrough \n 22 reset_bold \n 22 reset_dim \n 23 reset_italic \n 24 reset_underline \n 25 reset_blink \n 27 reset_invert \n 28 reset_hidden \n 29 reset_strikethrough\n 0 reset", + "crumbs": [ + "Style" + ] + }, + { + "objectID": "basics.html", + "href": "basics.html", + "title": "Basic functionality", + "section": "", + "text": "source\n\n\n\n ifnone (a, b)\n\nb if a is None else a\nSince b if a is None else a is such a common pattern, we wrap it in a function. However, be careful, because python will evaluate both a and b when calling ifnone (which it doesn’t do if using the if version directly).\n\ntest_eq(ifnone(None,1), 1)\ntest_eq(ifnone(2 ,1), 2)\n\n\nsource\n\n\n\n\n maybe_attr (o, attr)\n\ngetattr(o,attr,o)\nReturn the attribute attr for object o. If the attribute doesn’t exist, then return the object o instead.\n\nclass myobj: myattr='foo'\n\ntest_eq(maybe_attr(myobj, 'myattr'), 'foo')\ntest_eq(maybe_attr(myobj, 'another_attr'), myobj)\n\n\nsource\n\n\n\n\n basic_repr (flds=None)\n\nMinimal __repr__\nIn types which provide rich display functionality in Jupyter, their __repr__ is also called in order to provide a fallback text representation. Unfortunately, this includes a memory address which changes on every invocation, making it non-deterministic. This causes diffs to get messy and creates conflicts in git. To fix this, put __repr__=basic_repr() inside your class.\n\nclass SomeClass: __repr__=basic_repr()\nrepr(SomeClass())\n\n'<__main__.SomeClass>'\n\n\nIf you pass a list of attributes (flds) of an object, then this will generate a string with the name of each attribute and its corresponding value. The format of this string is key=value, where key is the name of the attribute, and value is the value of the attribute. For each value, attempt to use the __name__ attribute, otherwise fall back to using the value’s __repr__ when constructing the string.\n\nclass SomeClass:\n a=1\n b='foo'\n __repr__=basic_repr('a,b')\n __name__='some-class'\n\nrepr(SomeClass())\n\n\"__main__.SomeClass(a=1, b='foo')\"\n\n\n\nclass AnotherClass:\n c=SomeClass()\n d='bar'\n __repr__=basic_repr(['c', 'd'])\n\nrepr(AnotherClass())\n\n\"__main__.AnotherClass(c=__main__.SomeClass(a=1, b='foo'), d='bar')\"\n\n\n\nsource\n\n\n\n\n is_array (x)\n\nTrue if x supports __array__ or iloc\n\nis_array(np.array(1)),is_array([1])\n\n(True, False)\n\n\n\nsource\n\n\n\n\n listify (o=None, *rest, use_list=False, match=None)\n\nConvert o to a list\nConversion is designed to “do what you mean”, e.g:\n\ntest_eq(listify('hi'), ['hi'])\ntest_eq(listify(b'hi'), [b'hi'])\ntest_eq(listify(array(1)), [array(1)])\ntest_eq(listify(1), [1])\ntest_eq(listify([1,2]), [1,2])\ntest_eq(listify(range(3)), [0,1,2])\ntest_eq(listify(None), [])\ntest_eq(listify(1,2), [1,2])\n\n\narr = np.arange(9).reshape(3,3)\nlistify(arr)\n\n[array([[0, 1, 2],\n [3, 4, 5],\n [6, 7, 8]])]\n\n\n\nlistify(array([1,2]))\n\n[array([1, 2])]\n\n\nGenerators are turned into lists too:\n\ngen = (o for o in range(3))\ntest_eq(listify(gen), [0,1,2])\n\nUse match to provide a length to match:\n\ntest_eq(listify(1,match=3), [1,1,1])\n\nIf match is a sequence, it’s length is used:\n\ntest_eq(listify(1,match=range(3)), [1,1,1])\n\nIf the listified item is not of length 1, it must be the same length as match:\n\ntest_eq(listify([1,1,1],match=3), [1,1,1])\ntest_fail(lambda: listify([1,1],match=3))\n\n\nsource\n\n\n\n\n tuplify (o, use_list=False, match=None)\n\nMake o a tuple\n\ntest_eq(tuplify(None),())\ntest_eq(tuplify([1,2,3]),(1,2,3))\ntest_eq(tuplify(1,match=[1,2,3]),(1,1,1))\n\n\nsource\n\n\n\n\n true (x)\n\nTest whether x is truthy; collections with >0 elements are considered True\n\n[(o,true(o)) for o in\n (array(0),array(1),array([0]),array([0,1]),1,0,'',None)]\n\n[(array(0), False),\n (array(1), True),\n (array([0]), True),\n (array([0, 1]), True),\n (1, True),\n (0, False),\n ('', False),\n (None, False)]\n\n\n\nsource\n\n\n\n\n NullType ()\n\nAn object that is False and can be called, chained, and indexed\n\nbool(null.hi().there[3])\n\nFalse\n\n\n\nsource\n\n\n\n\n tonull (x)\n\nConvert None to null\n\nbool(tonull(None).hi().there[3])\n\nFalse\n\n\n\nsource\n\n\n\n\n get_class (nm, *fld_names, sup=None, doc=None, funcs=None, anno=None,\n **flds)\n\nDynamically create a class, optionally inheriting from sup, containing fld_names\n\n_t = get_class('_t', 'a', b=2, anno={'b':int})\nt = _t()\ntest_eq(t.a, None)\ntest_eq(t.b, 2)\nt = _t(1, b=3)\ntest_eq(t.a, 1)\ntest_eq(t.b, 3)\nt = _t(1, 3)\ntest_eq(t.a, 1)\ntest_eq(t.b, 3)\ntest_eq(t, pickle.loads(pickle.dumps(t)))\ntest_eq(_t.__annotations__, {'b':int, 'a':typing.Any})\nrepr(t)\n\n'__main__._t(a=1, b=3)'\n\n\nMost often you’ll want to call mk_class, since it adds the class to your module. See mk_class for more details and examples of use (which also apply to get_class).\n\nsource\n\n\n\n\n mk_class (nm, *fld_names, sup=None, doc=None, funcs=None, mod=None,\n anno=None, **flds)\n\nCreate a class using get_class and add to the caller’s module\nAny kwargs will be added as class attributes, and sup is an optional (tuple of) base classes.\n\nmk_class('_t', a=1, sup=dict)\nt = _t()\ntest_eq(t.a, 1)\nassert(isinstance(t,dict))\n\nA __init__ is provided that sets attrs for any kwargs, and for any args (matching by position to fields), along with a __repr__ which prints all attrs. The docstring is set to doc. You can pass funcs which will be added as attrs with the function names.\n\ndef foo(self): return 1\nmk_class('_t', 'a', sup=dict, doc='test doc', funcs=foo)\n\nt = _t(3, b=2)\ntest_eq(t.a, 3)\ntest_eq(t.b, 2)\ntest_eq(t.foo(), 1)\ntest_eq(t.__doc__, 'test doc')\nt\n\n{}\n\n\n\nsource\n\n\n\n\n wrap_class (nm, *fld_names, sup=None, doc=None, funcs=None, **flds)\n\nDecorator: makes function a method of a new class nm passing parameters to mk_class\n\n@wrap_class('_t', a=2)\ndef bar(self,x): return x+1\n\nt = _t()\ntest_eq(t.a, 2)\ntest_eq(t.bar(3), 4)\n\n\nsource\n\n\n\n ignore_exceptions ()\n\nContext manager to ignore exceptions\n\nwith ignore_exceptions(): \n # Exception will be ignored\n raise Exception\n\n\nsource\n\n\n\n\n\n exec_local (code, var_name)\n\nCall exec on code and return the var var_name\n\ntest_eq(exec_local(\"a=1\", \"a\"), 1)\n\n\nsource\n\n\n\n\n risinstance (types, obj=None)\n\nCurried isinstance but with args reversed\n\nassert risinstance(int, 1)\nassert not risinstance(str, 0)\nassert risinstance(int)(1)\n\ntypes can also be strings:\n\nassert risinstance(('str','int'), 'a')\nassert risinstance('str', 'a')\nassert not risinstance('int', 'a')\n\n\nsource\n\n\n\n\n ver2tuple (v:str)\n\n\ntest_eq(ver2tuple('3.8.1'), (3,8,1))\ntest_eq(ver2tuple('3.1'), (3,1,0))\ntest_eq(ver2tuple('3.'), (3,0,0))\ntest_eq(ver2tuple('3'), (3,0,0))", + "crumbs": [ + "Basic functionality" + ] + }, + { + "objectID": "basics.html#basics", + "href": "basics.html#basics", + "title": "Basic functionality", + "section": "", + "text": "source\n\n\n\n ifnone (a, b)\n\nb if a is None else a\nSince b if a is None else a is such a common pattern, we wrap it in a function. However, be careful, because python will evaluate both a and b when calling ifnone (which it doesn’t do if using the if version directly).\n\ntest_eq(ifnone(None,1), 1)\ntest_eq(ifnone(2 ,1), 2)\n\n\nsource\n\n\n\n\n maybe_attr (o, attr)\n\ngetattr(o,attr,o)\nReturn the attribute attr for object o. If the attribute doesn’t exist, then return the object o instead.\n\nclass myobj: myattr='foo'\n\ntest_eq(maybe_attr(myobj, 'myattr'), 'foo')\ntest_eq(maybe_attr(myobj, 'another_attr'), myobj)\n\n\nsource\n\n\n\n\n basic_repr (flds=None)\n\nMinimal __repr__\nIn types which provide rich display functionality in Jupyter, their __repr__ is also called in order to provide a fallback text representation. Unfortunately, this includes a memory address which changes on every invocation, making it non-deterministic. This causes diffs to get messy and creates conflicts in git. To fix this, put __repr__=basic_repr() inside your class.\n\nclass SomeClass: __repr__=basic_repr()\nrepr(SomeClass())\n\n'<__main__.SomeClass>'\n\n\nIf you pass a list of attributes (flds) of an object, then this will generate a string with the name of each attribute and its corresponding value. The format of this string is key=value, where key is the name of the attribute, and value is the value of the attribute. For each value, attempt to use the __name__ attribute, otherwise fall back to using the value’s __repr__ when constructing the string.\n\nclass SomeClass:\n a=1\n b='foo'\n __repr__=basic_repr('a,b')\n __name__='some-class'\n\nrepr(SomeClass())\n\n\"__main__.SomeClass(a=1, b='foo')\"\n\n\n\nclass AnotherClass:\n c=SomeClass()\n d='bar'\n __repr__=basic_repr(['c', 'd'])\n\nrepr(AnotherClass())\n\n\"__main__.AnotherClass(c=__main__.SomeClass(a=1, b='foo'), d='bar')\"\n\n\n\nsource\n\n\n\n\n is_array (x)\n\nTrue if x supports __array__ or iloc\n\nis_array(np.array(1)),is_array([1])\n\n(True, False)\n\n\n\nsource\n\n\n\n\n listify (o=None, *rest, use_list=False, match=None)\n\nConvert o to a list\nConversion is designed to “do what you mean”, e.g:\n\ntest_eq(listify('hi'), ['hi'])\ntest_eq(listify(b'hi'), [b'hi'])\ntest_eq(listify(array(1)), [array(1)])\ntest_eq(listify(1), [1])\ntest_eq(listify([1,2]), [1,2])\ntest_eq(listify(range(3)), [0,1,2])\ntest_eq(listify(None), [])\ntest_eq(listify(1,2), [1,2])\n\n\narr = np.arange(9).reshape(3,3)\nlistify(arr)\n\n[array([[0, 1, 2],\n [3, 4, 5],\n [6, 7, 8]])]\n\n\n\nlistify(array([1,2]))\n\n[array([1, 2])]\n\n\nGenerators are turned into lists too:\n\ngen = (o for o in range(3))\ntest_eq(listify(gen), [0,1,2])\n\nUse match to provide a length to match:\n\ntest_eq(listify(1,match=3), [1,1,1])\n\nIf match is a sequence, it’s length is used:\n\ntest_eq(listify(1,match=range(3)), [1,1,1])\n\nIf the listified item is not of length 1, it must be the same length as match:\n\ntest_eq(listify([1,1,1],match=3), [1,1,1])\ntest_fail(lambda: listify([1,1],match=3))\n\n\nsource\n\n\n\n\n tuplify (o, use_list=False, match=None)\n\nMake o a tuple\n\ntest_eq(tuplify(None),())\ntest_eq(tuplify([1,2,3]),(1,2,3))\ntest_eq(tuplify(1,match=[1,2,3]),(1,1,1))\n\n\nsource\n\n\n\n\n true (x)\n\nTest whether x is truthy; collections with >0 elements are considered True\n\n[(o,true(o)) for o in\n (array(0),array(1),array([0]),array([0,1]),1,0,'',None)]\n\n[(array(0), False),\n (array(1), True),\n (array([0]), True),\n (array([0, 1]), True),\n (1, True),\n (0, False),\n ('', False),\n (None, False)]\n\n\n\nsource\n\n\n\n\n NullType ()\n\nAn object that is False and can be called, chained, and indexed\n\nbool(null.hi().there[3])\n\nFalse\n\n\n\nsource\n\n\n\n\n tonull (x)\n\nConvert None to null\n\nbool(tonull(None).hi().there[3])\n\nFalse\n\n\n\nsource\n\n\n\n\n get_class (nm, *fld_names, sup=None, doc=None, funcs=None, anno=None,\n **flds)\n\nDynamically create a class, optionally inheriting from sup, containing fld_names\n\n_t = get_class('_t', 'a', b=2, anno={'b':int})\nt = _t()\ntest_eq(t.a, None)\ntest_eq(t.b, 2)\nt = _t(1, b=3)\ntest_eq(t.a, 1)\ntest_eq(t.b, 3)\nt = _t(1, 3)\ntest_eq(t.a, 1)\ntest_eq(t.b, 3)\ntest_eq(t, pickle.loads(pickle.dumps(t)))\ntest_eq(_t.__annotations__, {'b':int, 'a':typing.Any})\nrepr(t)\n\n'__main__._t(a=1, b=3)'\n\n\nMost often you’ll want to call mk_class, since it adds the class to your module. See mk_class for more details and examples of use (which also apply to get_class).\n\nsource\n\n\n\n\n mk_class (nm, *fld_names, sup=None, doc=None, funcs=None, mod=None,\n anno=None, **flds)\n\nCreate a class using get_class and add to the caller’s module\nAny kwargs will be added as class attributes, and sup is an optional (tuple of) base classes.\n\nmk_class('_t', a=1, sup=dict)\nt = _t()\ntest_eq(t.a, 1)\nassert(isinstance(t,dict))\n\nA __init__ is provided that sets attrs for any kwargs, and for any args (matching by position to fields), along with a __repr__ which prints all attrs. The docstring is set to doc. You can pass funcs which will be added as attrs with the function names.\n\ndef foo(self): return 1\nmk_class('_t', 'a', sup=dict, doc='test doc', funcs=foo)\n\nt = _t(3, b=2)\ntest_eq(t.a, 3)\ntest_eq(t.b, 2)\ntest_eq(t.foo(), 1)\ntest_eq(t.__doc__, 'test doc')\nt\n\n{}\n\n\n\nsource\n\n\n\n\n wrap_class (nm, *fld_names, sup=None, doc=None, funcs=None, **flds)\n\nDecorator: makes function a method of a new class nm passing parameters to mk_class\n\n@wrap_class('_t', a=2)\ndef bar(self,x): return x+1\n\nt = _t()\ntest_eq(t.a, 2)\ntest_eq(t.bar(3), 4)\n\n\nsource\n\n\n\n ignore_exceptions ()\n\nContext manager to ignore exceptions\n\nwith ignore_exceptions(): \n # Exception will be ignored\n raise Exception\n\n\nsource\n\n\n\n\n\n exec_local (code, var_name)\n\nCall exec on code and return the var var_name\n\ntest_eq(exec_local(\"a=1\", \"a\"), 1)\n\n\nsource\n\n\n\n\n risinstance (types, obj=None)\n\nCurried isinstance but with args reversed\n\nassert risinstance(int, 1)\nassert not risinstance(str, 0)\nassert risinstance(int)(1)\n\ntypes can also be strings:\n\nassert risinstance(('str','int'), 'a')\nassert risinstance('str', 'a')\nassert not risinstance('int', 'a')\n\n\nsource\n\n\n\n\n ver2tuple (v:str)\n\n\ntest_eq(ver2tuple('3.8.1'), (3,8,1))\ntest_eq(ver2tuple('3.1'), (3,1,0))\ntest_eq(ver2tuple('3.'), (3,0,0))\ntest_eq(ver2tuple('3'), (3,0,0))", + "crumbs": [ + "Basic functionality" + ] + }, + { + "objectID": "basics.html#noop", + "href": "basics.html#noop", + "title": "Basic functionality", + "section": "NoOp", + "text": "NoOp\nThese are used when you need a pass-through function.\n\n\nnoop\n\n noop (x=None, *args, **kwargs)\n\nDo nothing\n\nnoop()\ntest_eq(noop(1),1)\n\n\n\n\nnoops\n\n noops (x=None, *args, **kwargs)\n\nDo nothing (method)\n\nclass _t: foo=noops\ntest_eq(_t().foo(1),1)", + "crumbs": [ + "Basic functionality" + ] + }, + { + "objectID": "basics.html#infinite-lists", + "href": "basics.html#infinite-lists", + "title": "Basic functionality", + "section": "Infinite Lists", + "text": "Infinite Lists\nThese lists are useful for things like padding an array or adding index column(s) to arrays.\nInf defines the following properties:\n\ncount: itertools.count()\nzeros: itertools.cycle([0])\nones : itertools.cycle([1])\nnones: itertools.cycle([None])\n\n\ntest_eq([o for i,o in zip(range(5), Inf.count)],\n [0, 1, 2, 3, 4])\n\ntest_eq([o for i,o in zip(range(5), Inf.zeros)],\n [0]*5)\n\ntest_eq([o for i,o in zip(range(5), Inf.ones)],\n [1]*5)\n\ntest_eq([o for i,o in zip(range(5), Inf.nones)],\n [None]*5)", + "crumbs": [ + "Basic functionality" + ] + }, + { + "objectID": "basics.html#operator-functions", + "href": "basics.html#operator-functions", + "title": "Basic functionality", + "section": "Operator Functions", + "text": "Operator Functions\n\nsource\n\nin_\n\n in_ (x, a)\n\nTrue if x in a\n\n# test if element is in another\nassert in_('c', ('b', 'c', 'a'))\nassert in_(4, [2,3,4,5])\nassert in_('t', 'fastai')\ntest_fail(in_('h', 'fastai'))\n\n# use in_ as a partial\nassert in_('fastai')('t')\nassert in_([2,3,4,5])(4)\ntest_fail(in_('fastai')('h'))\n\nIn addition to in_, the following functions are provided matching the behavior of the equivalent versions in operator: lt gt le ge eq ne add sub mul truediv is_ is_not mod.\n\nlt(3,5),gt(3,5),is_(None,None),in_(0,[1,2]),mod(3,2)\n\n(True, False, True, False, 1)\n\n\nSimilarly to _in, they also have additional functionality: if you only pass one param, they return a partial function that passes that param as the second positional parameter.\n\nlt(5)(3),gt(5)(3),is_(None)(None),in_([1,2])(0),mod(2)(3)\n\n(True, False, True, False, 1)\n\n\n\nsource\n\n\nret_true\n\n ret_true (*args, **kwargs)\n\nPredicate: always True\n\nassert ret_true(1,2,3)\nassert ret_true(False)\n\n\nsource\n\n\nret_false\n\n ret_false (*args, **kwargs)\n\nPredicate: always False\n\nsource\n\n\nstop\n\n stop (e=<class 'StopIteration'>)\n\nRaises exception e (by default StopIteration)\n\nsource\n\n\ngen\n\n gen (func, seq, cond=<function ret_true>)\n\nLike (func(o) for o in seq if cond(func(o))) but handles StopIteration\n\ntest_eq(gen(noop, Inf.count, lt(5)),\n range(5))\ntest_eq(gen(operator.neg, Inf.count, gt(-5)),\n [0,-1,-2,-3,-4])\ntest_eq(gen(lambda o:o if o<5 else stop(), Inf.count),\n range(5))\n\n\nsource\n\n\nchunked\n\n chunked (it, chunk_sz=None, drop_last=False, n_chunks=None)\n\nReturn batches from iterator it of size chunk_sz (or return n_chunks total)\nNote that you must pass either chunk_sz, or n_chunks, but not both.\n\nt = list(range(10))\ntest_eq(chunked(t,3), [[0,1,2], [3,4,5], [6,7,8], [9]])\ntest_eq(chunked(t,3,True), [[0,1,2], [3,4,5], [6,7,8], ])\n\nt = map(lambda o:stop() if o==6 else o, Inf.count)\ntest_eq(chunked(t,3), [[0, 1, 2], [3, 4, 5]])\nt = map(lambda o:stop() if o==7 else o, Inf.count)\ntest_eq(chunked(t,3), [[0, 1, 2], [3, 4, 5], [6]])\n\nt = np.arange(10)\ntest_eq(chunked(t,3), [[0,1,2], [3,4,5], [6,7,8], [9]])\ntest_eq(chunked(t,3,True), [[0,1,2], [3,4,5], [6,7,8], ])\n\ntest_eq(chunked([], 3), [])\ntest_eq(chunked([], n_chunks=3), [])\n\n\nsource\n\n\notherwise\n\n otherwise (x, tst, y)\n\ny if tst(x) else x\n\ntest_eq(otherwise(2+1, gt(3), 4), 3)\ntest_eq(otherwise(2+1, gt(2), 4), 4)", + "crumbs": [ + "Basic functionality" + ] + }, + { + "objectID": "basics.html#attribute-helpers", + "href": "basics.html#attribute-helpers", + "title": "Basic functionality", + "section": "Attribute Helpers", + "text": "Attribute Helpers\nThese functions reduce boilerplate when setting or manipulating attributes or properties of objects.\n\nsource\n\ncustom_dir\n\n custom_dir (c, add)\n\nImplement custom __dir__, adding add to cls\ncustom_dir allows you extract the __dict__ property of a class and appends the list add to it.\n\nclass _T: \n def f(): pass\n\ns = custom_dir(_T(), add=['foo', 'bar'])\nassert {'foo', 'bar', 'f'}.issubset(s)\n\n\nsource\n\n\nAttrDict\ndict subclass that also provides access to keys as attrs\n\nd = AttrDict(a=1,b=\"two\")\ntest_eq(d.a, 1)\ntest_eq(d['b'], 'two')\ntest_eq(d.get('c','nope'), 'nope')\nd.b = 2\ntest_eq(d.b, 2)\ntest_eq(d['b'], 2)\nd['b'] = 3\ntest_eq(d['b'], 3)\ntest_eq(d.b, 3)\nassert 'a' in dir(d)\n\nAttrDict will pretty print in Jupyter Notebooks:\n\n_test_dict = {'a':1, 'b': {'c':1, 'd':2}, 'c': {'c':1, 'd':2}, 'd': {'c':1, 'd':2},\n 'e': {'c':1, 'd':2}, 'f': {'c':1, 'd':2, 'e': 4, 'f':[1,2,3,4,5]}}\nAttrDict(_test_dict)\n\n{ 'a': 1,\n 'b': {'c': 1, 'd': 2},\n 'c': {'c': 1, 'd': 2},\n 'd': {'c': 1, 'd': 2},\n 'e': {'c': 1, 'd': 2},\n 'f': {'c': 1, 'd': 2, 'e': 4, 'f': [1, 2, 3, 4, 5]}}\n\n\n\nsource\n\n\nNS\nSimpleNamespace subclass that also adds iter and dict support\nThis is very similar to AttrDict, but since it starts with SimpleNamespace, it has some differences in behavior. You can use it just like SimpleNamespace:\n\nd = NS(**_test_dict)\nd\n\nnamespace(a=1,\n b={'c': 1, 'd': 2},\n c={'c': 1, 'd': 2},\n d={'c': 1, 'd': 2},\n e={'c': 1, 'd': 2},\n f={'c': 1, 'd': 2, 'e': 4, 'f': [1, 2, 3, 4, 5]})\n\n\n…but you can also index it to get/set:\n\nd['a']\n\n1\n\n\n…and iterate t:\n\nlist(d)\n\n['a', 'b', 'c', 'd', 'e', 'f']\n\n\n\nsource\n\n\nget_annotations_ex\n\n get_annotations_ex (obj, globals=None, locals=None)\n\nBackport of py3.10 get_annotations that returns globals/locals\nIn Python 3.10 inspect.get_annotations was added. However previous versions of Python are unable to evaluate type annotations correctly if from future import __annotations__ is used. Furthermore, all annotations are evaluated, even if only some subset are needed. get_annotations_ex provides the same functionality as inspect.get_annotations, but works on earlier versions of Python, and returns the globals and locals needed to evaluate types.\n\nsource\n\n\neval_type\n\n eval_type (t, glb, loc)\n\neval a type or collection of types, if needed, for annotations in py3.10+\nIn py3.10, or if from future import __annotations__ is used, a is a str:\n\nclass _T2a: pass\ndef func(a: _T2a): pass\nann,glb,loc = get_annotations_ex(func)\n\neval_type(ann['a'], glb, loc)\n\n__main__._T2a\n\n\n| is supported for defining Union types when using eval_type even for python versions prior to 3.9:\n\nclass _T2b: pass\ndef func(a: _T2a|_T2b): pass\nann,glb,loc = get_annotations_ex(func)\n\neval_type(ann['a'], glb, loc)\n\ntyping.Union[__main__._T2a, __main__._T2b]\n\n\n\nsource\n\n\ntype_hints\n\n type_hints (f)\n\nLike typing.get_type_hints but returns {} if not allowed type\nBelow is a list of allowed types for type hints in python:\n\nlist(typing._allowed_types)\n\n[function,\n builtin_function_or_method,\n method,\n module,\n wrapper_descriptor,\n method-wrapper,\n method_descriptor]\n\n\nFor example, type func is allowed so type_hints returns the same value as typing.get_hints:\n\ndef f(a:int)->bool: ... # a function with type hints (allowed)\nexp = {'a':int,'return':bool}\ntest_eq(type_hints(f), typing.get_type_hints(f))\ntest_eq(type_hints(f), exp)\n\nHowever, class is not an allowed type, so type_hints returns {}:\n\nclass _T:\n def __init__(self, a:int=0)->bool: ...\nassert not type_hints(_T)\n\n\nsource\n\n\nannotations\n\n annotations (o)\n\nAnnotations for o, or type(o)\nThis supports a wider range of situations than type_hints, by checking type() and __init__ for annotations too:\n\nfor o in _T,_T(),_T.__init__,f: test_eq(annotations(o), exp)\nassert not annotations(int)\nassert not annotations(print)\n\n\nsource\n\n\nanno_ret\n\n anno_ret (func)\n\nGet the return annotation of func\n\ndef f(x) -> float: return x\ntest_eq(anno_ret(f), float)\n\ndef f(x) -> typing.Tuple[float,float]: return x\nassert anno_ret(f)==typing.Tuple[float,float]\n\nIf your return annotation is None, anno_ret will return NoneType (and not None):\n\ndef f(x) -> None: return x\n\ntest_eq(anno_ret(f), NoneType)\nassert anno_ret(f) is not None # returns NoneType instead of None\n\nIf your function does not have a return type, or if you pass in None instead of a function, then anno_ret returns None:\n\ndef f(x): return x\n\ntest_eq(anno_ret(f), None)\ntest_eq(anno_ret(None), None) # instead of passing in a func, pass in None\n\n\nsource\n\n\nsignature_ex\n\n signature_ex (obj, eval_str:bool=False)\n\nBackport of inspect.signature(..., eval_str=True to <py310\n\nsource\n\n\nunion2tuple\n\n union2tuple (t)\n\n\ntest_eq(union2tuple(Union[int,str]), (int,str))\ntest_eq(union2tuple(int), int)\nassert union2tuple(Tuple[int,str])==Tuple[int,str]\ntest_eq(union2tuple((int,str)), (int,str))\nif UnionType: test_eq(union2tuple(int|str), (int,str))\n\n\nsource\n\n\nargnames\n\n argnames (f, frame=False)\n\nNames of arguments to function or frame f\n\ntest_eq(argnames(f), ['x'])\n\n\nsource\n\n\nwith_cast\n\n with_cast (f)\n\nDecorator which uses any parameter annotations as preprocessing functions\n\n@with_cast\ndef _f(a, b:Path, c:str='', d=0): return (a,b,c,d)\n\ntest_eq(_f(1, '.', 3), (1,Path('.'),'3',0))\ntest_eq(_f(1, '.'), (1,Path('.'),'',0))\n\n@with_cast\ndef _g(a:int=0)->str: return a\n\ntest_eq(_g(4.0), '4')\ntest_eq(_g(4.4), '4')\ntest_eq(_g(2), '2')\n\n\nsource\n\n\nstore_attr\n\n store_attr (names=None, but='', cast=False, store_args=None, **attrs)\n\nStore params named in comma-separated names from calling context into attrs in self\nIn it’s most basic form, you can use store_attr to shorten code like this:\n\nclass T:\n def __init__(self, a,b,c): self.a,self.b,self.c = a,b,c\n\n…to this:\n\nclass T:\n def __init__(self, a,b,c): store_attr('a,b,c', self)\n\nThis class behaves as if we’d used the first form:\n\nt = T(1,c=2,b=3)\nassert t.a==1 and t.b==3 and t.c==2\n\nIn addition, it stores the attrs as a dict in __stored_args__, which you can use for display, logging, and so forth.\n\ntest_eq(t.__stored_args__, {'a':1, 'b':3, 'c':2})\n\nSince you normally want to use the first argument (often called self) for storing attributes, it’s optional:\n\nclass T:\n def __init__(self, a,b,c:str): store_attr('a,b,c')\n\nt = T(1,c=2,b=3)\nassert t.a==1 and t.b==3 and t.c==2\n\nWith cast=True any parameter annotations will be used as preprocessing functions for the corresponding arguments:\n\nclass T:\n def __init__(self, a:listify, b, c:str): store_attr('a,b,c', cast=True)\n\nt = T(1,c=2,b=3)\nassert t.a==[1] and t.b==3 and t.c=='2'\n\nYou can inherit from a class using store_attr, and just call it again to add in any new attributes added in the derived class:\n\nclass T2(T):\n def __init__(self, d, **kwargs):\n super().__init__(**kwargs)\n store_attr('d')\n\nt = T2(d=1,a=2,b=3,c=4)\nassert t.a==2 and t.b==3 and t.c==4 and t.d==1\n\nYou can skip passing a list of attrs to store. In this case, all arguments passed to the method are stored:\n\nclass T:\n def __init__(self, a,b,c): store_attr()\n\nt = T(1,c=2,b=3)\nassert t.a==1 and t.b==3 and t.c==2\n\n\nclass T4(T):\n def __init__(self, d, **kwargs):\n super().__init__(**kwargs)\n store_attr()\n\nt = T4(4, a=1,c=2,b=3)\nassert t.a==1 and t.b==3 and t.c==2 and t.d==4\n\n\nclass T4:\n def __init__(self, *, a: int, b: float = 1):\n store_attr()\n \nt = T4(a=3)\nassert t.a==3 and t.b==1\nt = T4(a=3, b=2)\nassert t.a==3 and t.b==2\n\nYou can skip some attrs by passing but:\n\nclass T:\n def __init__(self, a,b,c): store_attr(but='a')\n\nt = T(1,c=2,b=3)\nassert t.b==3 and t.c==2\nassert not hasattr(t,'a')\n\nYou can also pass keywords to store_attr, which is identical to setting the attrs directly, but also stores them in __stored_args__.\n\nclass T:\n def __init__(self): store_attr(a=1)\n\nt = T()\nassert t.a==1\n\nYou can also use store_attr inside functions.\n\ndef create_T(a, b):\n t = SimpleNamespace()\n store_attr(self=t)\n return t\n\nt = create_T(a=1, b=2)\nassert t.a==1 and t.b==2\n\n\nsource\n\n\nattrdict\n\n attrdict (o, *ks, default=None)\n\nDict from each k in ks to getattr(o,k)\n\nclass T:\n def __init__(self, a,b,c): store_attr()\n\nt = T(1,c=2,b=3)\ntest_eq(attrdict(t,'b','c'), {'b':3, 'c':2})\n\n\nsource\n\n\nproperties\n\n properties (cls, *ps)\n\nChange attrs in cls with names in ps to properties\n\nclass T:\n def a(self): return 1\n def b(self): return 2\nproperties(T,'a')\n\ntest_eq(T().a,1)\ntest_eq(T().b(),2)\n\n\nsource\n\n\ncamel2words\n\n camel2words (s, space=' ')\n\nConvert CamelCase to ‘spaced words’\n\ntest_eq(camel2words('ClassAreCamel'), 'Class Are Camel')\n\n\nsource\n\n\ncamel2snake\n\n camel2snake (name)\n\nConvert CamelCase to snake_case\n\ntest_eq(camel2snake('ClassAreCamel'), 'class_are_camel')\ntest_eq(camel2snake('Already_Snake'), 'already__snake')\n\n\nsource\n\n\nsnake2camel\n\n snake2camel (s)\n\nConvert snake_case to CamelCase\n\ntest_eq(snake2camel('a_b_cc'), 'ABCc')\n\n\nsource\n\n\nclass2attr\n\n class2attr (cls_name)\n\nReturn the snake-cased name of the class; strip ending cls_name if it exists.\n\nclass Parent:\n @property\n def name(self): return class2attr(self, 'Parent')\n\nclass ChildOfParent(Parent): pass\nclass ParentChildOf(Parent): pass\n\np = Parent()\ncp = ChildOfParent()\ncp2 = ParentChildOf()\n\ntest_eq(p.name, 'parent')\ntest_eq(cp.name, 'child_of')\ntest_eq(cp2.name, 'parent_child_of')\n\n\nsource\n\n\ngetcallable\n\n getcallable (o, attr)\n\nCalls getattr with a default of noop\n\nclass Math:\n def addition(self,a,b): return a+b\n\nm = Math()\n\ntest_eq(getcallable(m, \"addition\")(a=1,b=2), 3)\ntest_eq(getcallable(m, \"subtraction\")(a=1,b=2), None)\n\n\nsource\n\n\ngetattrs\n\n getattrs (o, *attrs, default=None)\n\nList of all attrs in o\n\nfrom fractions import Fraction\n\n\ngetattrs(Fraction(1,2), 'numerator', 'denominator')\n\n[1, 2]\n\n\n\nsource\n\n\nhasattrs\n\n hasattrs (o, attrs)\n\nTest whether o contains all attrs\n\nassert hasattrs(1,('imag','real'))\nassert not hasattrs(1,('imag','foo'))\n\n\nsource\n\n\nsetattrs\n\n setattrs (dest, flds, src)\n\n\nd = dict(a=1,bb=\"2\",ignore=3)\no = SimpleNamespace()\nsetattrs(o, \"a,bb\", d)\ntest_eq(o.a, 1)\ntest_eq(o.bb, \"2\")\n\n\nd = SimpleNamespace(a=1,bb=\"2\",ignore=3)\no = SimpleNamespace()\nsetattrs(o, \"a,bb\", d)\ntest_eq(o.a, 1)\ntest_eq(o.bb, \"2\")\n\n\nsource\n\n\ntry_attrs\n\n try_attrs (obj, *attrs)\n\nReturn first attr that exists in obj\n\ntest_eq(try_attrs(1, 'real'), 1)\ntest_eq(try_attrs(1, 'foobar', 'real'), 1)", + "crumbs": [ + "Basic functionality" + ] + }, + { + "objectID": "basics.html#attribute-delegation", + "href": "basics.html#attribute-delegation", + "title": "Basic functionality", + "section": "Attribute Delegation", + "text": "Attribute Delegation\n\nsource\n\nGetAttrBase\n\n GetAttrBase ()\n\nBasic delegation of __getattr__ and __dir__\n\nsource\n\nGetAttr\n\n GetAttr ()\n\nInherit from this to have all attr accesses in self._xtra passed down to self.default\nInherit from GetAttr to have attr access passed down to an instance attribute. This makes it easy to create composites that don’t require callers to know about their components. For a more detailed discussion of how this works as well as relevant context, we suggest reading the delegated composition section of this blog article.\nYou can customise the behaviour of GetAttr in subclasses via; - _default - By default, this is set to 'default', so attr access is passed down to self.default - _default can be set to the name of any instance attribute that does not start with dunder __ - _xtra - By default, this is None, so all attr access is passed down - You can limit which attrs get passed down by setting _xtra to a list of attribute names\nTo illuminate the utility of GetAttr, suppose we have the following two classes, _WebPage which is a superclass of _ProductPage, which we wish to compose like so:\n\nclass _WebPage:\n def __init__(self, title, author=\"Jeremy\"):\n self.title,self.author = title,author\n\nclass _ProductPage:\n def __init__(self, page, price): self.page,self.price = page,price\n \npage = _WebPage('Soap', author=\"Sylvain\")\np = _ProductPage(page, 15.0)\n\nHow do we make it so we can just write p.author, instead of p.page.author to access the author attribute? We can use GetAttr, of course! First, we subclass GetAttr when defining _ProductPage. Next, we set self.default to the object whose attributes we want to be able to access directly, which in this case is the page argument passed on initialization:\n\nclass _ProductPage(GetAttr):\n def __init__(self, page, price): self.default,self.price = page,price #self.default allows you to access page directly.\n\np = _ProductPage(page, 15.0)\n\nNow, we can access the author attribute directly from the instance:\n\ntest_eq(p.author, 'Sylvain')\n\nIf you wish to store the object you are composing in an attribute other than self.default, you can set the class attribute _data as shown below. This is useful in the case where you might have a name collision with self.default:\n\nclass _C(GetAttr):\n _default = '_data' # use different component name; `self._data` rather than `self.default`\n def __init__(self,a): self._data = a\n def foo(self): noop\n\nt = _C('Hi')\ntest_eq(t._data, 'Hi') \ntest_fail(lambda: t.default) # we no longer have self.default\ntest_eq(t.lower(), 'hi')\ntest_eq(t.upper(), 'HI')\nassert 'lower' in dir(t)\nassert 'upper' in dir(t)\n\nBy default, all attributes and methods of the object you are composing are retained. In the below example, we compose a str object with the class _C. This allows us to directly call string methods on instances of class _C, such as str.lower() or str.upper():\n\nclass _C(GetAttr):\n # allow all attributes and methods to get passed to `self.default` (by leaving _xtra=None)\n def __init__(self,a): self.default = a\n def foo(self): noop\n\nt = _C('Hi')\ntest_eq(t.lower(), 'hi')\ntest_eq(t.upper(), 'HI')\nassert 'lower' in dir(t)\nassert 'upper' in dir(t)\n\nHowever, you can choose which attributes or methods to retain by defining a class attribute _xtra, which is a list of allowed attribute and method names to delegate. In the below example, we only delegate the lower method from the composed str object when defining class _C:\n\nclass _C(GetAttr):\n _xtra = ['lower'] # specify which attributes get passed to `self.default`\n def __init__(self,a): self.default = a\n def foo(self): noop\n\nt = _C('Hi')\ntest_eq(t.default, 'Hi')\ntest_eq(t.lower(), 'hi')\ntest_fail(lambda: t.upper()) # upper wasn't in _xtra, so it isn't available to be called\nassert 'lower' in dir(t)\nassert 'upper' not in dir(t)\n\nYou must be careful to properly set an instance attribute in __init__ that corresponds to the class attribute _default. The below example sets the class attribute _default to data, but erroneously fails to define self.data (and instead defines self.default).\nFailing to properly set instance attributes leads to errors when you try to access methods directly:\n\nclass _C(GetAttr):\n _default = 'data' # use a bad component name; i.e. self.data does not exist\n def __init__(self,a): self.default = a\n def foo(self): noop\n \n# TODO: should we raise an error when we create a new instance ...\nt = _C('Hi')\ntest_eq(t.default, 'Hi')\n# ... or is it enough for all GetAttr features to raise errors\ntest_fail(lambda: t.data)\ntest_fail(lambda: t.lower())\ntest_fail(lambda: t.upper())\ntest_fail(lambda: dir(t))\n\n\nsource\n\n\n\ndelegate_attr\n\n delegate_attr (k, to)\n\nUse in __getattr__ to delegate to attr to without inheriting from GetAttr\ndelegate_attr is a functional way to delegate attributes, and is an alternative to GetAttr. We recommend reading the documentation of GetAttr for more details around delegation.\nYou can use achieve delegation when you define __getattr__ by using delegate_attr:\n\nclass _C:\n def __init__(self, o): self.o = o # self.o corresponds to the `to` argument in delegate_attr.\n def __getattr__(self, k): return delegate_attr(self, k, to='o')\n \n\nt = _C('HELLO') # delegates to a string\ntest_eq(t.lower(), 'hello')\n\nt = _C(np.array([5,4,3])) # delegates to a numpy array\ntest_eq(t.sum(), 12)\n\nt = _C(pd.DataFrame({'a': [1,2], 'b': [3,4]})) # delegates to a pandas.DataFrame\ntest_eq(t.b.max(), 4)", + "crumbs": [ + "Basic functionality" + ] + }, + { + "objectID": "basics.html#extensible-types", + "href": "basics.html#extensible-types", + "title": "Basic functionality", + "section": "Extensible Types", + "text": "Extensible Types\nShowPrint is a base class that defines a show method, which is used primarily for callbacks in fastai that expect this method to be defined.\nInt, Float, and Str extend int, float and str respectively by adding an additional show method by inheriting from ShowPrint.\nThe code for Int is shown below:\nExamples:\n\nInt(0).show()\nFloat(2.0).show()\nStr('Hello').show()\n\n0\n2.0\nHello", + "crumbs": [ + "Basic functionality" + ] + }, + { + "objectID": "basics.html#collection-functions", + "href": "basics.html#collection-functions", + "title": "Basic functionality", + "section": "Collection functions", + "text": "Collection functions\nFunctions that manipulate popular python collections.\n\nsource\n\npartition\n\n partition (coll, f)\n\nPartition a collection by a predicate\n\nts,fs = partition(range(10), mod(2))\ntest_eq(fs, [0,2,4,6,8])\ntest_eq(ts, [1,3,5,7,9])\n\n\nsource\n\n\nflatten\n\n flatten (o)\n\nConcatenate all collections and items as a generator\n\nsource\n\n\nconcat\n\n concat (colls)\n\nConcatenate all collections and items as a list\n\nconcat([(o for o in range(2)),[2,3,4], 5])\n\n[0, 1, 2, 3, 4, 5]\n\n\n\nconcat([[\"abc\", \"xyz\"], [\"foo\", \"bar\"]])\n\n['abc', 'xyz', 'foo', 'bar']\n\n\n\nsource\n\n\nstrcat\n\n strcat (its, sep:str='')\n\nConcatenate stringified items its\n\ntest_eq(strcat(['a',2]), 'a2')\ntest_eq(strcat(['a',2], ';'), 'a;2')\n\n\nsource\n\n\ndetuplify\n\n detuplify (x)\n\nIf x is a tuple with one thing, extract it\n\ntest_eq(detuplify(()),None)\ntest_eq(detuplify([1]),1)\ntest_eq(detuplify([1,2]), [1,2])\ntest_eq(detuplify(np.array([[1,2]])), np.array([[1,2]]))\n\n\nsource\n\n\nreplicate\n\n replicate (item, match)\n\nCreate tuple of item copied len(match) times\n\nt = [1,1]\ntest_eq(replicate([1,2], t),([1,2],[1,2]))\ntest_eq(replicate(1, t),(1,1))\n\n\nsource\n\n\nsetify\n\n setify (o)\n\nTurn any list like-object into a set.\n\n# test\ntest_eq(setify(None),set())\ntest_eq(setify('abc'),{'abc'})\ntest_eq(setify([1,2,2]),{1,2})\ntest_eq(setify(range(0,3)),{0,1,2})\ntest_eq(setify({1,2}),{1,2})\n\n\nsource\n\n\nmerge\n\n merge (*ds)\n\nMerge all dictionaries in ds\n\ntest_eq(merge(), {})\ntest_eq(merge(dict(a=1,b=2)), dict(a=1,b=2))\ntest_eq(merge(dict(a=1,b=2), dict(b=3,c=4), None), dict(a=1, b=3, c=4))\n\n\nsource\n\n\nrange_of\n\n range_of (x)\n\nAll indices of collection x (i.e. list(range(len(x))))\n\ntest_eq(range_of([1,1,1,1]), [0,1,2,3])\n\n\nsource\n\n\ngroupby\n\n groupby (x, key, val=<function noop>)\n\nLike itertools.groupby but doesn’t need to be sorted, and isn’t lazy, plus some extensions\n\ntest_eq(groupby('aa ab bb'.split(), itemgetter(0)), {'a':['aa','ab'], 'b':['bb']})\n\nHere’s an example of how to invert a grouping, using an int as key (which uses itemgetter; passing a str will use attrgetter), and using a val function:\n\nd = {0: [1, 3, 7], 2: [3], 3: [5], 4: [8], 5: [4], 7: [5]}\ngroupby(((o,k) for k,v in d.items() for o in v), 0, 1)\n\n{1: [0], 3: [0, 2], 7: [0], 5: [3, 7], 8: [4], 4: [5]}\n\n\n\nsource\n\n\nlast_index\n\n last_index (x, o)\n\nFinds the last index of occurence of x in o (returns -1 if no occurence)\n\ntest_eq(last_index(9, [1, 2, 9, 3, 4, 9, 10]), 5)\ntest_eq(last_index(6, [1, 2, 9, 3, 4, 9, 10]), -1)\n\n\nsource\n\n\nfilter_dict\n\n filter_dict (d, func)\n\nFilter a dict using func, applied to keys and values\n\nletters = {o:chr(o) for o in range(65,73)}\nletters\n\n{65: 'A', 66: 'B', 67: 'C', 68: 'D', 69: 'E', 70: 'F', 71: 'G', 72: 'H'}\n\n\n\nfilter_dict(letters, lambda k,v: k<67 or v in 'FG')\n\n{65: 'A', 66: 'B', 70: 'F', 71: 'G'}\n\n\n\nsource\n\n\nfilter_keys\n\n filter_keys (d, func)\n\nFilter a dict using func, applied to keys\n\nfilter_keys(letters, lt(67))\n\n{65: 'A', 66: 'B'}\n\n\n\nsource\n\n\nfilter_values\n\n filter_values (d, func)\n\nFilter a dict using func, applied to values\n\nfilter_values(letters, in_('FG'))\n\n{70: 'F', 71: 'G'}\n\n\n\nsource\n\n\ncycle\n\n cycle (o)\n\nLike itertools.cycle except creates list of Nones if o is empty\n\ntest_eq(itertools.islice(cycle([1,2,3]),5), [1,2,3,1,2])\ntest_eq(itertools.islice(cycle([]),3), [None]*3)\ntest_eq(itertools.islice(cycle(None),3), [None]*3)\ntest_eq(itertools.islice(cycle(1),3), [1,1,1])\n\n\nsource\n\n\nzip_cycle\n\n zip_cycle (x, *args)\n\nLike itertools.zip_longest but cycles through elements of all but first argument\n\ntest_eq(zip_cycle([1,2,3,4],list('abc')), [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'a')])\n\n\nsource\n\n\nsorted_ex\n\n sorted_ex (iterable, key=None, reverse=False)\n\nLike sorted, but if key is str use attrgetter; if int use itemgetter\n\nsource\n\n\nnot_\n\n not_ (f)\n\nCreate new function that negates result of f\n\ndef f(a): return a>0\ntest_eq(f(1),True)\ntest_eq(not_(f)(1),False)\ntest_eq(not_(f)(a=-1),True)\n\n\nsource\n\n\nargwhere\n\n argwhere (iterable, f, negate=False, **kwargs)\n\nLike filter_ex, but return indices for matching items\n\nsource\n\n\nfilter_ex\n\n filter_ex (iterable, f=<function noop>, negate=False, gen=False,\n **kwargs)\n\nLike filter, but passing kwargs to f, defaulting f to noop, and adding negate and gen\n\nsource\n\n\nrange_of\n\n range_of (a, b=None, step=None)\n\nAll indices of collection a, if a is a collection, otherwise range\n\ntest_eq(range_of([1,1,1,1]), [0,1,2,3])\ntest_eq(range_of(4), [0,1,2,3])\n\n\nsource\n\n\nrenumerate\n\n renumerate (iterable, start=0)\n\nSame as enumerate, but returns index as 2nd element instead of 1st\n\ntest_eq(renumerate('abc'), (('a',0),('b',1),('c',2)))\n\n\nsource\n\n\nfirst\n\n first (x, f=None, negate=False, **kwargs)\n\nFirst element of x, optionally filtered by f, or None if missing\n\ntest_eq(first(['a', 'b', 'c', 'd', 'e']), 'a')\ntest_eq(first([False]), False)\ntest_eq(first([False], noop), None)\n\n\nsource\n\n\nonly\n\n only (o)\n\nReturn the only item of o, raise if o doesn’t have exactly one item\n\nsource\n\n\nnested_attr\n\n nested_attr (o, attr, default=None)\n\nSame as getattr, but if attr includes a ., then looks inside nested objects\n\na = SimpleNamespace(b=(SimpleNamespace(c=1)))\ntest_eq(nested_attr(a, 'b.c'), getattr(getattr(a, 'b'), 'c'))\ntest_eq(nested_attr(a, 'b.d'), None)\n\n\nsource\n\n\nnested_setdefault\n\n nested_setdefault (o, attr, default)\n\nSame as setdefault, but if attr includes a ., then looks inside nested objects\n\nsource\n\n\nnested_callable\n\n nested_callable (o, attr)\n\nSame as nested_attr but if not found will return noop\n\na = SimpleNamespace(b=(SimpleNamespace(c=1)))\ntest_eq(nested_callable(a, 'b.c'), getattr(getattr(a, 'b'), 'c'))\ntest_eq(nested_callable(a, 'b.d'), noop)\n\n\nsource\n\n\nnested_idx\n\n nested_idx (coll, *idxs)\n\nIndex into nested collections, dicts, etc, with idxs\n\na = {'b':[1,{'c':2}]}\ntest_eq(nested_idx(a, 'nope'), None)\ntest_eq(nested_idx(a, 'nope', 'nup'), None)\ntest_eq(nested_idx(a, 'b', 3), None)\ntest_eq(nested_idx(a), a)\ntest_eq(nested_idx(a, 'b'), [1,{'c':2}])\ntest_eq(nested_idx(a, 'b', 1), {'c':2})\ntest_eq(nested_idx(a, 'b', 1, 'c'), 2)\n\n\na = SimpleNamespace(b=[1,{'c':2}])\ntest_eq(nested_idx(a, 'nope'), None)\ntest_eq(nested_idx(a, 'nope', 'nup'), None)\ntest_eq(nested_idx(a, 'b', 3), None)\ntest_eq(nested_idx(a), a)\ntest_eq(nested_idx(a, 'b'), [1,{'c':2}])\ntest_eq(nested_idx(a, 'b', 1), {'c':2})\ntest_eq(nested_idx(a, 'b', 1, 'c'), 2)\n\n\nsource\n\n\nset_nested_idx\n\n set_nested_idx (coll, value, *idxs)\n\nSet value indexed like `nested_idx\n\nset_nested_idx(a, 3, 'b', 0)\ntest_eq(nested_idx(a, 'b', 0), 3)\n\n\nsource\n\n\nval2idx\n\n val2idx (x)\n\nDict from value to index\n\ntest_eq(val2idx([1,2,3]), {3:2,1:0,2:1})\n\n\nsource\n\n\nuniqueify\n\n uniqueify (x, sort=False, bidir=False, start=None)\n\nUnique elements in x, optional sort, optional return reverse correspondence, optional prepend with elements.\n\nt = [1,1,0,5,0,3]\ntest_eq(uniqueify(t),[1,0,5,3])\ntest_eq(uniqueify(t, sort=True),[0,1,3,5])\ntest_eq(uniqueify(t, start=[7,8,6]), [7,8,6,1,0,5,3])\nv,o = uniqueify(t, bidir=True)\ntest_eq(v,[1,0,5,3])\ntest_eq(o,{1:0, 0: 1, 5: 2, 3: 3})\nv,o = uniqueify(t, sort=True, bidir=True)\ntest_eq(v,[0,1,3,5])\ntest_eq(o,{0:0, 1: 1, 3: 2, 5: 3})\n\n\nsource\n\n\nloop_first_last\n\n loop_first_last (values)\n\nIterate and generate a tuple with a flag for first and last value.\n\ntest_eq(loop_first_last(range(3)), [(True,False,0), (False,False,1), (False,True,2)])\n\n\nsource\n\n\nloop_first\n\n loop_first (values)\n\nIterate and generate a tuple with a flag for first value.\n\ntest_eq(loop_first(range(3)), [(True,0), (False,1), (False,2)])\n\n\nsource\n\n\nloop_last\n\n loop_last (values)\n\nIterate and generate a tuple with a flag for last value.\n\ntest_eq(loop_last(range(3)), [(False,0), (False,1), (True,2)])\n\n\nsource\n\n\nfirst_match\n\n first_match (lst, f, default=None)\n\nFirst element of lst matching predicate f, or default if none\n\na = [0,2,4,5,6,7,10]\ntest_eq(first_match(a, lambda o:o%2), 3)\n\n\nsource\n\n\nlast_match\n\n last_match (lst, f, default=None)\n\nLast element of lst matching predicate f, or default if none\n\ntest_eq(last_match(a, lambda o:o%2), 5)", + "crumbs": [ + "Basic functionality" + ] + }, + { + "objectID": "basics.html#fastuple", + "href": "basics.html#fastuple", + "title": "Basic functionality", + "section": "fastuple", + "text": "fastuple\nA tuple with extended functionality.\n\nsource\n\nfastuple\n\n fastuple (x=None, *rest)\n\nA tuple with elementwise ops and more friendly init behavior\n\n\nFriendly init behavior\nCommon failure modes when trying to initialize a tuple in python:\ntuple(3)\n> TypeError: 'int' object is not iterable\nor\ntuple(3, 4)\n> TypeError: tuple expected at most 1 arguments, got 2\nHowever, fastuple allows you to define tuples like this and in the usual way:\n\ntest_eq(fastuple(3), (3,))\ntest_eq(fastuple(3,4), (3, 4))\ntest_eq(fastuple((3,4)), (3, 4))\n\n\n\nElementwise operations\n\nsource\n\nfastuple.add\n\n fastuple.add (*args)\n\n+ is already defined in tuple for concat, so use add instead\n\ntest_eq(fastuple.add((1,1),(2,2)), (3,3))\ntest_eq_type(fastuple(1,1).add(2), fastuple(3,3))\ntest_eq(fastuple('1','2').add('2'), fastuple('12','22'))\n\n\nsource\n\n\nfastuple.mul\n\n fastuple.mul (*args)\n\n* is already defined in tuple for replicating, so use mul instead\n\ntest_eq_type(fastuple(1,1).mul(2), fastuple(2,2))\n\n\n\n\nOther Elementwise Operations\nAdditionally, the following elementwise operations are available: - le: less than or equal - eq: equal - gt: greater than - min: minimum of\n\ntest_eq(fastuple(3,1).le(1), (False, True))\ntest_eq(fastuple(3,1).eq(1), (False, True))\ntest_eq(fastuple(3,1).gt(1), (True, False))\ntest_eq(fastuple(3,1).min(2), (2,1))\n\nYou can also do other elementwise operations like negate a fastuple, or subtract two fastuples:\n\ntest_eq(-fastuple(1,2), (-1,-2))\ntest_eq(~fastuple(1,0,1), (False,True,False))\n\ntest_eq(fastuple(1,1)-fastuple(2,2), (-1,-1))\n\n\ntest_eq(type(fastuple(1)), fastuple)\ntest_eq_type(fastuple(1,2), fastuple(1,2))\ntest_ne(fastuple(1,2), fastuple(1,3))\ntest_eq(fastuple(), ())", + "crumbs": [ + "Basic functionality" + ] + }, + { + "objectID": "basics.html#functions-on-functions", + "href": "basics.html#functions-on-functions", + "title": "Basic functionality", + "section": "Functions on Functions", + "text": "Functions on Functions\nUtilities for functional programming or for defining, modifying, or debugging functions.\n\nsource\n\nbind\n\n bind (func, *pargs, **pkwargs)\n\nSame as partial, except you can use arg0 arg1 etc param placeholders\nbind is the same as partial, but also allows you to reorder positional arguments using variable name(s) arg{i} where i refers to the zero-indexed positional argument. bind as implemented currently only supports reordering of up to the first 5 positional arguments.\nConsider the function myfunc below, which has 3 positional arguments. These arguments can be referenced as arg0, arg1, and arg1, respectively.\n\ndef myfn(a,b,c,d=1,e=2): return(a,b,c,d,e)\n\nIn the below example we bind the positional arguments of myfn as follows:\n\nThe second input 14, referenced by arg1, is substituted for the first positional argument.\nWe supply a default value of 17 for the second positional argument.\nThe first input 19, referenced by arg0, is subsituted for the third positional argument.\n\n\ntest_eq(bind(myfn, arg1, 17, arg0, e=3)(19,14), (14,17,19,1,3))\n\nIn this next example:\n\nWe set the default value to 17 for the first positional argument.\nThe first input 19 refrenced by arg0, becomes the second positional argument.\nThe second input 14 becomes the third positional argument.\nWe override the default the value for named argument e to 3.\n\n\ntest_eq(bind(myfn, 17, arg0, e=3)(19,14), (17,19,14,1,3))\n\nThis is an example of using bind like partial and do not reorder any arguments:\n\ntest_eq(bind(myfn)(17,19,14), (17,19,14,1,2))\n\nbind can also be used to change default values. In the below example, we use the first input 3 to override the default value of the named argument e, and supply default values for the first three positional arguments:\n\ntest_eq(bind(myfn, 17,19,14,e=arg0)(3), (17,19,14,1,3))\n\n\nsource\n\n\nmapt\n\n mapt (func, *iterables)\n\nTuplified map\n\nt = [0,1,2,3]\ntest_eq(mapt(operator.neg, t), (0,-1,-2,-3))\n\n\nsource\n\n\nmap_ex\n\n map_ex (iterable, f, *args, gen=False, **kwargs)\n\nLike map, but use bind, and supports str and indexing\n\ntest_eq(map_ex(t,operator.neg), [0,-1,-2,-3])\n\nIf f is a string then it is treated as a format string to create the mapping:\n\ntest_eq(map_ex(t, '#{}#'), ['#0#','#1#','#2#','#3#'])\n\nIf f is a dictionary (or anything supporting __getitem__) then it is indexed to create the mapping:\n\ntest_eq(map_ex(t, list('abcd')), list('abcd'))\n\nYou can also pass the same arg params that bind accepts:\n\ndef f(a=None,b=None): return b\ntest_eq(map_ex(t, f, b=arg0), range(4))\n\n\nsource\n\n\ncompose\n\n compose (*funcs, order=None)\n\nCreate a function that composes all functions in funcs, passing along remaining *args and **kwargs to all\n\nf1 = lambda o,p=0: (o*2)+p\nf2 = lambda o,p=1: (o+1)/p\ntest_eq(f2(f1(3)), compose(f1,f2)(3))\ntest_eq(f2(f1(3,p=3),p=3), compose(f1,f2)(3,p=3))\ntest_eq(f2(f1(3, 3), 3), compose(f1,f2)(3, 3))\n\nf1.order = 1\ntest_eq(f1(f2(3)), compose(f1,f2, order=\"order\")(3))\n\n\nsource\n\n\nmaps\n\n maps (*args, retain=<function noop>)\n\nLike map, except funcs are composed first\n\ntest_eq(maps([1]), [1])\ntest_eq(maps(operator.neg, [1,2]), [-1,-2])\ntest_eq(maps(operator.neg, operator.neg, [1,2]), [1,2])\n\n\nsource\n\n\npartialler\n\n partialler (f, *args, order=None, **kwargs)\n\nLike functools.partial but also copies over docstring\n\ndef _f(x,a=1):\n \"test func\"\n return x-a\n_f.order=1\n\nf = partialler(_f, 2)\ntest_eq(f.order, 1)\ntest_eq(f(3), -1)\nf = partialler(_f, a=2, order=3)\ntest_eq(f.__doc__, \"test func\")\ntest_eq(f.order, 3)\ntest_eq(f(3), _f(3,2))\n\n\nclass partial0:\n \"Like `partialler`, but args passed to callable are inserted at started, instead of at end\"\n def __init__(self, f, *args, order=None, **kwargs):\n self.f,self.args,self.kwargs = f,args,kwargs\n self.order = ifnone(order, getattr(f,'order',None))\n self.__doc__ = f.__doc__\n\n def __call__(self, *args, **kwargs): return self.f(*args, *self.args, **kwargs, **self.kwargs)\n\n\nf = partial0(_f, 2)\ntest_eq(f.order, 1)\ntest_eq(f(3), 1) # NB: different to `partialler` example\n\n\nsource\n\n\ninstantiate\n\n instantiate (t)\n\nInstantiate t if it’s a type, otherwise do nothing\n\ntest_eq_type(instantiate(int), 0)\ntest_eq_type(instantiate(1), 1)\n\n\nsource\n\n\nusing_attr\n\n using_attr (f, attr)\n\nConstruct a function which applies f to the argument’s attribute attr\n\nt = Path('/a/b.txt')\nf = using_attr(str.upper, 'name')\ntest_eq(f(t), 'B.TXT')\n\n\n\nSelf (with an uppercase S)\nA Concise Way To Create Lambdas\nThis is a concise way to create lambdas that are calling methods on an object (note the capitalization!)\nSelf.sum(), for instance, is a shortcut for lambda o: o.sum().\n\nf = Self.sum()\nx = np.array([3.,1])\ntest_eq(f(x), 4.)\n\n# This is equivalent to above\nf = lambda o: o.sum()\nx = np.array([3.,1])\ntest_eq(f(x), 4.)\n\nf = Self.argmin()\narr = np.array([1,2,3,4,5])\ntest_eq(f(arr), arr.argmin())\n\nf = Self.sum().is_integer()\nx = np.array([3.,1])\ntest_eq(f(x), True)\n\nf = Self.sum().real.is_integer()\nx = np.array([3.,1])\ntest_eq(f(x), True)\n\nf = Self.imag()\ntest_eq(f(3), 0)\n\nf = Self[1]\ntest_eq(f(x), 1)\n\nSelf is also callable, which creates a function which calls any function passed to it, using the arguments passed to Self:\n\ndef f(a, b=3): return a+b+2\ndef g(a, b=3): return a*b\nfg = Self(1,b=2)\nlist(map(fg, [f,g]))\n\n[5, 2]", + "crumbs": [ + "Basic functionality" + ] + }, + { + "objectID": "basics.html#patching", + "href": "basics.html#patching", + "title": "Basic functionality", + "section": "Patching", + "text": "Patching\n\nsource\n\ncopy_func\n\n copy_func (f)\n\nCopy a non-builtin function (NB copy.copy does not work for this)\nSometimes it may be desirable to make a copy of a function that doesn’t point to the original object. When you use Python’s built in copy.copy or copy.deepcopy to copy a function, you get a reference to the original object:\n\nimport copy as cp\n\n\ndef foo(): pass\na = cp.copy(foo)\nb = cp.deepcopy(foo)\n\na.someattr = 'hello' # since a and b point at the same object, updating a will update b\ntest_eq(b.someattr, 'hello')\n\nassert a is foo and b is foo\n\nHowever, with copy_func, you can retrieve a copy of a function without a reference to the original object:\n\nc = copy_func(foo) # c is an indpendent object\nassert c is not foo\n\n\ndef g(x, *, y=3): return x+y\ntest_eq(copy_func(g)(4), 7)\n\n\nsource\n\n\npatch_to\n\n patch_to (cls, as_prop=False, cls_method=False)\n\nDecorator: add f to cls\nThe @patch_to decorator allows you to monkey patch a function into a class as a method:\n\nclass _T3(int): pass \n\n@patch_to(_T3)\ndef func1(self, a): return self+a\n\nt = _T3(1) # we initilized `t` to a type int = 1\ntest_eq(t.func1(2), 3) # we add 2 to `t`, so 2 + 1 = 3\n\nYou can access instance properties in the usual way via self:\n\nclass _T4():\n def __init__(self, g): self.g = g\n \n@patch_to(_T4)\ndef greet(self, x): return self.g + x\n \nt = _T4('hello ') # this sets self.g = 'helllo '\ntest_eq(t.greet('world'), 'hello world') #t.greet('world') will append 'world' to 'hello '\n\nYou can instead specify that the method should be a class method by setting cls_method=True:\n\nclass _T5(int): attr = 3 # attr is a class attribute we will access in a later method\n \n@patch_to(_T5, cls_method=True)\ndef func(cls, x): return cls.attr + x # you can access class attributes in the normal way\n\ntest_eq(_T5.func(4), 7)\n\nAdditionally you can specify that the function you want to patch should be a class attribute with as_prop=True:\n\n@patch_to(_T5, as_prop=True)\ndef add_ten(self): return self + 10\n\nt = _T5(4)\ntest_eq(t.add_ten, 14)\n\nInstead of passing one class to the @patch_to decorator, you can pass multiple classes in a tuple to simulteanously patch more than one class with the same method:\n\nclass _T6(int): pass\nclass _T7(int): pass\n\n@patch_to((_T6,_T7))\ndef func_mult(self, a): return self*a\n\nt = _T6(2)\ntest_eq(t.func_mult(4), 8)\nt = _T7(2)\ntest_eq(t.func_mult(4), 8)\n\n\nsource\n\n\npatch\n\n patch (f=None, as_prop=False, cls_method=False)\n\nDecorator: add f to the first parameter’s class (based on f’s type annotations)\n@patch is an alternative to @patch_to that allows you similarly monkey patch class(es) by using type annotations:\n\nclass _T8(int): pass \n\n@patch\ndef func(self:_T8, a): return self+a\n\nt = _T8(1) # we initilized `t` to a type int = 1\ntest_eq(t.func(3), 4) # we add 3 to `t`, so 3 + 1 = 4\ntest_eq(t.func.__qualname__, '_T8.func')\n\nSimilarly to patch_to, you can supply a union of classes instead of a single class in your type annotations to patch multiple classes:\n\nclass _T9(int): pass \n\n@patch\ndef func2(x:_T8|_T9, a): return x*a # will patch both _T8 and _T9\n\nt = _T8(2)\ntest_eq(t.func2(4), 8)\ntest_eq(t.func2.__qualname__, '_T8.func2')\n\nt = _T9(2)\ntest_eq(t.func2(4), 8)\ntest_eq(t.func2.__qualname__, '_T9.func2')\n\nJust like patch_to decorator you can use as_prop and cls_method parameters with patch decorator:\n\n@patch(as_prop=True)\ndef add_ten(self:_T5): return self + 10\n\nt = _T5(4)\ntest_eq(t.add_ten, 14)\n\n\nclass _T5(int): attr = 3 # attr is a class attribute we will access in a later method\n \n@patch(cls_method=True)\ndef func(cls:_T5, x): return cls.attr + x # you can access class attributes in the normal way\n\ntest_eq(_T5.func(4), 7)\n\n\nsource\n\n\npatch_property\n\n patch_property (f)\n\nDeprecated; use patch(as_prop=True) instead\nPatching classmethod shouldn’t affect how python’s inheritance works\n\nclass FastParent: pass\n\n@patch(cls_method=True)\ndef type_cls(cls: FastParent): return cls\n\nclass FastChild(FastParent): pass\n\nparent = FastParent()\ntest_eq(parent.type_cls(), FastParent)\n\nchild = FastChild()\ntest_eq(child.type_cls(), FastChild)", + "crumbs": [ + "Basic functionality" + ] + }, + { + "objectID": "basics.html#other-helpers", + "href": "basics.html#other-helpers", + "title": "Basic functionality", + "section": "Other Helpers", + "text": "Other Helpers\n\nsource\n\ncompile_re\n\n compile_re (pat)\n\nCompile pat if it’s not None\n\nassert compile_re(None) is None\nassert compile_re('a').match('ab')\n\n\nsource\n\nImportEnum\n\n ImportEnum (value, names=None, module=None, qualname=None, type=None,\n start=1)\n\nAn Enum that can have its values imported\n\n_T = ImportEnum('_T', {'foobar':1, 'goobar':2})\n_T.imports()\ntest_eq(foobar, _T.foobar)\ntest_eq(goobar, _T.goobar)\n\n\nsource\n\n\nStrEnum\n\n StrEnum (value, names=None, module=None, qualname=None, type=None,\n start=1)\n\nAn ImportEnum that behaves like a str\n\nsource\n\n\n\nstr_enum\n\n str_enum (name, *vals)\n\nSimplified creation of StrEnum types\n\nsource\n\nValEnum\n\n ValEnum (value, names=None, module=None, qualname=None, type=None,\n start=1)\n\nAn ImportEnum that stringifies using values\n\n_T = str_enum('_T', 'a', 'b')\ntest_eq(f'{_T.a}', 'a')\ntest_eq(_T.a, 'a')\ntest_eq(list(_T.__members__), ['a','b'])\nprint(_T.a, _T.a.upper())\n\na A\n\n\n\nsource\n\n\nStateful\n\n Stateful (*args, **kwargs)\n\nA base class/mixin for objects that should not serialize all their state\n\nclass _T(Stateful):\n def __init__(self):\n super().__init__()\n self.a=1\n self._state['test']=2\n\nt = _T()\nt2 = pickle.loads(pickle.dumps(t))\ntest_eq(t.a,1)\ntest_eq(t._state['test'],2)\ntest_eq(t2.a,1)\ntest_eq(t2._state,{})\n\nOverride _init_state to do any necessary setup steps that are required during __init__ or during deserialization (e.g. pickle.load). Here’s an example of how Stateful simplifies the official Python example for Handling Stateful Objects.\n\nclass TextReader(Stateful):\n \"\"\"Print and number lines in a text file.\"\"\"\n _stateattrs=('file',)\n def __init__(self, filename):\n self.filename,self.lineno = filename,0\n super().__init__()\n\n def readline(self):\n self.lineno += 1\n line = self.file.readline()\n if line: return f\"{self.lineno}: {line.strip()}\"\n\n def _init_state(self):\n self.file = open(self.filename)\n for _ in range(self.lineno): self.file.readline()\n\n\nreader = TextReader(\"00_test.ipynb\")\nprint(reader.readline())\nprint(reader.readline())\n\nnew_reader = pickle.loads(pickle.dumps(reader))\nprint(reader.readline())\n\n1: {\n2: \"cells\": [\n3: {\n\n\n\nsource\n\n\n\nNotStr\n\n NotStr (s)\n\nBehaves like a str, but isn’t an instance of one\n\ns = NotStr(\"hello\")\nassert not isinstance(s, str)\ntest_eq(s, 'hello')\ntest_eq(s*2, 'hellohello')\ntest_eq(len(s), 5)\n\n\nsource\n\nPrettyString\nLittle hack to get strings to show properly in Jupyter.\nAllow strings with special characters to render properly in Jupyter. Without calling print() strings with special characters are displayed like so:\n\nwith_special_chars='a string\\nwith\\nnew\\nlines and\\ttabs'\nwith_special_chars\n\n'a string\\nwith\\nnew\\nlines and\\ttabs'\n\n\nWe can correct this with PrettyString:\n\nPrettyString(with_special_chars)\n\na string\nwith\nnew\nlines and tabs\n\n\n\nsource\n\n\n\neven_mults\n\n even_mults (start, stop, n)\n\nBuild log-stepped array from start to stop in n steps.\n\ntest_eq(even_mults(2,8,3), [2,4,8])\ntest_eq(even_mults(2,32,5), [2,4,8,16,32])\ntest_eq(even_mults(2,8,1), 8)\n\n\nsource\n\n\nnum_cpus\n\n num_cpus ()\n\nGet number of cpus\n\nnum_cpus()\n\n8\n\n\n\nsource\n\n\nadd_props\n\n add_props (f, g=None, n=2)\n\nCreate properties passing each of range(n) to f\n\nclass _T(): a,b = add_props(lambda i,x:i*2)\n\nt = _T()\ntest_eq(t.a,0)\ntest_eq(t.b,2)\n\n\nclass _T(): \n def __init__(self, v): self.v=v\n def _set(i, self, v): self.v[i] = v\n a,b = add_props(lambda i,x: x.v[i], _set)\n\nt = _T([0,2])\ntest_eq(t.a,0)\ntest_eq(t.b,2)\nt.a = t.a+1\nt.b = 3\ntest_eq(t.a,1)\ntest_eq(t.b,3)\n\n\nsource\n\n\ntyped\n\n typed (f)\n\nDecorator to check param and return types at runtime\ntyped validates argument types at runtime. This is in contrast to MyPy which only offers static type checking.\nFor example, a TypeError will be raised if we try to pass an integer into the first argument of the below function:\n\n@typed\ndef discount(price:int, pct:float): \n return (1-pct) * price\n\nwith ExceptionExpected(TypeError): discount(100.0, .1)\n\nWe can also optionally allow multiple types by enumarating the types in a tuple as illustrated below:\n\ndef discount(price:int|float, pct:float): \n return (1-pct) * price\n\nassert 90.0 == discount(100.0, .1)\n\n\n@typed\ndef foo(a:int, b:str='a'): return a\ntest_eq(foo(1, '2'), 1)\n\nwith ExceptionExpected(TypeError): foo(1,2)\n\n@typed\ndef foo()->str: return 1\nwith ExceptionExpected(TypeError): foo()\n\n@typed\ndef foo()->str: return '1'\nassert foo()\n\ntyped works with classes, too:\n\nclass Foo:\n @typed\n def __init__(self, a:int, b: int, c:str): pass\n @typed\n def test(cls, d:str): return d\n\nwith ExceptionExpected(TypeError): Foo(1, 2, 3) \nwith ExceptionExpected(TypeError): Foo(1,2, 'a string').test(10)\n\n\nsource\n\n\nexec_new\n\n exec_new (code)\n\nExecute code in a new environment and return it\n\ng = exec_new('a=1')\ntest_eq(g['a'], 1)\n\n\nsource\n\n\nexec_import\n\n exec_import (mod, sym)\n\nImport sym from mod in a new environment\n\nsource\n\n\nstr2bool\n\n str2bool (s)\n\nCase-insensitive convert string s too a bool (y,yes,t,true,on,1->True)\nTrue values are ‘y’, ‘yes’, ‘t’, ‘true’, ‘on’, and ‘1’; false values are ‘n’, ‘no’, ‘f’, ‘false’, ‘off’, and ‘0’. Raises ValueError if ‘val’ is anything else.\n\nfor o in \"y YES t True on 1\".split(): assert str2bool(o)\nfor o in \"n no FALSE off 0\".split(): assert not str2bool(o)\nfor o in 0,None,'',False: assert not str2bool(o)\nfor o in 1,True: assert str2bool(o)", + "crumbs": [ + "Basic functionality" + ] + }, + { + "objectID": "basics.html#notebook-functions", + "href": "basics.html#notebook-functions", + "title": "Basic functionality", + "section": "Notebook functions", + "text": "Notebook functions\n\n\nipython_shell\n\n ipython_shell ()\n\nSame as get_ipython but returns False if not in IPython\n\n\n\nin_ipython\n\n in_ipython ()\n\nCheck if code is running in some kind of IPython environment\n\n\n\nin_colab\n\n in_colab ()\n\nCheck if the code is running in Google Colaboratory\n\n\n\nin_jupyter\n\n in_jupyter ()\n\nCheck if the code is running in a jupyter notebook\n\n\n\nin_notebook\n\n in_notebook ()\n\nCheck if the code is running in a jupyter notebook\nThese variables are available as booleans in fastcore.basics as IN_IPYTHON, IN_JUPYTER, IN_COLAB and IN_NOTEBOOK.\n\nIN_IPYTHON, IN_JUPYTER, IN_COLAB, IN_NOTEBOOK\n\n(True, True, False, True)", + "crumbs": [ + "Basic functionality" + ] + }, + { + "objectID": "xtras.html", + "href": "xtras.html", + "title": "Utility functions", + "section": "", + "text": "Utilities (other than extensions to Pathlib.Path) for dealing with IO.\n\nsource\n\n\n\n walk (path:pathlib.Path|str, symlinks:bool=True, keep_file:<built-\n infunctioncallable>=<function ret_true>, keep_folder:<built-\n infunctioncallable>=<function ret_true>, skip_folder:<built-\n infunctioncallable>=<function ret_false>, func:<built-\n infunctioncallable>=<function join>, ret_folders:bool=False)\n\nGenerator version of os.walk, using functions to filter files and folders\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\npath\nPath | str\n\npath to start searching\n\n\nsymlinks\nbool\nTrue\nfollow symlinks?\n\n\nkeep_file\ncallable\nret_true\nfunction that returns True for wanted files\n\n\nkeep_folder\ncallable\nret_true\nfunction that returns True for folders to enter\n\n\nskip_folder\ncallable\nret_false\nfunction that returns True for folders to skip\n\n\nfunc\ncallable\njoin\nfunction to apply to each matched file\n\n\nret_folders\nbool\nFalse\nreturn folders, not just files\n\n\n\n\nsource\n\n\n\n\n globtastic (path:pathlib.Path|str, recursive:bool=True,\n symlinks:bool=True, file_glob:str=None, file_re:str=None,\n folder_re:str=None, skip_file_glob:str=None,\n skip_file_re:str=None, skip_folder_re:str=None, func:<built-\n infunctioncallable>=<function join>, ret_folders:bool=False)\n\nA more powerful glob, including regex matches, symlink handling, and skip parameters\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\npath\nPath | str\n\npath to start searching\n\n\nrecursive\nbool\nTrue\nsearch subfolders\n\n\nsymlinks\nbool\nTrue\nfollow symlinks?\n\n\nfile_glob\nstr\nNone\nOnly include files matching glob\n\n\nfile_re\nstr\nNone\nOnly include files matching regex\n\n\nfolder_re\nstr\nNone\nOnly enter folders matching regex\n\n\nskip_file_glob\nstr\nNone\nSkip files matching glob\n\n\nskip_file_re\nstr\nNone\nSkip files matching regex\n\n\nskip_folder_re\nstr\nNone\nSkip folders matching regex,\n\n\nfunc\ncallable\njoin\nfunction to apply to each matched file\n\n\nret_folders\nbool\nFalse\nreturn folders, not just files\n\n\nReturns\nL\n\nPaths to matched files\n\n\n\n\nglobtastic('.', skip_folder_re='^[_.]', folder_re='core', file_glob='*.*py*', file_re='c')\n\n(#5) ['./fastcore/docments.py','./fastcore/dispatch.py','./fastcore/basics.py','./fastcore/docscrape.py','./fastcore/script.py']\n\n\n\nsource\n\n\n\n\n maybe_open (f, mode='r', **kwargs)\n\nContext manager: open f if it is a path (and close on exit)\nThis is useful for functions where you want to accept a path or file. maybe_open will not close your file handle if you pass one in.\n\ndef _f(fn):\n with maybe_open(fn) as f: return f.encoding\n\nfname = '00_test.ipynb'\nsys_encoding = 'cp1252' if sys.platform == 'win32' else 'UTF-8'\ntest_eq(_f(fname), sys_encoding)\nwith open(fname) as fh: test_eq(_f(fh), sys_encoding)\n\nFor example, we can use this to reimplement imghdr.what from the Python standard library, which is written in Python 3.9 as:\n\nfrom fastcore import imghdr\n\n\ndef what(file, h=None):\n f = None\n try:\n if h is None:\n if isinstance(file, (str,os.PathLike)):\n f = open(file, 'rb')\n h = f.read(32)\n else:\n location = file.tell()\n h = file.read(32)\n file.seek(location)\n for tf in imghdr.tests:\n res = tf(h, f)\n if res: return res\n finally:\n if f: f.close()\n return None\n\nHere’s an example of the use of this function:\n\nfname = 'images/puppy.jpg'\nwhat(fname)\n\n'jpeg'\n\n\nWith maybe_open, Self, and L.map_first, we can rewrite this in a much more concise and (in our opinion) clear way:\n\ndef what(file, h=None):\n if h is None:\n with maybe_open(file, 'rb') as f: h = f.peek(32)\n return L(imghdr.tests).map_first(Self(h,file))\n\n…and we can check that it still works:\n\ntest_eq(what(fname), 'jpeg')\n\n…along with the version passing a file handle:\n\nwith open(fname,'rb') as f: test_eq(what(f), 'jpeg')\n\n…along with the h parameter version:\n\nwith open(fname,'rb') as f: test_eq(what(None, h=f.read(32)), 'jpeg')\n\n\nsource\n\n\n\n\n mkdir (path, exist_ok=False, parents=False, overwrite=False, **kwargs)\n\nCreates and returns a directory defined by path, optionally removing previous existing directory if overwrite is True\n\nwith tempfile.TemporaryDirectory() as d:\n path = Path(os.path.join(d, 'new_dir'))\n new_dir = mkdir(path)\n assert new_dir.exists()\n test_eq(new_dir, path)\n \n # test overwrite\n with open(new_dir/'test.txt', 'w') as f: f.writelines('test')\n test_eq(len(list(walk(new_dir))), 1) # assert file is present\n new_dir = mkdir(new_dir, overwrite=True)\n test_eq(len(list(walk(new_dir))), 0) # assert file was deleted\n\n\nsource\n\n\n\n\n image_size (fn)\n\nTuple of (w,h) for png, gif, or jpg; None otherwise\n\ntest_eq(image_size(fname), (1200,803))\n\n\nsource\n\n\n\n\n bunzip (fn)\n\nbunzip fn, raising exception if output already exists\n\nf = Path('files/test.txt')\nif f.exists(): f.unlink()\nbunzip('files/test.txt.bz2')\nt = f.open().readlines()\ntest_eq(len(t),1)\ntest_eq(t[0], 'test\\n')\nf.unlink()\n\n\nsource\n\n\n\n\n loads (s, **kw)\n\nSame as json.loads, but handles None\n\nsource\n\n\n\n\n loads_multi (s:str)\n\nGenerator of >=0 decoded json dicts, possibly with non-json ignored text at start and end\n\ntst = \"\"\"\n# ignored\n{ \"a\":1 }\nhello\n{\n\"b\":2\n}\n\"\"\"\n\ntest_eq(list(loads_multi(tst)), [{'a': 1}, {'b': 2}])\n\n\nsource\n\n\n\n\n dumps (obj, **kw)\n\nSame as json.dumps, but uses ujson if available\n\nsource\n\n\n\n\n untar_dir (fname, dest, rename=False, overwrite=False)\n\nuntar file into dest, creating a directory if the root contains more than one item\n\ndef test_untar(foldername, rename=False, **kwargs):\n with tempfile.TemporaryDirectory() as d:\n nm = os.path.join(d, 'a')\n shutil.make_archive(nm, 'gztar', **kwargs)\n with tempfile.TemporaryDirectory() as d2:\n d2 = Path(d2)\n untar_dir(nm+'.tar.gz', d2, rename=rename)\n test_eq(d2.ls(), [d2/foldername])\n\nIf the contents of fname contain just one file or directory, it is placed directly in dest:\n\n# using `base_dir` in `make_archive` results in `images` directory included in file names\ntest_untar('images', base_dir='images')\n\nIf rename then the directory created is named based on the archive, without extension:\n\ntest_untar('a', base_dir='images', rename=True)\n\nIf the contents of fname contain multiple files and directories, a new folder in dest is created with the same name as fname (but without extension):\n\n# using `root_dir` in `make_archive` results in `images` directory *not* included in file names\ntest_untar('a', root_dir='images')\n\n\nsource\n\n\n\n\n repo_details (url)\n\nTuple of owner,name from ssh or https git repo url\n\ntest_eq(repo_details('https://github.com/fastai/fastai.git'), ['fastai', 'fastai'])\ntest_eq(repo_details('git@github.com:fastai/nbdev.git\\n'), ['fastai', 'nbdev'])\n\n\nsource\n\n\n\n\n run (cmd, *rest, same_in_win=False, ignore_ex=False, as_bytes=False,\n stderr=False)\n\nPass cmd (splitting with shlex if string) to subprocess.run; return stdout; raise IOError if fails\nYou can pass a string (which will be split based on standard shell rules), a list, or pass args directly:\n\nrun('echo', same_in_win=True)\nrun('pip', '--version', same_in_win=True)\nrun(['pip', '--version'], same_in_win=True)\n\n'pip 23.3.1 from /Users/jhoward/miniconda3/lib/python3.11/site-packages/pip (python 3.11)'\n\n\n\nif sys.platform == 'win32':\n assert 'ipynb' in run('cmd /c dir /p')\n assert 'ipynb' in run(['cmd', '/c', 'dir', '/p'])\n assert 'ipynb' in run('cmd', '/c', 'dir', '/p')\nelse:\n assert 'ipynb' in run('ls -ls')\n assert 'ipynb' in run(['ls', '-l'])\n assert 'ipynb' in run('ls', '-l')\n\nSome commands fail in non-error situations, like grep. Use ignore_ex in those cases, which will return a tuple of stdout and returncode:\n\nif sys.platform == 'win32':\n test_eq(run('cmd /c findstr asdfds 00_test.ipynb', ignore_ex=True)[0], 1)\nelse:\n test_eq(run('grep asdfds 00_test.ipynb', ignore_ex=True)[0], 1)\n\nrun automatically decodes returned bytes to a str. Use as_bytes to skip that:\n\nif sys.platform == 'win32':\n test_eq(run('cmd /c echo hi'), 'hi')\nelse:\n test_eq(run('echo hi', as_bytes=True), b'hi\\n')\n\n\nsource\n\n\n\n\n open_file (fn, mode='r', **kwargs)\n\nOpen a file, with optional compression if gz or bz2 suffix\n\nsource\n\n\n\n\n save_pickle (fn, o)\n\nSave a pickle file, to a file name or opened file\n\nsource\n\n\n\n\n load_pickle (fn)\n\nLoad a pickle file from a file name or opened file\n\nfor suf in '.pkl','.bz2','.gz':\n # delete=False is added for Windows\n # https://stackoverflow.com/questions/23212435/permission-denied-to-write-to-my-temporary-file\n with tempfile.NamedTemporaryFile(suffix=suf, delete=False) as f:\n fn = Path(f.name)\n save_pickle(fn, 't')\n t = load_pickle(fn)\n f.close()\n test_eq(t,'t')\n\n\nsource\n\n\n\n\n parse_env (s:str=None, fn:Union[str,pathlib.Path]=None)\n\nParse a shell-style environment string or file\n\ntestf = \"\"\"# comment\n # another comment\n export FOO=\"bar#baz\"\nBAR=thing # comment \"ok\"\n baz='thong'\nQUX=quux\nexport ZAP = \"zip\" # more comments\n FOOBAR = 42 # trailing space and comment\"\"\"\n\nexp = dict(FOO='bar#baz', BAR='thing', baz='thong', QUX='quux', ZAP='zip', FOOBAR='42')\n\ntest_eq(parse_env(testf), exp)\n\n\nsource\n\n\n\n\n expand_wildcards (code)\n\nExpand all wildcard imports in the given code string.\n\ninp = \"\"\"from math import *\nfrom os import *\nfrom random import *\ndef func(): return sin(pi) + path.join('a', 'b') + randint(1, 10)\"\"\"\n\nexp = \"\"\"from math import pi, sin\nfrom os import path\nfrom random import randint\ndef func(): return sin(pi) + path.join('a', 'b') + randint(1, 10)\"\"\"\n\ntest_eq(expand_wildcards(inp), exp)\n\ninp = \"\"\"from itertools import *\ndef func(): pass\"\"\"\ntest_eq(expand_wildcards(inp), inp)\n\ninp = \"\"\"def outer():\n from math import *\n def inner():\n from os import *\n return sin(pi) + path.join('a', 'b')\"\"\"\n\nexp = \"\"\"def outer():\n from math import pi, sin\n def inner():\n from os import path\n return sin(pi) + path.join('a', 'b')\"\"\"\n\ntest_eq(expand_wildcards(inp), exp)", + "crumbs": [ + "Utility functions" + ] + }, + { + "objectID": "xtras.html#file-functions", + "href": "xtras.html#file-functions", + "title": "Utility functions", + "section": "", + "text": "Utilities (other than extensions to Pathlib.Path) for dealing with IO.\n\nsource\n\n\n\n walk (path:pathlib.Path|str, symlinks:bool=True, keep_file:<built-\n infunctioncallable>=<function ret_true>, keep_folder:<built-\n infunctioncallable>=<function ret_true>, skip_folder:<built-\n infunctioncallable>=<function ret_false>, func:<built-\n infunctioncallable>=<function join>, ret_folders:bool=False)\n\nGenerator version of os.walk, using functions to filter files and folders\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\npath\nPath | str\n\npath to start searching\n\n\nsymlinks\nbool\nTrue\nfollow symlinks?\n\n\nkeep_file\ncallable\nret_true\nfunction that returns True for wanted files\n\n\nkeep_folder\ncallable\nret_true\nfunction that returns True for folders to enter\n\n\nskip_folder\ncallable\nret_false\nfunction that returns True for folders to skip\n\n\nfunc\ncallable\njoin\nfunction to apply to each matched file\n\n\nret_folders\nbool\nFalse\nreturn folders, not just files\n\n\n\n\nsource\n\n\n\n\n globtastic (path:pathlib.Path|str, recursive:bool=True,\n symlinks:bool=True, file_glob:str=None, file_re:str=None,\n folder_re:str=None, skip_file_glob:str=None,\n skip_file_re:str=None, skip_folder_re:str=None, func:<built-\n infunctioncallable>=<function join>, ret_folders:bool=False)\n\nA more powerful glob, including regex matches, symlink handling, and skip parameters\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\npath\nPath | str\n\npath to start searching\n\n\nrecursive\nbool\nTrue\nsearch subfolders\n\n\nsymlinks\nbool\nTrue\nfollow symlinks?\n\n\nfile_glob\nstr\nNone\nOnly include files matching glob\n\n\nfile_re\nstr\nNone\nOnly include files matching regex\n\n\nfolder_re\nstr\nNone\nOnly enter folders matching regex\n\n\nskip_file_glob\nstr\nNone\nSkip files matching glob\n\n\nskip_file_re\nstr\nNone\nSkip files matching regex\n\n\nskip_folder_re\nstr\nNone\nSkip folders matching regex,\n\n\nfunc\ncallable\njoin\nfunction to apply to each matched file\n\n\nret_folders\nbool\nFalse\nreturn folders, not just files\n\n\nReturns\nL\n\nPaths to matched files\n\n\n\n\nglobtastic('.', skip_folder_re='^[_.]', folder_re='core', file_glob='*.*py*', file_re='c')\n\n(#5) ['./fastcore/docments.py','./fastcore/dispatch.py','./fastcore/basics.py','./fastcore/docscrape.py','./fastcore/script.py']\n\n\n\nsource\n\n\n\n\n maybe_open (f, mode='r', **kwargs)\n\nContext manager: open f if it is a path (and close on exit)\nThis is useful for functions where you want to accept a path or file. maybe_open will not close your file handle if you pass one in.\n\ndef _f(fn):\n with maybe_open(fn) as f: return f.encoding\n\nfname = '00_test.ipynb'\nsys_encoding = 'cp1252' if sys.platform == 'win32' else 'UTF-8'\ntest_eq(_f(fname), sys_encoding)\nwith open(fname) as fh: test_eq(_f(fh), sys_encoding)\n\nFor example, we can use this to reimplement imghdr.what from the Python standard library, which is written in Python 3.9 as:\n\nfrom fastcore import imghdr\n\n\ndef what(file, h=None):\n f = None\n try:\n if h is None:\n if isinstance(file, (str,os.PathLike)):\n f = open(file, 'rb')\n h = f.read(32)\n else:\n location = file.tell()\n h = file.read(32)\n file.seek(location)\n for tf in imghdr.tests:\n res = tf(h, f)\n if res: return res\n finally:\n if f: f.close()\n return None\n\nHere’s an example of the use of this function:\n\nfname = 'images/puppy.jpg'\nwhat(fname)\n\n'jpeg'\n\n\nWith maybe_open, Self, and L.map_first, we can rewrite this in a much more concise and (in our opinion) clear way:\n\ndef what(file, h=None):\n if h is None:\n with maybe_open(file, 'rb') as f: h = f.peek(32)\n return L(imghdr.tests).map_first(Self(h,file))\n\n…and we can check that it still works:\n\ntest_eq(what(fname), 'jpeg')\n\n…along with the version passing a file handle:\n\nwith open(fname,'rb') as f: test_eq(what(f), 'jpeg')\n\n…along with the h parameter version:\n\nwith open(fname,'rb') as f: test_eq(what(None, h=f.read(32)), 'jpeg')\n\n\nsource\n\n\n\n\n mkdir (path, exist_ok=False, parents=False, overwrite=False, **kwargs)\n\nCreates and returns a directory defined by path, optionally removing previous existing directory if overwrite is True\n\nwith tempfile.TemporaryDirectory() as d:\n path = Path(os.path.join(d, 'new_dir'))\n new_dir = mkdir(path)\n assert new_dir.exists()\n test_eq(new_dir, path)\n \n # test overwrite\n with open(new_dir/'test.txt', 'w') as f: f.writelines('test')\n test_eq(len(list(walk(new_dir))), 1) # assert file is present\n new_dir = mkdir(new_dir, overwrite=True)\n test_eq(len(list(walk(new_dir))), 0) # assert file was deleted\n\n\nsource\n\n\n\n\n image_size (fn)\n\nTuple of (w,h) for png, gif, or jpg; None otherwise\n\ntest_eq(image_size(fname), (1200,803))\n\n\nsource\n\n\n\n\n bunzip (fn)\n\nbunzip fn, raising exception if output already exists\n\nf = Path('files/test.txt')\nif f.exists(): f.unlink()\nbunzip('files/test.txt.bz2')\nt = f.open().readlines()\ntest_eq(len(t),1)\ntest_eq(t[0], 'test\\n')\nf.unlink()\n\n\nsource\n\n\n\n\n loads (s, **kw)\n\nSame as json.loads, but handles None\n\nsource\n\n\n\n\n loads_multi (s:str)\n\nGenerator of >=0 decoded json dicts, possibly with non-json ignored text at start and end\n\ntst = \"\"\"\n# ignored\n{ \"a\":1 }\nhello\n{\n\"b\":2\n}\n\"\"\"\n\ntest_eq(list(loads_multi(tst)), [{'a': 1}, {'b': 2}])\n\n\nsource\n\n\n\n\n dumps (obj, **kw)\n\nSame as json.dumps, but uses ujson if available\n\nsource\n\n\n\n\n untar_dir (fname, dest, rename=False, overwrite=False)\n\nuntar file into dest, creating a directory if the root contains more than one item\n\ndef test_untar(foldername, rename=False, **kwargs):\n with tempfile.TemporaryDirectory() as d:\n nm = os.path.join(d, 'a')\n shutil.make_archive(nm, 'gztar', **kwargs)\n with tempfile.TemporaryDirectory() as d2:\n d2 = Path(d2)\n untar_dir(nm+'.tar.gz', d2, rename=rename)\n test_eq(d2.ls(), [d2/foldername])\n\nIf the contents of fname contain just one file or directory, it is placed directly in dest:\n\n# using `base_dir` in `make_archive` results in `images` directory included in file names\ntest_untar('images', base_dir='images')\n\nIf rename then the directory created is named based on the archive, without extension:\n\ntest_untar('a', base_dir='images', rename=True)\n\nIf the contents of fname contain multiple files and directories, a new folder in dest is created with the same name as fname (but without extension):\n\n# using `root_dir` in `make_archive` results in `images` directory *not* included in file names\ntest_untar('a', root_dir='images')\n\n\nsource\n\n\n\n\n repo_details (url)\n\nTuple of owner,name from ssh or https git repo url\n\ntest_eq(repo_details('https://github.com/fastai/fastai.git'), ['fastai', 'fastai'])\ntest_eq(repo_details('git@github.com:fastai/nbdev.git\\n'), ['fastai', 'nbdev'])\n\n\nsource\n\n\n\n\n run (cmd, *rest, same_in_win=False, ignore_ex=False, as_bytes=False,\n stderr=False)\n\nPass cmd (splitting with shlex if string) to subprocess.run; return stdout; raise IOError if fails\nYou can pass a string (which will be split based on standard shell rules), a list, or pass args directly:\n\nrun('echo', same_in_win=True)\nrun('pip', '--version', same_in_win=True)\nrun(['pip', '--version'], same_in_win=True)\n\n'pip 23.3.1 from /Users/jhoward/miniconda3/lib/python3.11/site-packages/pip (python 3.11)'\n\n\n\nif sys.platform == 'win32':\n assert 'ipynb' in run('cmd /c dir /p')\n assert 'ipynb' in run(['cmd', '/c', 'dir', '/p'])\n assert 'ipynb' in run('cmd', '/c', 'dir', '/p')\nelse:\n assert 'ipynb' in run('ls -ls')\n assert 'ipynb' in run(['ls', '-l'])\n assert 'ipynb' in run('ls', '-l')\n\nSome commands fail in non-error situations, like grep. Use ignore_ex in those cases, which will return a tuple of stdout and returncode:\n\nif sys.platform == 'win32':\n test_eq(run('cmd /c findstr asdfds 00_test.ipynb', ignore_ex=True)[0], 1)\nelse:\n test_eq(run('grep asdfds 00_test.ipynb', ignore_ex=True)[0], 1)\n\nrun automatically decodes returned bytes to a str. Use as_bytes to skip that:\n\nif sys.platform == 'win32':\n test_eq(run('cmd /c echo hi'), 'hi')\nelse:\n test_eq(run('echo hi', as_bytes=True), b'hi\\n')\n\n\nsource\n\n\n\n\n open_file (fn, mode='r', **kwargs)\n\nOpen a file, with optional compression if gz or bz2 suffix\n\nsource\n\n\n\n\n save_pickle (fn, o)\n\nSave a pickle file, to a file name or opened file\n\nsource\n\n\n\n\n load_pickle (fn)\n\nLoad a pickle file from a file name or opened file\n\nfor suf in '.pkl','.bz2','.gz':\n # delete=False is added for Windows\n # https://stackoverflow.com/questions/23212435/permission-denied-to-write-to-my-temporary-file\n with tempfile.NamedTemporaryFile(suffix=suf, delete=False) as f:\n fn = Path(f.name)\n save_pickle(fn, 't')\n t = load_pickle(fn)\n f.close()\n test_eq(t,'t')\n\n\nsource\n\n\n\n\n parse_env (s:str=None, fn:Union[str,pathlib.Path]=None)\n\nParse a shell-style environment string or file\n\ntestf = \"\"\"# comment\n # another comment\n export FOO=\"bar#baz\"\nBAR=thing # comment \"ok\"\n baz='thong'\nQUX=quux\nexport ZAP = \"zip\" # more comments\n FOOBAR = 42 # trailing space and comment\"\"\"\n\nexp = dict(FOO='bar#baz', BAR='thing', baz='thong', QUX='quux', ZAP='zip', FOOBAR='42')\n\ntest_eq(parse_env(testf), exp)\n\n\nsource\n\n\n\n\n expand_wildcards (code)\n\nExpand all wildcard imports in the given code string.\n\ninp = \"\"\"from math import *\nfrom os import *\nfrom random import *\ndef func(): return sin(pi) + path.join('a', 'b') + randint(1, 10)\"\"\"\n\nexp = \"\"\"from math import pi, sin\nfrom os import path\nfrom random import randint\ndef func(): return sin(pi) + path.join('a', 'b') + randint(1, 10)\"\"\"\n\ntest_eq(expand_wildcards(inp), exp)\n\ninp = \"\"\"from itertools import *\ndef func(): pass\"\"\"\ntest_eq(expand_wildcards(inp), inp)\n\ninp = \"\"\"def outer():\n from math import *\n def inner():\n from os import *\n return sin(pi) + path.join('a', 'b')\"\"\"\n\nexp = \"\"\"def outer():\n from math import pi, sin\n def inner():\n from os import path\n return sin(pi) + path.join('a', 'b')\"\"\"\n\ntest_eq(expand_wildcards(inp), exp)", + "crumbs": [ + "Utility functions" + ] + }, + { + "objectID": "xtras.html#collections", + "href": "xtras.html#collections", + "title": "Utility functions", + "section": "Collections", + "text": "Collections\n\nsource\n\ndict2obj\n\n dict2obj (d, list_func=<class 'fastcore.foundation.L'>, dict_func=<class\n 'fastcore.basics.AttrDict'>)\n\nConvert (possibly nested) dicts (or lists of dicts) to AttrDict\nThis is a convenience to give you “dotted” access to (possibly nested) dictionaries, e.g:\n\nd1 = dict(a=1, b=dict(c=2,d=3))\nd2 = dict2obj(d1)\ntest_eq(d2.b.c, 2)\ntest_eq(d2.b['c'], 2)\n\nIt can also be used on lists of dicts.\n\n_list_of_dicts = [d1, d1]\nds = dict2obj(_list_of_dicts)\ntest_eq(ds[0].b.c, 2)\n\n\nsource\n\n\nobj2dict\n\n obj2dict (d)\n\nConvert (possibly nested) AttrDicts (or lists of AttrDicts) to dict\nobj2dict can be used to reverse what is done by dict2obj:\n\ntest_eq(obj2dict(d2), d1)\ntest_eq(obj2dict(ds), _list_of_dicts)\n\n\nsource\n\n\nrepr_dict\n\n repr_dict (d)\n\nPrint nested dicts and lists, such as returned by dict2obj\n\nprint(repr_dict(d2))\n\n- a: 1\n- b: \n - c: 2\n - d: 3\n\n\n\nsource\n\n\nis_listy\n\n is_listy (x)\n\nisinstance(x, (tuple,list,L,slice,Generator))\n\nassert is_listy((1,))\nassert is_listy([1])\nassert is_listy(L([1]))\nassert is_listy(slice(2))\nassert not is_listy(array([1]))\n\n\nsource\n\n\nmapped\n\n mapped (f, it)\n\nmap f over it, unless it’s not listy, in which case return f(it)\n\ndef _f(x,a=1): return x-a\n\ntest_eq(mapped(_f,1),0)\ntest_eq(mapped(_f,[1,2]),[0,1])\ntest_eq(mapped(_f,(1,)),(0,))", + "crumbs": [ + "Utility functions" + ] + }, + { + "objectID": "xtras.html#extensions-to-pathlib.path", + "href": "xtras.html#extensions-to-pathlib.path", + "title": "Utility functions", + "section": "Extensions to Pathlib.Path", + "text": "Extensions to Pathlib.Path\nThe following methods are added to the standard python libary Pathlib.Path.\n\nsource\n\nPath.readlines\n\n Path.readlines (hint=-1, encoding='utf8')\n\nRead the content of self\n\nsource\n\n\nPath.read_json\n\n Path.read_json (encoding=None, errors=None)\n\nSame as read_text followed by loads\n\nsource\n\n\nPath.mk_write\n\n Path.mk_write (data, encoding=None, errors=None, mode=511)\n\nMake all parent dirs of self, and write data\n\nsource\n\n\nPath.relpath\n\n Path.relpath (start=None)\n\nSame as os.path.relpath, but returns a Path, and resolves symlinks\n\np = Path('../fastcore/').resolve()\np\n\nPath('/Users/jhoward/Documents/GitHub/fastcore/fastcore')\n\n\n\np.relpath(Path.cwd())\n\nPath('../fastcore')\n\n\n\nsource\n\n\nPath.ls\n\n Path.ls (n_max=None, file_type=None, file_exts=None)\n\nContents of path as a list\nWe add an ls() method to pathlib.Path which is simply defined as list(Path.iterdir()), mainly for convenience in REPL environments such as notebooks.\n\npath = Path()\nt = path.ls()\nassert len(t)>0\nt1 = path.ls(10)\ntest_eq(len(t1), 10)\nt2 = path.ls(file_exts='.ipynb')\nassert len(t)>len(t2)\nt[0]\n\nPath('000_tour.ipynb')\n\n\nYou can also pass an optional file_type MIME prefix and/or a list of file extensions.\n\nlib_path = (path/'../fastcore')\ntxt_files=lib_path.ls(file_type='text')\nassert len(txt_files) > 0 and txt_files[0].suffix=='.py'\nipy_files=path.ls(file_exts=['.ipynb'])\nassert len(ipy_files) > 0 and ipy_files[0].suffix=='.ipynb'\ntxt_files[0],ipy_files[0]\n\n(Path('../fastcore/shutil.py'), Path('000_tour.ipynb'))\n\n\n\nsource\n\n\nPath.__repr__\n\n Path.__repr__ ()\n\nReturn repr(self).\nfastai also updates the repr of Path such that, if Path.BASE_PATH is defined, all paths are printed relative to that path (as long as they are contained in Path.BASE_PATH:\n\nt = ipy_files[0].absolute()\ntry:\n Path.BASE_PATH = t.parent.parent\n test_eq(repr(t), f\"Path('nbs/{t.name}')\")\nfinally: Path.BASE_PATH = None\n\n\nsource\n\n\nPath.delete\n\n Path.delete ()\n\nDelete a file, symlink, or directory tree", + "crumbs": [ + "Utility functions" + ] + }, + { + "objectID": "xtras.html#reindexing-collections", + "href": "xtras.html#reindexing-collections", + "title": "Utility functions", + "section": "Reindexing Collections", + "text": "Reindexing Collections\n\nsource\n\nReindexCollection\n\n ReindexCollection (coll, idxs=None, cache=None, tfm=<function noop>)\n\nReindexes collection coll with indices idxs and optional LRU cache of size cache\nThis is useful when constructing batches or organizing data in a particular manner (i.e. for deep learning). This class is primarly used in organizing data for language models in fastai.\nYou can supply a custom index upon instantiation with the idxs argument, or you can call the reindex method to supply a new index for your collection.\nHere is how you can reindex a list such that the elements are reversed:\n\nrc=ReindexCollection(['a', 'b', 'c', 'd', 'e'], idxs=[4,3,2,1,0])\nlist(rc)\n\n['e', 'd', 'c', 'b', 'a']\n\n\nAlternatively, you can use the reindex method:\n\nsource\n\nReindexCollection.reindex\n\n ReindexCollection.reindex (idxs)\n\nReplace self.idxs with idxs\n\nrc=ReindexCollection(['a', 'b', 'c', 'd', 'e'])\nrc.reindex([4,3,2,1,0])\nlist(rc)\n\n['e', 'd', 'c', 'b', 'a']\n\n\nYou can optionally specify a LRU cache, which uses functools.lru_cache upon instantiation:\n\nsz = 50\nt = ReindexCollection(L.range(sz), cache=2)\n\n#trigger a cache hit by indexing into the same element multiple times\nt[0], t[0]\nt._get.cache_info()\n\nCacheInfo(hits=1, misses=1, maxsize=2, currsize=1)\n\n\nYou can optionally clear the LRU cache by calling the cache_clear method:\n\nsource\n\n\nReindexCollection.cache_clear\n\n ReindexCollection.cache_clear ()\n\nClear LRU cache\n\nsz = 50\nt = ReindexCollection(L.range(sz), cache=2)\n\n#trigger a cache hit by indexing into the same element multiple times\nt[0], t[0]\nt.cache_clear()\nt._get.cache_info()\n\nCacheInfo(hits=0, misses=0, maxsize=2, currsize=0)\n\n\n\nsource\n\n\nReindexCollection.shuffle\n\n ReindexCollection.shuffle ()\n\nRandomly shuffle indices\nNote that an ordered index is automatically constructed for the data structure even if one is not supplied.\n\nrc=ReindexCollection(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])\nrc.shuffle()\nlist(rc)\n\n['a', 'h', 'f', 'b', 'c', 'g', 'e', 'd']\n\n\n\nsz = 50\nt = ReindexCollection(L.range(sz), cache=2)\ntest_eq(list(t), range(sz))\ntest_eq(t[sz-1], sz-1)\ntest_eq(t._get.cache_info().hits, 1)\nt.shuffle()\ntest_eq(t._get.cache_info().hits, 1)\ntest_ne(list(t), range(sz))\ntest_eq(set(t), set(range(sz)))\nt.cache_clear()\ntest_eq(t._get.cache_info().hits, 0)\ntest_eq(t.count(0), 1)", + "crumbs": [ + "Utility functions" + ] + }, + { + "objectID": "xtras.html#other-helpers", + "href": "xtras.html#other-helpers", + "title": "Utility functions", + "section": "Other Helpers", + "text": "Other Helpers\n\nsource\n\nget_source_link\n\n get_source_link (func)\n\nReturn link to func in source code\nget_source_link allows you get a link to source code related to an object. For nbdev related projects such as fastcore, we can get the full link to a GitHub repo. For nbdev projects, be sure to properly set the git_url in settings.ini (derived from lib_name and branch on top of the prefix you will need to adapt) so that those links are correct.\nFor example, below we get the link to fastcore.test.test_eq:\n\nfrom fastcore.test import test_eq\n\n\nassert 'fastcore/test.py' in get_source_link(test_eq)\nassert get_source_link(test_eq).startswith('https://github.com/fastai/fastcore')\nget_source_link(test_eq)\n\n'https://github.com/fastai/fastcore/tree/master/fastcore/test.py#L35'\n\n\n\nsource\n\n\ntruncstr\n\n truncstr (s:str, maxlen:int, suf:str='…', space='')\n\nTruncate s to length maxlen, adding suffix suf if truncated\n\nw = 'abacadabra'\ntest_eq(truncstr(w, 10), w)\ntest_eq(truncstr(w, 5), 'abac…')\ntest_eq(truncstr(w, 5, suf=''), 'abaca')\ntest_eq(truncstr(w, 11, space='_'), w+\"_\")\ntest_eq(truncstr(w, 10, space='_'), w[:-1]+'…')\ntest_eq(truncstr(w, 5, suf='!!'), 'aba!!')\n\n\nsource\n\n\nsparkline\n\n sparkline (data, mn=None, mx=None, empty_zero=False)\n\nSparkline for data, with Nones (and zero, if empty_zero) shown as empty column\n\ndata = [9,6,None,1,4,0,8,15,10]\nprint(f'without \"empty_zero\": {sparkline(data, empty_zero=False)}')\nprint(f' with \"empty_zero\": {sparkline(data, empty_zero=True )}')\n\nwithout \"empty_zero\": ▅▂ ▁▂▁▃▇▅\n with \"empty_zero\": ▅▂ ▁▂ ▃▇▅\n\n\nYou can set a maximum and minimum for the y-axis of the sparkline with the arguments mn and mx respectively:\n\nsparkline([1,2,3,400], mn=0, mx=3)\n\n'▂▅▇▇'\n\n\n\nsource\n\n\nmodify_exception\n\n modify_exception (e:Exception, msg:str=None, replace:bool=False)\n\nModifies e with a custom message attached\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ne\nException\n\nAn exception\n\n\nmsg\nstr\nNone\nA custom message\n\n\nreplace\nbool\nFalse\nWhether to replace e.args with [msg]\n\n\nReturns\nException\n\n\n\n\n\n\nmsg = \"This is my custom message!\"\n\ntest_fail(lambda: (_ for _ in ()).throw(modify_exception(Exception(), None)), contains='')\ntest_fail(lambda: (_ for _ in ()).throw(modify_exception(Exception(), msg)), contains=msg)\ntest_fail(lambda: (_ for _ in ()).throw(modify_exception(Exception(\"The first message\"), msg)), contains=\"The first message This is my custom message!\")\ntest_fail(lambda: (_ for _ in ()).throw(modify_exception(Exception(\"The first message\"), msg, True)), contains=\"This is my custom message!\")\n\n\nsource\n\n\nround_multiple\n\n round_multiple (x, mult, round_down=False)\n\nRound x to nearest multiple of mult\n\ntest_eq(round_multiple(63,32), 64)\ntest_eq(round_multiple(50,32), 64)\ntest_eq(round_multiple(40,32), 32)\ntest_eq(round_multiple( 0,32), 0)\ntest_eq(round_multiple(63,32, round_down=True), 32)\ntest_eq(round_multiple((63,40),32), (64,32))\n\n\nsource\n\n\nset_num_threads\n\n set_num_threads (nt)\n\nGet numpy (and others) to use nt threads\nThis sets the number of threads consistently for many tools, by:\n\nSet the following environment variables equal to nt: OPENBLAS_NUM_THREADS,NUMEXPR_NUM_THREADS,OMP_NUM_THREADS,MKL_NUM_THREADS\nSets nt threads for numpy and pytorch.\n\n\nsource\n\n\njoin_path_file\n\n join_path_file (file, path, ext='')\n\nReturn path/file if file is a string or a Path, file otherwise\n\npath = Path.cwd()/'_tmp'/'tst'\nf = join_path_file('tst.txt', path)\nassert path.exists()\ntest_eq(f, path/'tst.txt')\nwith open(f, 'w') as f_: assert join_path_file(f_, path) == f_\nshutil.rmtree(Path.cwd()/'_tmp')\n\n\nsource\n\n\nautostart\n\n autostart (g)\n\nDecorator that automatically starts a generator\n\nsource\n\nEventTimer\n\n EventTimer (store=5, span=60)\n\nAn event timer with history of store items of time span\nAdd events with add, and get number of events and their frequency (freq).\n\n# Random wait function for testing\ndef _randwait(): yield from (sleep(random.random()/200) for _ in range(100))\n\nc = EventTimer(store=5, span=0.03)\nfor o in _randwait(): c.add(1)\nprint(f'Num Events: {c.events}, Freq/sec: {c.freq:.01f}')\nprint('Most recent: ', sparkline(c.hist), *L(c.hist).map('{:.01f}'))\n\nNum Events: 3, Freq/sec: 316.2\nMost recent: ▇▁▂▃▁ 288.7 227.7 246.5 256.5 217.9\n\n\n\nsource\n\n\n\nstringfmt_names\n\n stringfmt_names (s:str)\n\nUnique brace-delimited names in s\n\ns = '/pulls/{pull_number}/reviews/{review_id}'\ntest_eq(stringfmt_names(s), ['pull_number','review_id'])\n\n\nsource\n\nPartialFormatter\n\n PartialFormatter ()\n\nA string.Formatter that doesn’t error on missing fields, and tracks missing fields and unused args\n\nsource\n\n\n\npartial_format\n\n partial_format (s:str, **kwargs)\n\nstring format s, ignoring missing field errors, returning missing and extra fields\nThe result is a tuple of (formatted_string,missing_fields,extra_fields), e.g:\n\nres,missing,xtra = partial_format(s, pull_number=1, foo=2)\ntest_eq(res, '/pulls/1/reviews/{review_id}')\ntest_eq(missing, ['review_id'])\ntest_eq(xtra, {'foo':2})\n\n\nsource\n\n\nutc2local\n\n utc2local (dt:datetime.datetime)\n\nConvert dt from UTC to local time\n\ndt = datetime(2000,1,1,12)\nprint(f'{dt} UTC is {utc2local(dt)} local time')\n\n2000-01-01 12:00:00 UTC is 2000-01-01 22:00:00+10:00 local time\n\n\n\nsource\n\n\nlocal2utc\n\n local2utc (dt:datetime.datetime)\n\nConvert dt from local to UTC time\n\nprint(f'{dt} local is {local2utc(dt)} UTC time')\n\n2000-01-01 12:00:00 local is 2000-01-01 02:00:00+00:00 UTC time\n\n\n\nsource\n\n\ntrace\n\n trace (f)\n\nAdd set_trace to an existing function f\nYou can add a breakpoint to an existing function, e.g:\nPath.cwd = trace(Path.cwd)\nPath.cwd()\nNow, when the function is called it will drop you into the debugger. Note, you must issue the s command when you begin to step into the function that is being traced.\n\nsource\n\n\nmodified_env\n\n modified_env (*delete, **replace)\n\nContext manager temporarily modifying os.environ by deleting delete and replacing replace\n\n# USER isn't in Cloud Linux Environments\nenv_test = 'USERNAME' if sys.platform == \"win32\" else 'SHELL'\noldusr = os.environ[env_test]\n\nreplace_param = {env_test: 'a'}\nwith modified_env('PATH', **replace_param):\n test_eq(os.environ[env_test], 'a')\n assert 'PATH' not in os.environ\n\nassert 'PATH' in os.environ\ntest_eq(os.environ[env_test], oldusr)\n\n\nsource\n\nContextManagers\n\n ContextManagers (mgrs)\n\nWrapper for contextlib.ExitStack which enters a collection of context managers\n\nsource\n\n\n\nshufflish\n\n shufflish (x, pct=0.04)\n\nRandomly relocate items of x up to pct of len(x) from their starting location\n\nsource\n\n\nconsole_help\n\n console_help (libname:str)\n\nShow help for all console scripts from libname\n\n\n\n\nType\nDetails\n\n\n\n\nlibname\nstr\nname of library for console script listing\n\n\n\n\nsource\n\n\nhl_md\n\n hl_md (s, lang='xml', show=True)\n\nSyntax highlight s using lang.\nWhen we display code in a notebook, it’s nice to highlight it, so we create a function to simplify that:\n\nhl_md('<test><xml foo=\"bar\">a child</xml></test>')\n\n<test><xml foo=\"bar\">a child</xml></test>\n\n\n\nsource\n\n\ntype2str\n\n type2str (typ:type)\n\nStringify typ\n\ntest_eq(type2str(Optional[float]), 'Union[float, None]')\n\n\nsource\n\n\ndataclass_src\n\n dataclass_src (cls)\n\n\nfrom dataclasses import make_dataclass, dataclass\n\n\nDC = make_dataclass('DC', [('x', int), ('y', Optional[float], None), ('z', float, None)])\nprint(dataclass_src(DC))\n\n@dataclass\nclass DC:\n x: int\n y: Union[float, None] = None\n z: float = None\n\n\n\n\nsource\n\n\nnullable_dc\n\n nullable_dc (cls)\n\nLike dataclass, but default of None added to fields without defaults\n\n@nullable_dc\nclass Person: name: str; age: int; city: str = \"Unknown\"\nPerson(name=\"Bob\")\n\nPerson(name='Bob', age=None, city='Unknown')\n\n\n\nsource\n\n\nmake_nullable\n\n make_nullable (clas)\n\n\n@dataclass\nclass Person: name: str; age: int; city: str = \"Unknown\"\n\nmake_nullable(Person)\nPerson(\"Bob\", city='NY')\n\nPerson(name='Bob', age=None, city='NY')\n\n\n\nPerson(name=\"Bob\")\n\nPerson(name='Bob', age=None, city='Unknown')\n\n\n\nPerson(\"Bob\", 34)\n\nPerson(name='Bob', age=34, city='Unknown')\n\n\n\nsource\n\n\nmk_dataclass\n\n mk_dataclass (cls)\n\n\nclass Person: name: str; age: int; city: str = \"Unknown\"\n\nmk_dataclass(Person)\nPerson(name=\"Bob\")\n\nPerson(name='Bob', age=None, city='Unknown')\n\n\n\nsource\n\n\nflexicache\n\n flexicache (*funcs, maxsize=128)\n\nLike lru_cache, but customisable with policy funcs\nThis is a flexible lru cache function that you can pass a list of functions to. Those functions define the cache eviction policy. For instance, time_policy is provided for time-based cache eviction, and mtime_policy evicts based on a file’s modified-time changing. The policy functions are passed the last value that function returned was (initially None), and return a new value to indicate the cache has expired. When the cache expires, all functions are called with None to force getting new values.\n\nsource\n\n\ntime_policy\n\n time_policy (seconds)\n\nA flexicache policy that expires cached items after seconds have passed\n\nsource\n\n\nmtime_policy\n\n mtime_policy (filepath)\n\nA flexicache policy that expires cached items after filepath modified-time changes\n\n@flexicache(time_policy(10), mtime_policy('000_tour.ipynb'))\ndef cached_func(x, y): return x+y\n\ncached_func(1,2)\n\n3\n\n\n\n@flexicache(time_policy(10), mtime_policy('000_tour.ipynb'))\nasync def cached_func(x, y): return x+y\n\nawait cached_func(1,2)\nawait cached_func(1,2)\n\n3\n\n\n\nsource\n\n\ntimed_cache\n\n timed_cache (seconds=60, maxsize=128)\n\nLike lru_cache, but also with time-based eviction\nThis function is a small convenience wrapper for using flexicache with time_policy.\n\n@timed_cache(seconds=0.05, maxsize=2)\ndef cached_func(x): return x * 2, time()\n\n# basic caching\nresult1, time1 = cached_func(2)\ntest_eq(result1, 4)\nsleep(0.001)\nresult2, time2 = cached_func(2)\ntest_eq(result2, 4)\ntest_eq(time1, time2)\n\n# caching different values\nresult3, _ = cached_func(3)\ntest_eq(result3, 6)\n\n# maxsize\n_, time4 = cached_func(4)\n_, time2_new = cached_func(2)\ntest_close(time2, time2_new, eps=0.1)\n_, time3_new = cached_func(3)\ntest_ne(time3_new, time())\n\n# time expiration\nsleep(0.05)\n_, time4_new = cached_func(4)\ntest_ne(time4_new, time())", + "crumbs": [ + "Utility functions" + ] + }, + { + "objectID": "foundation.html", + "href": "foundation.html", + "title": "Foundation", + "section": "", + "text": "source\n\n\n\n working_directory (path)\n\nChange working directory to path and return to previous on exit.\n\nsource\n\n\n\n\n add_docs (cls, cls_doc=None, **docs)\n\nCopy values from docs to cls docstrings, and confirm all public methods are documented\nadd_docs allows you to add docstrings to a class and its associated methods. This function allows you to group docstrings together seperate from your code, which enables you to define one-line functions as well as organize your code more succintly. We believe this confers a number of benefits which we discuss in our style guide.\nSuppose you have the following undocumented class:\n\nclass T:\n def foo(self): pass\n def bar(self): pass\n\nYou can add documentation to this class like so:\n\nadd_docs(T, cls_doc=\"A docstring for the class.\",\n foo=\"The foo method.\",\n bar=\"The bar method.\")\n\nNow, docstrings will appear as expected:\n\ntest_eq(T.__doc__, \"A docstring for the class.\")\ntest_eq(T.foo.__doc__, \"The foo method.\")\ntest_eq(T.bar.__doc__, \"The bar method.\")\n\nadd_docs also validates that all of your public methods contain a docstring. If one of your methods is not documented, it will raise an error:\n\nclass T:\n def foo(self): pass\n def bar(self): pass\n\nf=lambda: add_docs(T, \"A docstring for the class.\", foo=\"The foo method.\")\ntest_fail(f, contains=\"Missing docs\")\n\n\nsource\n\n\n\n\n docs (cls)\n\nDecorator version of add_docs, using _docs dict\nInstead of using add_docs, you can use the decorator docs as shown below. Note that the docstring for the class can be set with the argument cls_doc:\n\n@docs\nclass _T:\n def f(self): pass\n def g(cls): pass\n \n _docs = dict(cls_doc=\"The class docstring\", \n f=\"The docstring for method f.\",\n g=\"A different docstring for method g.\")\n\n \ntest_eq(_T.__doc__, \"The class docstring\")\ntest_eq(_T.f.__doc__, \"The docstring for method f.\")\ntest_eq(_T.g.__doc__, \"A different docstring for method g.\")\n\nFor either the docs decorator or the add_docs function, you can still define your docstrings in the normal way. Below we set the docstring for the class as usual, but define the method docstrings through the _docs attribute:\n\n@docs\nclass _T:\n \"The class docstring\"\n def f(self): pass\n _docs = dict(f=\"The docstring for method f.\")\n\n \ntest_eq(_T.__doc__, \"The class docstring\")\ntest_eq(_T.f.__doc__, \"The docstring for method f.\")\n\n\n\n\n\n\n is_iter (o)\n\nTest whether o can be used in a for loop\n\nassert is_iter([1])\nassert not is_iter(array(1))\nassert is_iter(array([1,2]))\nassert (o for o in range(3))\n\n\nsource\n\n\n\n\n coll_repr (c, max_n=10)\n\nString repr of up to max_n items of (possibly lazy) collection c\ncoll_repr is used to provide a more informative __repr__ about list-like objects. coll_repr and is used by L to build a __repr__ that displays the length of a list in addition to a preview of a list.\nBelow is an example of the __repr__ string created for a list of 1000 elements:\n\ntest_eq(coll_repr(range(1000)), '(#1000) [0,1,2,3,4,5,6,7,8,9...]')\ntest_eq(coll_repr(range(1000), 5), '(#1000) [0,1,2,3,4...]')\ntest_eq(coll_repr(range(10), 5), '(#10) [0,1,2,3,4...]')\ntest_eq(coll_repr(range(5), 5), '(#5) [0,1,2,3,4]')\n\nWe can set the option max_n to optionally preview a specified number of items instead of the default:\n\ntest_eq(coll_repr(range(1000), max_n=5), '(#1000) [0,1,2,3,4...]')\n\n\nsource\n\n\n\n\n is_bool (x)\n\nCheck whether x is a bool or None\n\nsource\n\n\n\n\n mask2idxs (mask)\n\nConvert bool mask or index list to index L\n\ntest_eq(mask2idxs([False,True,False,True]), [1,3])\ntest_eq(mask2idxs(array([False,True,False,True])), [1,3])\ntest_eq(mask2idxs(array([1,2,3])), [1,2,3])\n\n\nsource\n\n\n\n\n cycle (o)\n\nLike itertools.cycle except creates list of Nones if o is empty\n\ntest_eq(itertools.islice(cycle([1,2,3]),5), [1,2,3,1,2])\ntest_eq(itertools.islice(cycle([]),3), [None]*3)\ntest_eq(itertools.islice(cycle(None),3), [None]*3)\ntest_eq(itertools.islice(cycle(1),3), [1,1,1])\n\n\nsource\n\n\n\n\n zip_cycle (x, *args)\n\nLike itertools.zip_longest but cycles through elements of all but first argument\n\ntest_eq(zip_cycle([1,2,3,4],list('abc')), [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'a')])\n\n\nsource\n\n\n\n\n is_indexer (idx)\n\nTest whether idx will index a single item in a list\nYou can, for example index a single item in a list with an integer or a 0-dimensional numpy array:\n\nassert is_indexer(1)\nassert is_indexer(np.array(1))\n\nHowever, you cannot index into single item in a list with another list or a numpy array with ndim > 0.\n\nassert not is_indexer([1, 2])\nassert not is_indexer(np.array([[1, 2], [3, 4]]))", + "crumbs": [ + "Foundation" + ] + }, + { + "objectID": "foundation.html#foundational-functions", + "href": "foundation.html#foundational-functions", + "title": "Foundation", + "section": "", + "text": "source\n\n\n\n working_directory (path)\n\nChange working directory to path and return to previous on exit.\n\nsource\n\n\n\n\n add_docs (cls, cls_doc=None, **docs)\n\nCopy values from docs to cls docstrings, and confirm all public methods are documented\nadd_docs allows you to add docstrings to a class and its associated methods. This function allows you to group docstrings together seperate from your code, which enables you to define one-line functions as well as organize your code more succintly. We believe this confers a number of benefits which we discuss in our style guide.\nSuppose you have the following undocumented class:\n\nclass T:\n def foo(self): pass\n def bar(self): pass\n\nYou can add documentation to this class like so:\n\nadd_docs(T, cls_doc=\"A docstring for the class.\",\n foo=\"The foo method.\",\n bar=\"The bar method.\")\n\nNow, docstrings will appear as expected:\n\ntest_eq(T.__doc__, \"A docstring for the class.\")\ntest_eq(T.foo.__doc__, \"The foo method.\")\ntest_eq(T.bar.__doc__, \"The bar method.\")\n\nadd_docs also validates that all of your public methods contain a docstring. If one of your methods is not documented, it will raise an error:\n\nclass T:\n def foo(self): pass\n def bar(self): pass\n\nf=lambda: add_docs(T, \"A docstring for the class.\", foo=\"The foo method.\")\ntest_fail(f, contains=\"Missing docs\")\n\n\nsource\n\n\n\n\n docs (cls)\n\nDecorator version of add_docs, using _docs dict\nInstead of using add_docs, you can use the decorator docs as shown below. Note that the docstring for the class can be set with the argument cls_doc:\n\n@docs\nclass _T:\n def f(self): pass\n def g(cls): pass\n \n _docs = dict(cls_doc=\"The class docstring\", \n f=\"The docstring for method f.\",\n g=\"A different docstring for method g.\")\n\n \ntest_eq(_T.__doc__, \"The class docstring\")\ntest_eq(_T.f.__doc__, \"The docstring for method f.\")\ntest_eq(_T.g.__doc__, \"A different docstring for method g.\")\n\nFor either the docs decorator or the add_docs function, you can still define your docstrings in the normal way. Below we set the docstring for the class as usual, but define the method docstrings through the _docs attribute:\n\n@docs\nclass _T:\n \"The class docstring\"\n def f(self): pass\n _docs = dict(f=\"The docstring for method f.\")\n\n \ntest_eq(_T.__doc__, \"The class docstring\")\ntest_eq(_T.f.__doc__, \"The docstring for method f.\")\n\n\n\n\n\n\n is_iter (o)\n\nTest whether o can be used in a for loop\n\nassert is_iter([1])\nassert not is_iter(array(1))\nassert is_iter(array([1,2]))\nassert (o for o in range(3))\n\n\nsource\n\n\n\n\n coll_repr (c, max_n=10)\n\nString repr of up to max_n items of (possibly lazy) collection c\ncoll_repr is used to provide a more informative __repr__ about list-like objects. coll_repr and is used by L to build a __repr__ that displays the length of a list in addition to a preview of a list.\nBelow is an example of the __repr__ string created for a list of 1000 elements:\n\ntest_eq(coll_repr(range(1000)), '(#1000) [0,1,2,3,4,5,6,7,8,9...]')\ntest_eq(coll_repr(range(1000), 5), '(#1000) [0,1,2,3,4...]')\ntest_eq(coll_repr(range(10), 5), '(#10) [0,1,2,3,4...]')\ntest_eq(coll_repr(range(5), 5), '(#5) [0,1,2,3,4]')\n\nWe can set the option max_n to optionally preview a specified number of items instead of the default:\n\ntest_eq(coll_repr(range(1000), max_n=5), '(#1000) [0,1,2,3,4...]')\n\n\nsource\n\n\n\n\n is_bool (x)\n\nCheck whether x is a bool or None\n\nsource\n\n\n\n\n mask2idxs (mask)\n\nConvert bool mask or index list to index L\n\ntest_eq(mask2idxs([False,True,False,True]), [1,3])\ntest_eq(mask2idxs(array([False,True,False,True])), [1,3])\ntest_eq(mask2idxs(array([1,2,3])), [1,2,3])\n\n\nsource\n\n\n\n\n cycle (o)\n\nLike itertools.cycle except creates list of Nones if o is empty\n\ntest_eq(itertools.islice(cycle([1,2,3]),5), [1,2,3,1,2])\ntest_eq(itertools.islice(cycle([]),3), [None]*3)\ntest_eq(itertools.islice(cycle(None),3), [None]*3)\ntest_eq(itertools.islice(cycle(1),3), [1,1,1])\n\n\nsource\n\n\n\n\n zip_cycle (x, *args)\n\nLike itertools.zip_longest but cycles through elements of all but first argument\n\ntest_eq(zip_cycle([1,2,3,4],list('abc')), [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'a')])\n\n\nsource\n\n\n\n\n is_indexer (idx)\n\nTest whether idx will index a single item in a list\nYou can, for example index a single item in a list with an integer or a 0-dimensional numpy array:\n\nassert is_indexer(1)\nassert is_indexer(np.array(1))\n\nHowever, you cannot index into single item in a list with another list or a numpy array with ndim > 0.\n\nassert not is_indexer([1, 2])\nassert not is_indexer(np.array([[1, 2], [3, 4]]))", + "crumbs": [ + "Foundation" + ] + }, + { + "objectID": "foundation.html#l-helpers", + "href": "foundation.html#l-helpers", + "title": "Foundation", + "section": "L helpers", + "text": "L helpers\n\nsource\n\nCollBase\n\n CollBase (items)\n\nBase class for composing a list of items\nColBase is a base class that emulates the functionality of a python list:\n\nclass _T(CollBase): pass\nl = _T([1,2,3,4,5])\n\ntest_eq(len(l), 5) # __len__\ntest_eq(l[-1], 5); test_eq(l[0], 1) #__getitem__\nl[2] = 100; test_eq(l[2], 100) # __set_item__\ndel l[0]; test_eq(len(l), 4) # __delitem__\ntest_eq(str(l), '[2, 100, 4, 5]') # __repr__\n\n\nsource\n\n\nL\n\n L (x=None, *args, **kwargs)\n\nBehaves like a list of items but can also index with list of indices or masks\nL is a drop in replacement for a python list. Inspired by NumPy, L, supports advanced indexing and has additional methods (outlined below) that provide additional functionality and encourage simple expressive code. For example, the code below takes a list of pairs, selects the second item of each pair, takes its absolute value, filters items greater than 4, and adds them up:\n\nfrom fastcore.utils import gt\n\n\nd = dict(a=1,b=-5,d=6,e=9).items()\ntest_eq(L(d).itemgot(1).map(abs).filter(gt(4)).sum(), 20) # abs(-5) + abs(6) + abs(9) = 20; 1 was filtered out.\n\nRead this overview section for a quick tutorial of L, as well as background on the name.\nYou can create an L from an existing iterable (e.g. a list, range, etc) and access or modify it with an int list/tuple index, mask, int, or slice. All list methods can also be used with L.\n\nt = L(range(12))\ntest_eq(t, list(range(12)))\ntest_ne(t, list(range(11)))\nt.reverse()\ntest_eq(t[0], 11)\nt[3] = \"h\"\ntest_eq(t[3], \"h\")\nt[3,5] = (\"j\",\"k\")\ntest_eq(t[3,5], [\"j\",\"k\"])\ntest_eq(t, L(t))\ntest_eq(L(L(1,2),[3,4]), ([1,2],[3,4]))\nt\n\n(#12) [11,10,9,'j',7,'k',5,4,3,2...]\n\n\nAny L is a Sequence so you can use it with methods like random.sample:\n\nassert isinstance(t, Sequence)\n\n\nimport random\n\n\nrandom.seed(0)\nrandom.sample(t, 3)\n\n[5, 0, 11]\n\n\nThere are optimized indexers for arrays, tensors, and DataFrames.\n\nimport pandas as pd\n\n\narr = np.arange(9).reshape(3,3)\nt = L(arr, use_list=None)\ntest_eq(t[1,2], arr[[1,2]])\n\ndf = pd.DataFrame({'a':[1,2,3]})\nt = L(df, use_list=None)\ntest_eq(t[1,2], L(pd.DataFrame({'a':[2,3]}, index=[1,2]), use_list=None))\n\nYou can also modify an L with append, +, and *.\n\nt = L()\ntest_eq(t, [])\nt.append(1)\ntest_eq(t, [1])\nt += [3,2]\ntest_eq(t, [1,3,2])\nt = t + [4]\ntest_eq(t, [1,3,2,4])\nt = 5 + t\ntest_eq(t, [5,1,3,2,4])\ntest_eq(L(1,2,3), [1,2,3])\ntest_eq(L(1,2,3), L(1,2,3))\nt = L(1)*5\nt = t.map(operator.neg)\ntest_eq(t,[-1]*5)\ntest_eq(~L([True,False,False]), L([False,True,True]))\nt = L(range(4))\ntest_eq(zip(t, L(1).cycle()), zip(range(4),(1,1,1,1)))\nt = L.range(100)\ntest_shuffled(t,t.shuffle())\n\n\ntest_eq(L([]).sum(), 0)\ntest_eq(L([]).product(), 1)\n\n\ndef _f(x,a=0): return x+a\nt = L(1)*5\ntest_eq(t.map(_f), t)\ntest_eq(t.map(_f,1), [2]*5)\ntest_eq(t.map(_f,a=2), [3]*5)\n\nAn L can be constructed from anything iterable, although tensors and arrays will not be iterated over on construction, unless you pass use_list to the constructor.\n\ntest_eq(L([1,2,3]),[1,2,3])\ntest_eq(L(L([1,2,3])),[1,2,3])\ntest_ne(L([1,2,3]),[1,2,])\ntest_eq(L('abc'),['abc'])\ntest_eq(L(range(0,3)),[0,1,2])\ntest_eq(L(o for o in range(0,3)),[0,1,2])\ntest_eq(L(array(0)),[array(0)])\ntest_eq(L([array(0),array(1)]),[array(0),array(1)])\ntest_eq(L(array([0.,1.1]))[0],array([0.,1.1]))\ntest_eq(L(array([0.,1.1]), use_list=True), [array(0.),array(1.1)]) # `use_list=True` to unwrap arrays/arrays\n\nIf match is not None then the created list is same len as match, either by:\n\nIf len(items)==1 then items is replicated,\nOtherwise an error is raised if match and items are not already the same size.\n\n\ntest_eq(L(1,match=[1,2,3]),[1,1,1])\ntest_eq(L([1,2],match=[2,3]),[1,2])\ntest_fail(lambda: L([1,2],match=[1,2,3]))\n\nIf you create an L from an existing L then you’ll get back the original object (since L uses the NewChkMeta metaclass).\n\ntest_is(L(t), t)\n\nAn L is considred equal to a list if they have the same elements. It’s never considered equal to a str a set or a dict even if they have the same elements/keys.\n\ntest_eq(L(['a', 'b']), ['a', 'b'])\ntest_ne(L(['a', 'b']), 'ab')\ntest_ne(L(['a', 'b']), {'a':1, 'b':2})\n\n\n\nL Methods\n\nsource\n\n\nL.__getitem__\n\n L.__getitem__ (idx)\n\nRetrieve idx (can be list of indices, or mask, or int) items\n\nt = L(range(12))\ntest_eq(t[1,2], [1,2]) # implicit tuple\ntest_eq(t[[1,2]], [1,2]) # list\ntest_eq(t[:3], [0,1,2]) # slice\ntest_eq(t[[False]*11 + [True]], [11]) # mask\ntest_eq(t[array(3)], 3)\n\n\nsource\n\n\nL.__setitem__\n\n L.__setitem__ (idx, o)\n\nSet idx (can be list of indices, or mask, or int) items to o (which is broadcast if not iterable)\n\nt[4,6] = 0\ntest_eq(t[4,6], [0,0])\nt[4,6] = [1,2]\ntest_eq(t[4,6], [1,2])\n\n\nsource\n\n\nL.unique\n\n L.unique (sort=False, bidir=False, start=None)\n\nUnique items, in stable order\n\ntest_eq(L(4,1,2,3,4,4).unique(), [4,1,2,3])\n\n\nsource\n\n\nL.val2idx\n\n L.val2idx ()\n\nDict from value to index\n\ntest_eq(L(1,2,3).val2idx(), {3:2,1:0,2:1})\n\n\nsource\n\n\nL.filter\n\n L.filter (f=<function noop>, negate=False, **kwargs)\n\nCreate new L filtered by predicate f, passing args and kwargs to f\n\nlist(t)\n\n[0, 1, 2, 3, 1, 5, 2, 7, 8, 9, 10, 11]\n\n\n\ntest_eq(t.filter(lambda o:o<5), [0,1,2,3,1,2])\ntest_eq(t.filter(lambda o:o<5, negate=True), [5,7,8,9,10,11])\n\n\nsource\n\n\nL.argwhere\n\n L.argwhere (f, negate=False, **kwargs)\n\nLike filter, but return indices for matching items\n\ntest_eq(t.argwhere(lambda o:o<5), [0,1,2,3,4,6])\n\n\nsource\n\n\nL.argfirst\n\n L.argfirst (f, negate=False)\n\nReturn index of first matching item\n\ntest_eq(t.argfirst(lambda o:o>4), 5)\ntest_eq(t.argfirst(lambda o:o>4,negate=True),0)\n\n\nsource\n\n\nL.map\n\n L.map (f, *args, **kwargs)\n\nCreate new L with f applied to all items, passing args and kwargs to f\n\ntest_eq(L.range(4).map(operator.neg), [0,-1,-2,-3])\n\nIf f is a string then it is treated as a format string to create the mapping:\n\ntest_eq(L.range(4).map('#{}#'), ['#0#','#1#','#2#','#3#'])\n\nIf f is a dictionary (or anything supporting __getitem__) then it is indexed to create the mapping:\n\ntest_eq(L.range(4).map(list('abcd')), list('abcd'))\n\nYou can also pass the same arg params that bind accepts:\n\ndef f(a=None,b=None): return b\ntest_eq(L.range(4).map(f, b=arg0), range(4))\n\n\nsource\n\n\nL.map_dict\n\n L.map_dict (f=<function noop>, *args, **kwargs)\n\nLike map, but creates a dict from items to function results\n\ntest_eq(L(range(1,5)).map_dict(), {1:1, 2:2, 3:3, 4:4})\ntest_eq(L(range(1,5)).map_dict(operator.neg), {1:-1, 2:-2, 3:-3, 4:-4})\n\n\nsource\n\n\nL.zip\n\n L.zip (cycled=False)\n\nCreate new L with zip(*items)\n\nt = L([[1,2,3],'abc'])\ntest_eq(t.zip(), [(1, 'a'),(2, 'b'),(3, 'c')])\n\n\nt = L([[1,2,3,4],['a','b','c']])\ntest_eq(t.zip(cycled=True ), [(1, 'a'),(2, 'b'),(3, 'c'),(4, 'a')])\ntest_eq(t.zip(cycled=False), [(1, 'a'),(2, 'b'),(3, 'c')])\n\n\nsource\n\n\nL.map_zip\n\n L.map_zip (f, *args, cycled=False, **kwargs)\n\nCombine zip and starmap\n\nt = L([1,2,3],[2,3,4])\ntest_eq(t.map_zip(operator.mul), [2,6,12])\n\n\nsource\n\n\nL.zipwith\n\n L.zipwith (*rest, cycled=False)\n\nCreate new L with self zip with each of *rest\n\nb = [[0],[1],[2,2]]\nt = L([1,2,3]).zipwith(b)\ntest_eq(t, [(1,[0]), (2,[1]), (3,[2,2])])\n\n\nsource\n\n\nL.map_zipwith\n\n L.map_zipwith (f, *rest, cycled=False, **kwargs)\n\nCombine zipwith and starmap\n\ntest_eq(L(1,2,3).map_zipwith(operator.mul, [2,3,4]), [2,6,12])\n\n\nsource\n\n\nL.itemgot\n\n L.itemgot (*idxs)\n\nCreate new L with item idx of all items\n\ntest_eq(t.itemgot(1), b)\n\n\nsource\n\n\nL.attrgot\n\n L.attrgot (k, default=None)\n\nCreate new L with attr k (or value k for dicts) of all items.\n\n# Example when items are not a dict\na = [SimpleNamespace(a=3,b=4),SimpleNamespace(a=1,b=2)]\ntest_eq(L(a).attrgot('b'), [4,2])\n\n#Example of when items are a dict\nb =[{'id': 15, 'name': 'nbdev'}, {'id': 17, 'name': 'fastcore'}]\ntest_eq(L(b).attrgot('id'), [15, 17])\n\n\nsource\n\n\nL.sorted\n\n L.sorted (key=None, reverse=False)\n\nNew L sorted by key. If key is str use attrgetter; if int use itemgetter\n\ntest_eq(L(a).sorted('a').attrgot('b'), [2,4])\n\n\nsource\n\n\nL.split\n\n L.split (s, sep=None, maxsplit=-1)\n\nClass Method: Same as str.split, but returns an L\n\ntest_eq(L.split('a b c'), list('abc'))\n\n\nsource\n\n\nL.range\n\n L.range (a, b=None, step=None)\n\nClass Method: Same as range, but returns L. Can pass collection for a, to use len(a)\n\ntest_eq_type(L.range([1,1,1]), L(range(3)))\ntest_eq_type(L.range(5,2,2), L(range(5,2,2)))\n\n\nsource\n\n\nL.concat\n\n L.concat ()\n\nConcatenate all elements of list\n\ntest_eq(L([0,1,2,3],4,L(5,6)).concat(), range(7))\n\n\nsource\n\n\nL.copy\n\n L.copy ()\n\nSame as list.copy, but returns an L\n\nt = L([0,1,2,3],4,L(5,6)).copy()\ntest_eq(t.concat(), range(7))\n\n\nsource\n\n\nL.map_first\n\n L.map_first (f=<function noop>, g=<function noop>, *args, **kwargs)\n\nFirst element of map_filter\n\nt = L(0,1,2,3)\ntest_eq(t.map_first(lambda o:o*2 if o>2 else None), 6)\n\n\nsource\n\n\nL.setattrs\n\n L.setattrs (attr, val)\n\nCall setattr on all items\n\nt = L(SimpleNamespace(),SimpleNamespace())\nt.setattrs('foo', 'bar')\ntest_eq(t.attrgot('foo'), ['bar','bar'])", + "crumbs": [ + "Foundation" + ] + }, + { + "objectID": "foundation.html#config", + "href": "foundation.html#config", + "title": "Foundation", + "section": "Config", + "text": "Config\n\nsource\n\nsave_config_file\n\n save_config_file (file, d, **kwargs)\n\nWrite settings dict to a new config file, or overwrite the existing one.\n\nsource\n\n\nread_config_file\n\n read_config_file (file, **kwargs)\n\nConfig files are saved and read using Python’s configparser.ConfigParser, inside the DEFAULT section.\n\n_d = dict(user='fastai', lib_name='fastcore', some_path='test', some_bool=True, some_num=3)\ntry:\n save_config_file('tmp.ini', _d)\n res = read_config_file('tmp.ini')\nfinally: os.unlink('tmp.ini')\ndict(res)\n\n{'user': 'fastai',\n 'lib_name': 'fastcore',\n 'some_path': 'test',\n 'some_bool': 'True',\n 'some_num': '3'}\n\n\n\nsource\n\n\nConfig\n\n Config (cfg_path, cfg_name, create=None, save=True, extra_files=None,\n types=None)\n\nReading and writing ConfigParser ini files\nConfig is a convenient wrapper around ConfigParser ini files with a single section (DEFAULT).\nInstantiate a Config from an ini file at cfg_path/cfg_name:\n\nsave_config_file('../tmp.ini', _d)\ntry: cfg = Config('..', 'tmp.ini')\nfinally: os.unlink('../tmp.ini')\ncfg\n\n{'user': 'fastai', 'lib_name': 'fastcore', 'some_path': 'test', 'some_bool': 'True', 'some_num': '3'}\n\n\nYou can create a new file if one doesn’t exist by providing a create dict:\n\ntry: cfg = Config('..', 'tmp.ini', create=_d)\nfinally: os.unlink('../tmp.ini')\ncfg\n\n{'user': 'fastai', 'lib_name': 'fastcore', 'some_path': 'test', 'some_bool': 'True', 'some_num': '3'}\n\n\nIf you additionally pass save=False, the Config will contain the items from create without writing a new file:\n\ncfg = Config('..', 'tmp.ini', create=_d, save=False)\ntest_eq(cfg.user,'fastai')\nassert not Path('../tmp.ini').exists()\n\nKeys can be accessed as attributes, items, or with get and an optional default:\n\ntest_eq(cfg.user,'fastai')\ntest_eq(cfg['some_path'], 'test')\ntest_eq(cfg.get('foo','bar'),'bar')\n\nExtra files can be read before cfg_path/cfg_name using extra_files, in the order they appear:\n\nwith tempfile.TemporaryDirectory() as d:\n a = Config(d, 'a.ini', {'a':0,'b':0})\n b = Config(d, 'b.ini', {'a':1,'c':0})\n c = Config(d, 'c.ini', {'a':2,'d':0}, extra_files=[a.config_file,b.config_file])\n test_eq(c.d, {'a':'2','b':'0','c':'0','d':'0'})\n\nIf you pass a dict types, then the values of that dict will be used as types to instantiate all values returned. Path is a special case – in that case, the path returned will be relative to the path containing the config file (assuming the value is relative). bool types use str2bool to convert to boolean.\n\n_types = dict(some_path=Path, some_bool=bool, some_num=int)\ncfg = Config('..', 'tmp.ini', create=_d, save=False, types=_types)\n\ntest_eq(cfg.user,'fastai')\ntest_eq(cfg['some_path'].resolve(), (Path('..')/'test').resolve())\ntest_eq(cfg.get('some_num'), 3)", + "crumbs": [ + "Foundation" + ] + }, + { + "objectID": "py2pyi.html#basics", + "href": "py2pyi.html#basics", + "title": "Create delegated pyi", + "section": "Basics", + "text": "Basics\n\nsource\n\nimp_mod\n\n imp_mod (module_path, package=None)\n\nImport dynamically the module referenced in fn\n\nfn = Path('test_py2pyi.py')\n\n\nmod = imp_mod(fn)\na = mod.A()\na.h()\n\n1\n\n\n\ntree = _get_tree(mod)\n\n\n\n\nAST.__repr__\n\n AST.__repr__ ()\n\n\n# for o in enumerate(tree.body): print(o)\n\n\nnode = tree.body[4]\nnode\n\ndef f(a: int, b: str='a') -> str:\n \"\"\"I am f\"\"\"\n return 1\n\n\n\nisinstance(node, functypes)\n\nTrue\n\n\n\nsource\n\n\nhas_deco\n\n has_deco (node:Union[ast.FunctionDef,ast.AsyncFunctionDef], name:str)\n\nCheck if a function node node has a decorator named name\n\nnm = 'delegates'\nhas_deco(node, nm)\n\nFalse\n\n\n\nnode = tree.body[5]\nnode\n\n@delegates(f)\ndef g(c, d: X, **kwargs) -> str:\n \"\"\"I am g\"\"\"\n return 2\n\n\n\nhas_deco(node, nm)\n\nTrue", + "crumbs": [ + "Create delegated pyi" + ] + }, + { + "objectID": "py2pyi.html#function-processing", + "href": "py2pyi.html#function-processing", + "title": "Create delegated pyi", + "section": "Function processing", + "text": "Function processing\n\ndef _proc_body (node, mod): print('_proc_body', type(node))\ndef _proc_func (node, mod): print('_proc_func', type(node))\ndef _proc_class (node, mod): print('_proc_class', type(node))\ndef _proc_patched(node, mod): print('_proc_patched', type(node))\n\n\n_proc_mod(mod);\n\n_proc_class <class 'ast.ClassDef'>\n_proc_body <class 'ast.FunctionDef'>\n_proc_func <class 'ast.FunctionDef'>\n_proc_body <class 'ast.FunctionDef'>\n_proc_class <class 'ast.ClassDef'>\n_proc_class <class 'ast.ClassDef'>\n_proc_patched <class 'ast.FunctionDef'>\n_proc_patched <class 'ast.FunctionDef'>\n_proc_body <class 'ast.FunctionDef'>\n\n\n\nnode.name\n\n'g'\n\n\n\nsym = getattr(mod, node.name)\nsym\n\n<function test_py2pyi.g(c, d: test_py2pyi.X, *, b: str = 'a') -> str>\n\n\n\nsig = signature(sym)\nprint(sig)\n\n(c, d: test_py2pyi.X, *, b: str = 'a') -> str\n\n\n\nsource\n\nsig2str\n\n sig2str (sig)\n\n\nsource\n\n\nast_args\n\n ast_args (func)\n\n\nnewargs = ast_args(sym)\nnewargs\n\nc, d: test_py2pyi.X, *, b: str='a'\n\n\n\nnode.args\n\nc, d: X, **kwargs\n\n\n\nnode.args = newargs\nnode\n\n@delegates(f)\ndef g(c, d: test_py2pyi.X, *, b: str='a') -> str:\n \"\"\"I am g\"\"\"\n return 2\n\n\n\n_body_ellip(node)\nnode\n\n@delegates(f)\ndef g(c, d: test_py2pyi.X, *, b: str='a') -> str:\n \"\"\"I am g\"\"\"\n ...\n\n\n\ntree = _get_tree(mod)\nnode = tree.body[5]\nnode\n\n@delegates(f)\ndef g(c, d: X, **kwargs) -> str:\n \"\"\"I am g\"\"\"\n return 2\n\n\n\n_update_func(node, sym)\nnode\n\ndef g(c, d: test_py2pyi.X, *, b: str='a') -> str:\n \"\"\"I am g\"\"\"\n ...\n\n\n\ntree = _proc_mod(mod)\ntree.body[5]\n\n_proc_class <class 'ast.ClassDef'>\n_proc_class <class 'ast.ClassDef'>\n_proc_class <class 'ast.ClassDef'>\n_proc_patched <class 'ast.FunctionDef'>\n_proc_patched <class 'ast.FunctionDef'>\n\n\ndef g(c, d: test_py2pyi.X, *, b: str='a') -> str:\n \"\"\"I am g\"\"\"\n ...", + "crumbs": [ + "Create delegated pyi" + ] + }, + { + "objectID": "py2pyi.html#patch", + "href": "py2pyi.html#patch", + "title": "Create delegated pyi", + "section": "Patch", + "text": "Patch\n\nnode = tree.body[9]\nnode\n\n@patch\n@delegates(j)\ndef k(self: (A, B), b: bool=False, **kwargs):\n return 1\n\n\n\nann = node.args.args[0].annotation\n\n\nif hasattr(ann, 'elts'): ann = ann.elts[0]\n\n\nnm = ann.id\nnm\n\n'A'\n\n\n\ncls = getattr(mod, nm)\nsym = getattr(cls, node.name)\n\n\nsig2str(signature(sym))\n\n\"(self: (test_py2pyi.A, test_py2pyi.B), b: bool = False, *, d: str = 'a')\"\n\n\n\n_update_func(node, sym)\n\n\nnode\n\n@patch\ndef k(self: (test_py2pyi.A, test_py2pyi.B), b: bool=False, *, d: str='a'):\n ...\n\n\n\ntree = _proc_mod(mod)\ntree.body[9]\n\n_proc_class <class 'ast.ClassDef'>\n_proc_class <class 'ast.ClassDef'>\n_proc_class <class 'ast.ClassDef'>\n\n\n@patch\ndef k(self: (test_py2pyi.A, test_py2pyi.B), b: bool=False, *, d: str='a'):\n ...", + "crumbs": [ + "Create delegated pyi" + ] + }, + { + "objectID": "py2pyi.html#class-and-file", + "href": "py2pyi.html#class-and-file", + "title": "Create delegated pyi", + "section": "Class and file", + "text": "Class and file\n\ntree = _get_tree(mod)\nnode = tree.body[7]\nnode\n\nclass A:\n\n @delegates(j)\n def h(self, b: bool=False, **kwargs):\n a = 1\n return a\n\n\n\nnode.body\n\n[@delegates(j)\n def h(self, b: bool=False, **kwargs):\n a = 1\n return a]\n\n\n\ntree = _proc_mod(mod)\ntree.body[7]\n\nclass A:\n\n def h(self, b: bool=False, *, d: str='a'):\n ...\n\n\n\nsource\n\ncreate_pyi\n\n create_pyi (fn, package=None)\n\nConvert fname.py to fname.pyi by removing function bodies and expanding delegates kwargs\n\ncreate_pyi(fn)\n\n\n# fn = Path('/Users/jhoward/git/fastcore/fastcore/docments.py')\n# create_pyi(fn, 'fastcore')", + "crumbs": [ + "Create delegated pyi" + ] + }, + { + "objectID": "py2pyi.html#script", + "href": "py2pyi.html#script", + "title": "Create delegated pyi", + "section": "Script", + "text": "Script\n\nsource\n\npy2pyi\n\n py2pyi (fname:str, package:str=None)\n\nConvert fname.py to fname.pyi by removing function bodies and expanding delegates kwargs\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nfname\nstr\n\nThe file name to convert\n\n\npackage\nstr\nNone\nThe parent package\n\n\n\n\nsource\n\n\nreplace_wildcards\n\n replace_wildcards (path:str)\n\nExpand wildcard imports in the specified Python file.\n\n\n\n\nType\nDetails\n\n\n\n\npath\nstr\nPath to the Python file to process", + "crumbs": [ + "Create delegated pyi" + ] + }, + { + "objectID": "dispatch.html", + "href": "dispatch.html", + "title": "Type dispatch", + "section": "", + "text": "from nbdev.showdoc import *\nfrom fastcore.test import *\nfrom fastcore.nb_imports import *", + "crumbs": [ + "Type dispatch" + ] + }, + { + "objectID": "dispatch.html#helpers", + "href": "dispatch.html#helpers", + "title": "Type dispatch", + "section": "Helpers", + "text": "Helpers\n\nsource\n\nlenient_issubclass\n\n lenient_issubclass (cls, types)\n\nIf possible return whether cls is a subclass of types, otherwise return False.\n\nassert not lenient_issubclass(typing.Collection, list)\nassert lenient_issubclass(list, typing.Collection)\nassert lenient_issubclass(typing.Collection, object)\nassert lenient_issubclass(typing.List, typing.Collection)\nassert not lenient_issubclass(typing.Collection, typing.List)\nassert not lenient_issubclass(object, typing.Callable)\n\n\nsource\n\n\nsorted_topologically\n\n sorted_topologically (iterable, cmp=<built-in function lt>,\n reverse=False)\n\nReturn a new list containing all items from the iterable sorted topologically\n\ntd = [3, 1, 2, 5]\ntest_eq(sorted_topologically(td), [1, 2, 3, 5])\ntest_eq(sorted_topologically(td, reverse=True), [5, 3, 2, 1])\n\n\ntd = {int:1, numbers.Number:2, numbers.Integral:3}\ntest_eq(sorted_topologically(td, cmp=lenient_issubclass), [int, numbers.Integral, numbers.Number])\n\n\ntd = [numbers.Integral, tuple, list, int, dict]\ntd = sorted_topologically(td, cmp=lenient_issubclass)\nassert td.index(int) < td.index(numbers.Integral)", + "crumbs": [ + "Type dispatch" + ] + }, + { + "objectID": "dispatch.html#typedispatch", + "href": "dispatch.html#typedispatch", + "title": "Type dispatch", + "section": "TypeDispatch", + "text": "TypeDispatch\nType dispatch, or Multiple dispatch, allows you to change the way a function behaves based upon the input types it recevies. This is a prominent feature in some programming languages like Julia. For example, this is a conceptual example of how multiple dispatch works in Julia, returning different values depending on the input types of x and y:\ncollide_with(x::Asteroid, y::Asteroid) = ... \n# deal with asteroid hitting asteroid\n\ncollide_with(x::Asteroid, y::Spaceship) = ... \n# deal with asteroid hitting spaceship\n\ncollide_with(x::Spaceship, y::Asteroid) = ... \n# deal with spaceship hitting asteroid\n\ncollide_with(x::Spaceship, y::Spaceship) = ... \n# deal with spaceship hitting spaceship\nType dispatch can be especially useful in data science, where you might allow different input types (i.e. numpy arrays and pandas dataframes) to function that processes data. Type dispatch allows you to have a common API for functions that do similar tasks.\nThe TypeDispatch class allows us to achieve type dispatch in Python. It contains a dictionary that maps types from type annotations to functions, which ensures that the proper function is called when passed inputs.\n\nsource\n\nTypeDispatch\n\n TypeDispatch (funcs=(), bases=())\n\nDictionary-like object; __getitem__ matches keys of types using issubclass\nTo demonstrate how TypeDispatch works, we define a set of functions that accept a variety of input types, specified with different type annotations:\n\ndef f2(x:int, y:float): return x+y #int and float for 2nd arg\ndef f_nin(x:numbers.Integral)->int: return x+1 #integral numeric\ndef f_ni2(x:int): return x #integer\ndef f_bll(x:bool|list): return x #bool or list\ndef f_num(x:numbers.Number): return x #Number (root of numerics)\n\nWe can optionally initialize TypeDispatch with a list of functions we want to search. Printing an instance of TypeDispatch will display convenient mapping of types -> functions:\n\nt = TypeDispatch([f_nin,f_ni2,f_num,f_bll,None])\nt\n\n(bool,object) -> f_bll\n(int,object) -> f_ni2\n(Integral,object) -> f_nin\n(Number,object) -> f_num\n(list,object) -> f_bll\n(object,object) -> NoneType\n\n\nNote that only the first two arguments are used for TypeDispatch. If your function only contains one argument, the second parameter will be shown as object. If you pass None into TypeDispatch, then this will be displayed as (object, object) -> NoneType.\nTypeDispatch is a dictionary-like object, which means that you can retrieve a function by the associated type annotation. For example, the statement:\nt[float]\nWill return f_num because that is the matching function that has a type annotation that is a super-class of of float - numbers.Number:\n\nassert issubclass(float, numbers.Number)\ntest_eq(t[float], f_num)\n\nThe same is true for other types as well:\n\ntest_eq(t[np.int32], f_nin)\ntest_eq(t[bool], f_bll)\ntest_eq(t[list], f_bll)\ntest_eq(t[np.int32], f_nin)\n\nIf you try to get a type that doesn’t match, TypeDispatch will return None:\n\ntest_eq(t[str], None)\n\n\nsource\n\n\nTypeDispatch.add\n\n TypeDispatch.add (f)\n\nAdd type t and function f\nThis method allows you to add an additional function to an existing TypeDispatch instance :\n\ndef f_col(x:typing.Collection): return x\nt.add(f_col)\ntest_eq(t[str], f_col)\nt\n\n(bool,object) -> f_bll\n(int,object) -> f_ni2\n(Integral,object) -> f_nin\n(Number,object) -> f_num\n(list,object) -> f_bll\n(typing.Collection,object) -> f_col\n(object,object) -> NoneType\n\n\nIf you accidentally add the same function more than once things will still work as expected:\n\nt.add(f_ni2) \ntest_eq(t[int], f_ni2)\n\nHowever, if you add a function that has a type collision that raises an ambiguity, this will automatically resolve to the latest function added:\n\ndef f_ni3(z:int): return z # collides with f_ni2 with same type annotations\nt.add(f_ni3) \ntest_eq(t[int], f_ni3)\n\n\nUsing bases:\nThe argument bases can optionally accept a single instance of TypeDispatch or a collection (i.e. a tuple or list) of TypeDispatch objects. This can provide functionality similar to multiple inheritance.\nThese are searched for matching functions if no match in your list of functions:\n\ndef f_str(x:str): return x+'1'\n\nt = TypeDispatch([f_nin,f_ni2,f_num,f_bll,None])\nt2 = TypeDispatch(f_str, bases=t) # you can optionally supply a list of TypeDispatch objects for `bases`.\nt2\n\n(str,object) -> f_str\n(bool,object) -> f_bll\n(int,object) -> f_ni2\n(Integral,object) -> f_nin\n(Number,object) -> f_num\n(list,object) -> f_bll\n(object,object) -> NoneType\n\n\n\ntest_eq(t2[int], f_ni2) # searches `t` b/c not found in `t2`\ntest_eq(t2[np.int32], f_nin) # searches `t` b/c not found in `t2`\ntest_eq(t2[float], f_num) # searches `t` b/c not found in `t2`\ntest_eq(t2[bool], f_bll) # searches `t` b/c not found in `t2`\ntest_eq(t2[str], f_str) # found in `t`!\ntest_eq(t2('a'), 'a1') # found in `t`!, and uses __call__\n\no = np.int32(1)\ntest_eq(t2(o), 2) # found in `t2` and uses __call__\n\n\n\nUp To Two Arguments\nTypeDispatch supports up to two arguments when searching for the appropriate function. The following functions f1 and f2 both have two parameters:\n\ndef f1(x:numbers.Integral, y): return x+1 #Integral is a numeric type\ndef f2(x:int, y:float): return x+y\nt = TypeDispatch([f1,f2])\nt\n\n(int,float) -> f2\n(Integral,object) -> f1\n\n\nYou can lookup functions from a TypeDispatch instance with two parameters like this:\n\ntest_eq(t[np.int32], f1)\ntest_eq(t[int,float], f2)\n\nKeep in mind that anything beyond the first two parameters are ignored, and any collisions will be resolved in favor of the most recent function added. In the below example, f1 is ignored in favor of f2 because the first two parameters have identical type hints:\n\ndef f1(a:str, b:int, c:list): return a\ndef f2(a: str, b:int): return b\nt = TypeDispatch([f1,f2])\ntest_eq(t[str, int], f2)\nt\n\n(str,int) -> f2\n\n\n\n\nMatching\nType Dispatch matches types with functions according to whether the supplied class is a subclass or the same class of the type annotation(s) of associated functions.\nLet’s consider an example where we try to retrieve the function corresponding to types of [np.int32, float].\nIn this scenario, f2 will not be matched. This is because the first type annotation of f2, int, is not a superclass (or the same class) of np.int32:\n\ndef f1(x:numbers.Integral, y): return x+1\ndef f2(x:int, y:float): return x+y\nt = TypeDispatch([f1,f2])\n\nassert not issubclass(np.int32, int)\n\nInstead, f1 is a valid match, as its first argument is annoted with the type numbers.Integeral, which np.int32 is a subclass of:\n\nassert issubclass(np.int32, numbers.Integral)\ntest_eq(t[np.int32,float], f1)\n\nIn f1 , the 2nd parameter y is not annotated, which means TypeDispatch will match anything where the first argument matches int that is not matched with anything else:\n\nassert issubclass(int, numbers.Integral) # int is a subclass of numbers.Integral\ntest_eq(t[int], f1)\ntest_eq(t[int,int], f1)\n\nIf no match is possible, None is returned:\n\ntest_eq(t[float,float], None)\n\n\nsource\n\n\n\nTypeDispatch.__call__\n\n TypeDispatch.__call__ (*args, **kwargs)\n\nCall self as a function.\nTypeDispatch is also callable. When you call an instance of TypeDispatch, it will execute the relevant function:\n\ndef f_arr(x:np.ndarray): return x.sum()\ndef f_int(x:np.int32): return x+1\nt = TypeDispatch([f_arr, f_int])\n\narr = np.array([5,4,3,2,1])\ntest_eq(t(arr), 15) # dispatches to f_arr\n\no = np.int32(1)\ntest_eq(t(o), 2) # dispatches to f_int\nassert t.first() is not None\n\nYou can also call an instance of of TypeDispatch when there are two parameters:\n\ndef f1(x:numbers.Integral, y): return x+1\ndef f2(x:int, y:float): return x+y\nt = TypeDispatch([f1,f2])\n\ntest_eq(t(3,2.0), 5)\ntest_eq(t(3,2), 4)\n\nWhen no match is found, a TypeDispatch instance becomes an identity function. This default behavior is leveraged by fasatai for data transformations to provide a sensible default when a matching function cannot be found.\n\ntest_eq(t('a'), 'a')\n\n\nsource\n\n\nTypeDispatch.returns\n\n TypeDispatch.returns (x)\n\nGet the return type of annotation of x.\nYou can optionally pass an object to TypeDispatch.returns and get the return type annotation back:\n\ndef f1(x:int) -> np.ndarray: return np.array(x)\ndef f2(x:str) -> float: return List\ndef f3(x:float): return List # f3 has no return type annotation\n\nt = TypeDispatch([f1, f2, f3])\n\ntest_eq(t.returns(1), np.ndarray) # dispatched to f1\ntest_eq(t.returns('Hello'), float) # dispatched to f2\ntest_eq(t.returns(1.0), None) # dispatched to f3\n\nclass _Test: pass\n_test = _Test()\ntest_eq(t.returns(_test), None) # type `_Test` not found, so None returned\n\n\nUsing TypeDispatch With Methods\nYou can use TypeDispatch when defining methods as well:\n\ndef m_nin(self, x:str|numbers.Integral): return str(x)+'1'\ndef m_bll(self, x:bool): self.foo='a'\ndef m_num(self, x:numbers.Number): return x*2\n\nt = TypeDispatch([m_nin,m_num,m_bll])\nclass A: f = t # set class attribute `f` equal to a TypeDispatch instance\n \na = A()\ntest_eq(a.f(1), '11') #dispatch to m_nin\ntest_eq(a.f(1.), 2.) #dispatch to m_num\ntest_is(a.f.inst, a)\n\na.f(False) # this triggers t.m_bll to run, which sets self.foo to 'a'\ntest_eq(a.foo, 'a')\n\nAs discussed in TypeDispatch.__call__, when there is not a match, TypeDispatch.__call__ becomes an identity function. In the below example, a tuple does not match any type annotations so a tuple is returned:\n\ntest_eq(a.f(()), ())\n\nWe extend the previous example by using bases to add an additional method that supports tuples:\n\ndef m_tup(self, x:tuple): return x+(1,)\nt2 = TypeDispatch(m_tup, bases=t)\n\nclass A2: f = t2\na2 = A2()\ntest_eq(a2.f(1), '11')\ntest_eq(a2.f(1.), 2.)\ntest_is(a2.f.inst, a2)\na2.f(False)\ntest_eq(a2.foo, 'a')\ntest_eq(a2.f(()), (1,))\n\n\n\nUsing TypeDispatch With Class Methods\nYou can use TypeDispatch when defining class methods too:\n\ndef m_nin(cls, x:str|numbers.Integral): return str(x)+'1'\ndef m_bll(cls, x:bool): cls.foo='a'\ndef m_num(cls, x:numbers.Number): return x*2\n\nt = TypeDispatch([m_nin,m_num,m_bll])\nclass A: f = t # set class attribute `f` equal to a TypeDispatch\n\ntest_eq(A.f(1), '11') #dispatch to m_nin\ntest_eq(A.f(1.), 2.) #dispatch to m_num\ntest_is(A.f.owner, A)\n\nA.f(False) # this triggers t.m_bll to run, which sets A.foo to 'a'\ntest_eq(A.foo, 'a')", + "crumbs": [ + "Type dispatch" + ] + }, + { + "objectID": "dispatch.html#typedispatch-decorator", + "href": "dispatch.html#typedispatch-decorator", + "title": "Type dispatch", + "section": "typedispatch Decorator", + "text": "typedispatch Decorator\n\nsource\n\nDispatchReg\n\n DispatchReg ()\n\nA global registry for TypeDispatch objects keyed by function name\n\n@typedispatch\ndef f_td_test(x, y): return f'{x}{y}'\n@typedispatch\ndef f_td_test(x:numbers.Integral|int, y): return x+1\n@typedispatch\ndef f_td_test(x:int, y:float): return x+y\n@typedispatch\ndef f_td_test(x:int, y:int): return x*y\n\ntest_eq(f_td_test(3,2.0), 5)\nassert issubclass(int, numbers.Integral)\ntest_eq(f_td_test(3,2), 6)\n\ntest_eq(f_td_test('a','b'), 'ab')\n\n\nUsing typedispatch With other decorators\nYou can use typedispatch with classmethod and staticmethod decorator\n\nclass A:\n @typedispatch\n def f_td_test(self, x:numbers.Integral, y): return x+1\n @typedispatch\n @classmethod\n def f_td_test(cls, x:int, y:float): return x+y\n @typedispatch\n @staticmethod\n def f_td_test(x:int, y:int): return x*y\n \ntest_eq(A.f_td_test(3,2), 6)\ntest_eq(A.f_td_test(3,2.0), 5)\ntest_eq(A().f_td_test(3,'2.0'), 4)", + "crumbs": [ + "Type dispatch" + ] + }, + { + "objectID": "dispatch.html#casting", + "href": "dispatch.html#casting", + "title": "Type dispatch", + "section": "Casting", + "text": "Casting\nNow that we can dispatch on types, let’s make it easier to cast objects to a different type.\n\nsource\n\nretain_meta\n\n retain_meta (x, res, as_copy=False)\n\nCall res.set_meta(x), if it exists\n\nsource\n\n\ndefault_set_meta\n\n default_set_meta (x, as_copy=False)\n\nCopy over _meta from x to res, if it’s missing\n\n\n\n(object,object) -> cast\nDictionary-like object; __getitem__ matches keys of types using issubclass\nThis works both for plain python classes:…\n\nmk_class('_T1', 'a') # mk_class is a fastai utility that constructs a class.\nclass _T2(_T1): pass\n\nt = _T1(a=1)\nt2 = cast(t, _T2) \nassert t2 is t # t2 refers to the same object as t\nassert isinstance(t, _T2) # t also changed in-place\nassert isinstance(t2, _T2)\n\ntest_eq_type(_T2(a=1), t2)\n\n…as well as for arrays and tensors.\n\nclass _T1(ndarray): pass\n\nt = array([1])\nt2 = cast(t, _T1)\ntest_eq(array([1]), t2)\ntest_eq(_T1, type(t2))\n\nTo customize casting for other types, define a separate cast function with typedispatch for your type.\n\nsource\n\n\nretain_type\n\n retain_type (new, old=None, typ=None, as_copy=False)\n\nCast new to type of old or typ if it’s a superclass\n\nclass _T(tuple): pass\na = _T((1,2))\nb = tuple((1,2))\nc = retain_type(b, typ=_T)\ntest_eq_type(c, a)\n\nIf old has a _meta attribute, its content is passed when casting new to the type of old. In the below example, only the attribute a, but not other_attr is kept, because other_attr is not in _meta:\n\nclass _A():\n set_meta = default_set_meta\n def __init__(self, t): self.t=t\n\nclass _B1(_A):\n def __init__(self, t, a=1):\n super().__init__(t)\n self._meta = {'a':a}\n self.other_attr = 'Hello' # will not be kept after casting.\n \nx = _B1(1, a=2)\nb = _A(1)\nc = retain_type(b, old=x)\ntest_eq(c._meta, {'a': 2})\nassert not getattr(c, 'other_attr', None)\n\n\nsource\n\n\nretain_types\n\n retain_types (new, old=None, typs=None)\n\nCast each item of new to type of matching item in old if it’s a superclass\n\nclass T(tuple): pass\n\nt1,t2 = retain_types((1,(1,(1,1))), (2,T((2,T((3,4))))))\ntest_eq_type(t1, 1)\ntest_eq_type(t2, T((1,T((1,1)))))\n\nt1,t2 = retain_types((1,(1,(1,1))), typs = {tuple: [int, {T: [int, {T: [int,int]}]}]})\ntest_eq_type(t1, 1)\ntest_eq_type(t2, T((1,T((1,1)))))\n\n\nsource\n\n\nexplode_types\n\n explode_types (o)\n\nReturn the type of o, potentially in nested dictionaries for thing that are listy\n\ntest_eq(explode_types((2,T((2,T((3,4)))))), {tuple: [int, {T: [int, {T: [int,int]}]}]})", + "crumbs": [ + "Type dispatch" + ] + }, + { + "objectID": "index.html", + "href": "index.html", + "title": "Welcome to fastcore", + "section": "", + "text": "Python is a powerful, dynamic language. Rather than bake everything into the language, it lets the programmer customize it to make it work for them. fastcore uses this flexibility to add to Python features inspired by other languages we’ve loved, like multiple dispatch from Julia, mixins from Ruby, and currying, binding, and more from Haskell. It also adds some “missing features” and clean up some rough edges in the Python standard library, such as simplifying parallel processing, and bringing ideas from NumPy over to Python’s list type.", + "crumbs": [ + "Welcome to fastcore" + ] + }, + { + "objectID": "index.html#getting-started", + "href": "index.html#getting-started", + "title": "Welcome to fastcore", + "section": "Getting started", + "text": "Getting started\nTo install fastcore run: conda install fastcore -c fastai (if you use Anaconda, which we recommend) or pip install fastcore. For an editable install, clone this repo and run: pip install -e \".[dev]\". fastcore is tested to work on Ubuntu, macOS and Windows (versions tested are those shown with the -latest suffix here).\nfastcore contains many features, including:\n\nfastcore.test: Simple testing functions\nfastcore.foundation: Mixins, delegation, composition, and more\nfastcore.xtras: Utility functions to help with functional-style programming, parallel processing, and more\nfastcore.dispatch: Multiple dispatch methods\nfastcore.transform: Pipelines of composed partially reversible transformations\n\nTo get started, we recommend you read through the fastcore tour.", + "crumbs": [ + "Welcome to fastcore" + ] + }, + { + "objectID": "index.html#contributing", + "href": "index.html#contributing", + "title": "Welcome to fastcore", + "section": "Contributing", + "text": "Contributing\nAfter you clone this repository, please run nbdev_install_hooks in your terminal. This sets up git hooks, which clean up the notebooks to remove the extraneous stuff stored in the notebooks (e.g. which cells you ran) which causes unnecessary merge conflicts.\nTo run the tests in parallel, launch nbdev_test.\nBefore submitting a PR, check that the local library and notebooks match.\n\nIf you made a change to the notebooks in one of the exported cells, you can export it to the library with nbdev_prepare.\nIf you made a change to the library, you can export it back to the notebooks with nbdev_update.", + "crumbs": [ + "Welcome to fastcore" + ] + }, + { + "objectID": "transform.html", + "href": "transform.html", + "title": "Transforms", + "section": "", + "text": "from __future__ import annotations\nfrom nbdev.showdoc import *\nfrom fastcore.test import *\nfrom fastcore.nb_imports import *\n\nThe classes here provide functionality for creating a composition of partially reversible functions. By “partially reversible” we mean that a transform can be decoded, creating a form suitable for display. This is not necessarily identical to the original form (e.g. a transform that changes a byte tensor to a float tensor does not recreate a byte tensor when decoded, since that may lose precision, and a float tensor can be displayed already).\nClasses are also provided and for composing transforms, and mapping them over collections. Pipeline is a transform which composes several Transform, knowing how to decode them or show an encoded item.\n\nsource\n\nTransform\n\n Transform (enc=None, dec=None, split_idx=None, order=None)\n\nDelegates (__call__,decode,setup) to (encodes,decodes,setups) if split_idx matches\nA Transform is the main building block of the fastai data pipelines. In the most general terms a transform can be any function you want to apply to your data, however the Transform class provides several mechanisms that make the process of building them easy and flexible.\n\n\nThe main Transform features:\n\nType dispatch - Type annotations are used to determine if a transform should be applied to the given argument. It also gives an option to provide several implementations and it choses the one to run based on the type. This is useful for example when running both independent and dependent variables through the pipeline where some transforms only make sense for one and not the other. Another usecase is designing a transform that handles different data formats. Note that if a transform takes multiple arguments only the type of the first one is used for dispatch.\nHandling of tuples - When a tuple (or a subclass of tuple) of data is passed to a transform it will get applied to each element separately. You can opt out of this behavior by passing a list or an L, as only tuples gets this specific behavior. An alternative is to use ItemTransform defined below, which will always take the input as a whole.\nReversability - A transform can be made reversible by implementing the decodes method. This is mainly used to turn something like a category which is encoded as a number back into a label understandable by humans for showing purposes. Like the regular call method, the decode method that is used to decode will be applied over each element of a tuple separately.\nType propagation - Whenever possible a transform tries to return data of the same type it received. Mainly used to maintain semantics of things like ArrayImage which is a thin wrapper of pytorch’s Tensor. You can opt out of this behavior by adding ->None return type annotation.\nPreprocessing - The setup method can be used to perform any one-time calculations to be later used by the transform, for example generating a vocabulary to encode categorical data.\nFiltering based on the dataset type - By setting the split_idx flag you can make the transform be used only in a specific DataSource subset like in training, but not validation.\nOrdering - You can set the order attribute which the Pipeline uses when it needs to merge two lists of transforms.\nAppending new behavior with decorators - You can easily extend an existing Transform by creating encodes or decodes methods for new data types. You can put those new methods outside the original transform definition and decorate them with the class you wish them patched into. This can be used by the fastai library users to add their own behavior, or multiple modules contributing to the same transform.\n\n\n\nDefining a Transform\nThere are a few ways to create a transform with different ratios of simplicity to flexibility. - Extending the Transform class - Use inheritence to implement the methods you want. - Passing methods to the constructor - Instantiate the Transform class and pass your functions as enc and dec arguments. - @Transform decorator - Turn any function into a Transform by just adding a decorator - very straightforward if all you need is a single encodes implementation. - Passing a function to fastai APIs - Same as above, but when passing a function to other transform aware classes like Pipeline or TfmdDS you don’t even need a decorator. Your function will get converted to a Transform automatically.\nA simple way to create a Transform is to pass a function to the constructor. In the below example, we pass an anonymous function that does integer division by 2:\n\nf = Transform(lambda o:o//2)\n\nIf you call this transform, it will apply the transformation:\n\ntest_eq_type(f(2), 1)\n\nAnother way to define a Transform is to extend the Transform class:\n\nclass A(Transform): pass\n\nHowever, to enable your transform to do something, you have to define an encodes method. Note that we can use the class name as a decorator to add this method to the original class.\n\n@A\ndef encodes(self, x): return x+1\n\nf1 = A()\ntest_eq(f1(1), 2) # f1(1) is the same as f1.encode(1)\n\nIn addition to adding an encodes method, we can also add a decodes method. This enables you to call the decode method (without an s). For more information about the purpose of decodes, see the discussion about Reversibility in the above section.\nJust like with encodes, you can add a decodes method to the original class by using the class name as a decorator:\n\nclass B(A): pass\n\n@B\ndef decodes(self, x): return x-1\n\nf2 = B()\ntest_eq(f2.decode(2), 1)\n\ntest_eq(f2(1), 2) # uses A's encode method from the parent class\n\nIf you do not define an encodes or decodes method the original value will be returned:\n\nclass _Tst(Transform): pass \n\nf3 = _Tst() # no encodes or decodes method have been defined\ntest_eq_type(f3.decode(2.0), 2.0)\ntest_eq_type(f3(2), 2)\n\nTransforms can be created from class methods too:\n\nclass A:\n @classmethod\n def create(cls, x:int): return x+1\ntest_eq(Transform(A.create)(1), 2)\n\n\nDefining Transforms With A Decorator\nTransform can be used as a decorator to turn a function into a Transform.\n\n@Transform\ndef f(x): return x//2\ntest_eq_type(f(2), 1)\ntest_eq_type(f.decode(2.0), 2.0)\n\n@Transform\ndef f(x): return x*2\ntest_eq_type(f(2), 4)\ntest_eq_type(f.decode(2.0), 2.0)\n\n\n\nTyped Dispatch and Transforms\nWe can also apply different transformations depending on the type of the input passed by using TypedDispatch. TypedDispatch automatically works with Transform when using type hints:\n\nclass A(Transform): pass\n\n@A\ndef encodes(self, x:int): return x//2\n\n@A\ndef encodes(self, x:float): return x+1\n\nWhen we pass in an int, this calls the first encodes method:\n\nf = A()\ntest_eq_type(f(3), 1)\n\nWhen we pass in a float, this calls the second encodes method:\n\ntest_eq_type(f(2.), 3.)\n\nWhen we pass in a type that is not specified in encodes, the original value is returned:\n\ntest_eq(f('a'), 'a')\n\nIf the type annotation is a tuple, then any type in the tuple will match:\n\nclass MyClass(int): pass\n\nclass A(Transform):\n def encodes(self, x:MyClass|float): return x/2\n def encodes(self, x:str|list): return str(x)+'_1'\n\nf = A()\n\nThe below two examples match the first encodes, with a type of MyClass and float, respectively:\n\ntest_eq(f(MyClass(2)), 1.) # input is of type MyClass \ntest_eq(f(6.0), 3.0) # input is of type float\n\nThe next two examples match the second encodes method, with a type of str and list, respectively:\n\ntest_eq(f('a'), 'a_1') # input is of type str\ntest_eq(f(['a','b','c']), \"['a', 'b', 'c']_1\") # input is of type list\n\n\n\nCasting Types With Transform\nWithout any intervention it is easy for operations to change types in Python. For example, FloatSubclass (defined below) becomes a float after performing multiplication:\n\nclass FloatSubclass(float): pass\ntest_eq_type(FloatSubclass(3.0) * 2, 6.0)\n\nThis behavior is often not desirable when performing transformations on data. Therefore, Transform will attempt to cast the output to be of the same type as the input by default. In the below example, the output will be cast to a FloatSubclass type to match the type of the input:\n\n@Transform\ndef f(x): return x*2\n\ntest_eq_type(f(FloatSubclass(3.0)), FloatSubclass(6.0))\n\nWe can optionally turn off casting by annotating the transform function with a return type of None:\n\n@Transform\ndef f(x)-> None: return x*2 # Same transform as above, but with a -> None annotation\n\ntest_eq_type(f(FloatSubclass(3.0)), 6.0) # Casting is turned off because of -> None annotation\n\nHowever, Transform will only cast output back to the input type when the input is a subclass of the output. In the below example, the input is of type FloatSubclass which is not a subclass of the output which is of type str. Therefore, the output doesn’t get cast back to FloatSubclass and stays as type str:\n\n@Transform\ndef f(x): return str(x)\n \ntest_eq_type(f(Float(2.)), '2.0')\n\nJust like encodes, the decodes method will cast outputs to match the input type in the same way. In the below example, the output of decodes remains of type MySubclass:\n\nclass MySubclass(int): pass\n\ndef enc(x): return MySubclass(x+1)\ndef dec(x): return x-1\n\n\nf = Transform(enc,dec)\nt = f(1) # t is of type MySubclass\ntest_eq_type(f.decode(t), MySubclass(1)) # the output of decode is cast to MySubclass to match the input type.\n\n\n\nApply Transforms On Subsets With split_idx\nYou can apply transformations to subsets of data by specifying a split_idx property. If a transform has a split_idx then it’s only applied if the split_idx param matches. In the below example, we set split_idx equal to 1:\n\ndef enc(x): return x+1\ndef dec(x): return x-1\nf = Transform(enc,dec)\nf.split_idx = 1\n\nThe transformations are applied when a matching split_idx parameter is passed:\n\ntest_eq(f(1, split_idx=1),2)\ntest_eq(f.decode(2, split_idx=1),1)\n\nOn the other hand, transformations are ignored when the split_idx parameter does not match:\n\ntest_eq(f(1, split_idx=0), 1)\ntest_eq(f.decode(2, split_idx=0), 2)\n\n\n\nTransforms on Lists\nTransform operates on lists as a whole, not element-wise:\n\nclass A(Transform):\n def encodes(self, x): return dict(x)\n def decodes(self, x): return list(x.items())\n \nf = A()\n_inp = [(1,2), (3,4)]\nt = f(_inp)\n\ntest_eq(t, dict(_inp))\ntest_eq(f.decodes(t), _inp)\n\nIf you want a transform to operate on a list elementwise, you must implement this appropriately in the encodes and decodes methods:\n\nclass AL(Transform): pass\n\n@AL\ndef encodes(self, x): return [x_+1 for x_ in x]\n\n@AL\ndef decodes(self, x): return [x_-1 for x_ in x]\n\nf = AL()\nt = f([1,2])\n\ntest_eq(t, [2,3])\ntest_eq(f.decode(t), [1,2])\n\n\n\nTransforms on Tuples\nUnlike lists, Transform operates on tuples element-wise.\n\ndef neg_int(x): return -x\nf = Transform(neg_int)\n\ntest_eq(f((1,2,3)), (-1,-2,-3))\n\nTransforms will also apply TypedDispatch element-wise on tuples when an input type annotation is specified. In the below example, the values 1.0 and 3.0 are ignored because they are of type float, not int:\n\ndef neg_int(x:int): return -x\nf = Transform(neg_int)\n\ntest_eq(f((1.0, 2, 3.0)), (1.0, -2, 3.0))\n\nAnother example of how Transform can use TypedDispatch with tuples is shown below:\n\nclass B(Transform): pass\n\n@B\ndef encodes(self, x:int): return x+1\n\n@B\ndef encodes(self, x:str): return x+'hello'\n\n@B\ndef encodes(self, x): return str(x)+'!'\n\nIf the input is not an int or str, the third encodes method will apply:\n\nb = B()\ntest_eq(b([1]), '[1]!') \ntest_eq(b([1.0]), '[1.0]!')\n\nHowever, if the input is a tuple, then the appropriate method will apply according to the type of each element in the tuple:\n\ntest_eq(b(('1',)), ('1hello',))\ntest_eq(b((1,2)), (2,3))\ntest_eq(b(('a',1.0)), ('ahello','1.0!'))\n\nDispatching over tuples works recursively, by the way:\n\nclass B(Transform):\n def encodes(self, x:int): return x+1\n def encodes(self, x:str): return x+'_hello'\n def decodes(self, x:int): return x-1\n def decodes(self, x:str): return x.replace('_hello', '')\n\nf = B()\nstart = (1.,(2,'3'))\nt = f(start)\ntest_eq_type(t, (1.,(3,'3_hello')))\ntest_eq(f.decode(t), start)\n\nDispatching also works with typing module type classes, like numbers.integral:\n\n@Transform\ndef f(x:numbers.Integral): return x+1\n\nt = f((1,'1',1))\ntest_eq(t, (2, '1', 2))\n\n\nsource\n\n\n\nInplaceTransform\n\n InplaceTransform (enc=None, dec=None, split_idx=None, order=None)\n\nA Transform that modifies in-place and just returns whatever it’s passed\n\nclass A(InplaceTransform): pass\n\n@A\ndef encodes(self, x:pd.Series): x.fillna(10, inplace=True)\n \nf = A()\n\ntest_eq_type(f(pd.Series([1,2,None])),pd.Series([1,2,10],dtype=np.float64)) #fillna fills with floats.\n\n\nsource\n\n\nDisplayedTransform\n\n DisplayedTransform (enc=None, dec=None, split_idx=None, order=None)\n\nA transform with a __repr__ that shows its attrs\nTransforms normally are represented by just their class name and a list of encodes and decodes implementations:\n\nclass A(Transform): encodes,decodes = noop,noop\nf = A()\nf\n\nA:\nencodes: (object,object) -> noop\ndecodes: (object,object) -> noop\n\n\nA DisplayedTransform will in addition show the contents of all attributes listed in the comma-delimited string self.store_attrs:\n\nclass A(DisplayedTransform):\n encodes = noop\n def __init__(self, a, b=2):\n super().__init__()\n store_attr()\n \nA(a=1,b=2)\n\nA -- {'a': 1, 'b': 2}:\nencodes: (object,object) -> noop\ndecodes: \n\n\n\nsource\n\n\nItemTransform\n\n ItemTransform (enc=None, dec=None, split_idx=None, order=None)\n\nA transform that always take tuples as items\nItemTransform is the class to use to opt out of the default behavior of Transform.\n\nclass AIT(ItemTransform): \n def encodes(self, xy): x,y=xy; return (x+y,y)\n def decodes(self, xy): x,y=xy; return (x-y,y)\n \nf = AIT()\ntest_eq(f((1,2)), (3,2))\ntest_eq(f.decode((3,2)), (1,2))\n\nIf you pass a special tuple subclass, the usual retain type behavior of Transform will keep it:\n\nclass _T(tuple): pass\nx = _T((1,2))\ntest_eq_type(f(x), _T((3,2)))\n\n\nsource\n\n\nget_func\n\n get_func (t, name, *args, **kwargs)\n\nGet the t.name (potentially partial-ized with args and kwargs) or noop if not defined\nThis works for any kind of t supporting getattr, so a class or a module.\n\ntest_eq(get_func(operator, 'neg', 2)(), -2)\ntest_eq(get_func(operator.neg, '__call__')(2), -2)\ntest_eq(get_func(list, 'foobar')([2]), [2])\na = [2,1]\nget_func(list, 'sort')(a)\ntest_eq(a, [1,2])\n\nTransforms are built with multiple-dispatch: a given function can have several methods depending on the type of the object received. This is done directly with the TypeDispatch module and type-annotation in Transform, but you can also use the following class.\n\nsource\n\n\nFunc\n\n Func (name, *args, **kwargs)\n\nBasic wrapper around a name with args and kwargs to call on a given type\nYou can call the Func object on any module name or type, even a list of types. It will return the corresponding function (with a default to noop if nothing is found) or list of functions.\n\ntest_eq(Func('sqrt')(math), math.sqrt)\n\n\n\n\nSig\n\n Sig (*args, **kwargs)\n\nSig is just sugar-syntax to create a Func object more easily with the syntax Sig.name(*args, **kwargs).\n\nf = Sig.sqrt()\ntest_eq(f(math), math.sqrt)\n\n\nsource\n\n\ncompose_tfms\n\n compose_tfms (x, tfms, is_enc=True, reverse=False, **kwargs)\n\nApply all func_nm attribute of tfms on x, maybe in reverse order\n\ndef to_int (x): return Int(x)\ndef to_float(x): return Float(x)\ndef double (x): return x*2\ndef half(x)->None: return x/2\n\n\ndef test_compose(a, b, *fs): test_eq_type(compose_tfms(a, tfms=map(Transform,fs)), b)\n\ntest_compose(1, Int(1), to_int)\ntest_compose(1, Float(1), to_int,to_float)\ntest_compose(1, Float(2), to_int,to_float,double)\ntest_compose(2.0, 2.0, to_int,double,half)\n\n\nclass A(Transform):\n def encodes(self, x:float): return Float(x+1)\n def decodes(self, x): return x-1\n \ntfms = [A(), Transform(math.sqrt)]\nt = compose_tfms(3., tfms=tfms)\ntest_eq_type(t, Float(2.))\ntest_eq(compose_tfms(t, tfms=tfms, is_enc=False), 1.)\ntest_eq(compose_tfms(4., tfms=tfms, reverse=True), 3.)\n\n\ntfms = [A(), Transform(math.sqrt)]\ntest_eq(compose_tfms((9,3.), tfms=tfms), (3,2.))\n\n\nsource\n\n\nmk_transform\n\n mk_transform (f)\n\nConvert function f to Transform if it isn’t already one\n\nsource\n\n\ngather_attrs\n\n gather_attrs (o, k, nm)\n\nUsed in getattr to collect all attrs k from self.{nm}\n\nsource\n\n\ngather_attr_names\n\n gather_attr_names (o, nm)\n\nUsed in dir to collect all attrs k from self.{nm}\n\nsource\n\n\nPipeline\n\n Pipeline (funcs=None, split_idx=None)\n\nA pipeline of composed (for encode/decode) transforms, setup with types\n\nadd_docs(Pipeline,\n __call__=\"Compose `__call__` of all `fs` on `o`\",\n decode=\"Compose `decode` of all `fs` on `o`\",\n show=\"Show `o`, a single item from a tuple, decoding as needed\",\n add=\"Add transforms `ts`\",\n setup=\"Call each tfm's `setup` in order\")\n\nPipeline is a wrapper for compose_tfms. You can pass instances of Transform or regular functions in funcs, the Pipeline will wrap them all in Transform (and instantiate them if needed) during the initialization. It handles the transform setup by adding them one at a time and calling setup on each, goes through them in order in __call__ or decode and can show an object by applying decoding the transforms up until the point it gets an object that knows how to show itself.\n\n# Empty pipeline is noop\npipe = Pipeline()\ntest_eq(pipe(1), 1)\ntest_eq(pipe((1,)), (1,))\n# Check pickle works\nassert pickle.loads(pickle.dumps(pipe))\n\n\nclass IntFloatTfm(Transform):\n def encodes(self, x): return Int(x)\n def decodes(self, x): return Float(x)\n foo=1\n\nint_tfm=IntFloatTfm()\n\ndef neg(x): return -x\nneg_tfm = Transform(neg, neg)\n\n\npipe = Pipeline([neg_tfm, int_tfm])\n\nstart = 2.0\nt = pipe(start)\ntest_eq_type(t, Int(-2))\ntest_eq_type(pipe.decode(t), Float(start))\ntest_stdout(lambda:pipe.show(t), '-2')\n\n\npipe = Pipeline([neg_tfm, int_tfm])\nt = pipe(start)\ntest_stdout(lambda:pipe.show(pipe((1.,2.))), '-1\\n-2')\ntest_eq(pipe.foo, 1)\nassert 'foo' in dir(pipe)\nassert 'int_float_tfm' in dir(pipe)\n\nYou can add a single transform or multiple transforms ts using Pipeline.add. Transforms will be ordered by Transform.order.\n\npipe = Pipeline([neg_tfm, int_tfm])\nclass SqrtTfm(Transform):\n order=-1\n def encodes(self, x): \n return x**(.5)\n def decodes(self, x): return x**2\npipe.add(SqrtTfm())\ntest_eq(pipe(4),-2)\ntest_eq(pipe.decode(-2),4)\npipe.add([SqrtTfm(),SqrtTfm()])\ntest_eq(pipe(256),-2)\ntest_eq(pipe.decode(-2),256)\n\nTransforms are available as attributes named with the snake_case version of the names of their types. Attributes in transforms can be directly accessed as attributes of the pipeline.\n\ntest_eq(pipe.int_float_tfm, int_tfm)\ntest_eq(pipe.foo, 1)\n\npipe = Pipeline([int_tfm, int_tfm])\npipe.int_float_tfm\ntest_eq(pipe.int_float_tfm[0], int_tfm)\ntest_eq(pipe.foo, [1,1])\n\n\n# Check opposite order\npipe = Pipeline([int_tfm,neg_tfm])\nt = pipe(start)\ntest_eq(t, -2)\ntest_stdout(lambda:pipe.show(t), '-2')\n\n\nclass A(Transform):\n def encodes(self, x): return int(x)\n def decodes(self, x): return Float(x)\n\npipe = Pipeline([neg_tfm, A])\nt = pipe(start)\ntest_eq_type(t, -2)\ntest_eq_type(pipe.decode(t), Float(start))\ntest_stdout(lambda:pipe.show(t), '-2.0')\n\n\ns2 = (1,2)\npipe = Pipeline([neg_tfm, A])\nt = pipe(s2)\ntest_eq_type(t, (-1,-2))\ntest_eq_type(pipe.decode(t), (Float(1.),Float(2.)))\ntest_stdout(lambda:pipe.show(t), '-1.0\\n-2.0')\n\n\nfrom PIL import Image\n\n\nclass ArrayImage(ndarray):\n _show_args = {'cmap':'viridis'}\n def __new__(cls, x, *args, **kwargs):\n if isinstance(x,tuple): super().__new__(cls, x, *args, **kwargs)\n if args or kwargs: raise RuntimeError('Unknown array init args')\n if not isinstance(x,ndarray): x = array(x)\n return x.view(cls)\n \n def show(self, ctx=None, figsize=None, **kwargs):\n if ctx is None: _,ctx = plt.subplots(figsize=figsize)\n ctx.imshow(im, **{**self._show_args, **kwargs})\n ctx.axis('off')\n return ctx\n \nim = Image.open(TEST_IMAGE)\nim_t = ArrayImage(im)\n\n\ndef f1(x:ArrayImage): return -x\ndef f2(x): return Image.open(x).resize((128,128))\ndef f3(x:Image.Image): return(ArrayImage(array(x)))\n\n\npipe = Pipeline([f2,f3,f1])\nt = pipe(TEST_IMAGE)\ntest_eq(type(t), ArrayImage)\ntest_eq(t, -array(f3(f2(TEST_IMAGE))))\n\n\npipe = Pipeline([f2,f3])\nt = pipe(TEST_IMAGE)\nax = pipe.show(t)\n\n\n\n\n\n\n\n\n\n#test_fig_exists(ax)\n\n\n#Check filtering is properly applied\nadd1 = B()\nadd1.split_idx = 1\npipe = Pipeline([neg_tfm, A(), add1])\ntest_eq(pipe(start), -2)\npipe.split_idx=1\ntest_eq(pipe(start), -1)\npipe.split_idx=0\ntest_eq(pipe(start), -2)\nfor t in [None, 0, 1]:\n pipe.split_idx=t\n test_eq(pipe.decode(pipe(start)), start)\n test_stdout(lambda: pipe.show(pipe(start)), \"-2.0\")\n\n\ndef neg(x): return -x\ntest_eq(type(mk_transform(neg)), Transform)\ntest_eq(type(mk_transform(math.sqrt)), Transform)\ntest_eq(type(mk_transform(lambda a:a*2)), Transform)\ntest_eq(type(mk_transform(Pipeline([neg]))), Pipeline)\n\n\n\nMethods\n\n#TODO: method examples\n\n\nsource\n\n\nPipeline.__call__\n\n Pipeline.__call__ (o)\n\nCall self as a function.\n\nsource\n\n\nPipeline.decode\n\n Pipeline.decode (o, full=True)\n\n\nsource\n\n\nPipeline.setup\n\n Pipeline.setup (items=None, train_setup=False)\n\nDuring the setup, the Pipeline starts with no transform and adds them one at a time, so that during its setup, each transform gets the items processed up to its point and not after.", + "crumbs": [ + "Transforms" + ] + }, + { + "objectID": "docments.html", + "href": "docments.html", + "title": "Docments", + "section": "", + "text": "docments provides programmatic access to comments in function parameters and return types. It can be used to create more developer-friendly documentation, CLI, etc tools.", + "crumbs": [ + "Docments" + ] + }, + { + "objectID": "docments.html#why", + "href": "docments.html#why", + "title": "Docments", + "section": "Why?", + "text": "Why?\nWithout docments, if you want to document your parameters, you have to repeat param names in docstrings, since they’re already in the function signature. The parameters have to be kept synchronized in the two places as you change your code. Readers of your code have to look back and forth between two places to understand what’s happening. So it’s more work for you, and for your users.\nFurthermore, to have parameter documentation formatted nicely without docments, you have to use special magic docstring formatting, often with odd quirks, which is a pain to create and maintain, and awkward to read in code. For instance, using numpy-style documentation:\n\ndef add_np(a:int, b:int=0)->int:\n \"\"\"The sum of two numbers.\n \n Used to demonstrate numpy-style docstrings.\n\nParameters\n----------\na : int\n the 1st number to add\nb : int\n the 2nd number to add (default: 0)\n\nReturns\n-------\nint\n the result of adding `a` to `b`\"\"\"\n return a+b\n\nBy comparison, here’s the same thing using docments:\n\ndef add(\n a:int, # the 1st number to add\n b=0, # the 2nd number to add\n)->int: # the result of adding `a` to `b`\n \"The sum of two numbers.\"\n return a+b", + "crumbs": [ + "Docments" + ] + }, + { + "objectID": "docments.html#numpy-docstring-helper-functions", + "href": "docments.html#numpy-docstring-helper-functions", + "title": "Docments", + "section": "Numpy docstring helper functions", + "text": "Numpy docstring helper functions\ndocments also supports numpy-style docstrings, or a mix or numpy-style and docments parameter documentation. The functions in this section help get and parse this information.\n\nsource\n\ndocstring\n\n docstring (sym)\n\nGet docstring for sym for functions ad classes\n\ntest_eq(docstring(add), \"The sum of two numbers.\")\n\n\nsource\n\n\nparse_docstring\n\n parse_docstring (sym)\n\nParse a numpy-style docstring in sym\n\n# parse_docstring(add_np)\n\n\nsource\n\n\nisdataclass\n\n isdataclass (s)\n\nCheck if s is a dataclass but not a dataclass’ instance\n\nsource\n\n\nget_dataclass_source\n\n get_dataclass_source (s)\n\nGet source code for dataclass s\n\nsource\n\n\nget_source\n\n get_source (s)\n\nGet source code for string, function object or dataclass s\n\nsource\n\n\nget_name\n\n get_name (obj)\n\nGet the name of obj\n\ntest_eq(get_name(in_ipython), 'in_ipython')\ntest_eq(get_name(L.map), 'map')\n\n\nsource\n\n\nqual_name\n\n qual_name (obj)\n\nGet the qualified name of obj\n\nassert qual_name(docscrape) == 'fastcore.docscrape'", + "crumbs": [ + "Docments" + ] + }, + { + "objectID": "docments.html#docments", + "href": "docments.html#docments", + "title": "Docments", + "section": "Docments", + "text": "Docments\n\nsource\n\ndocments\n\n docments (elt, full=False, returns=True, eval_str=False)\n\nGenerates a docment\nThe returned dict has parameter names as keys, docments as values. The return value comment appears in the return, unless returns=False. Using the add definition above, we get:\n\ndef add(\n a:int, # the 1st number to add\n b=0, # the 2nd number to add\n)->int: # the result of adding `a` to `b`\n \"The sum of two numbers.\"\n return a+b\n\ndocments(add)\n\n{ 'a': 'the 1st number to add',\n 'b': 'the 2nd number to add',\n 'return': 'the result of adding `a` to `b`'}\n\n\nIf you pass full=True, the values are dict of defaults, types, and docments as values. Note that the type annotation is inferred from the default value, if the annotation is empty and a default is supplied.\n\ndocments(add, full=True)\n\n{ 'a': { 'anno': 'int',\n 'default': <class 'inspect._empty'>,\n 'docment': 'the 1st number to add'},\n 'b': { 'anno': <class 'int'>,\n 'default': 0,\n 'docment': 'the 2nd number to add'},\n 'return': { 'anno': 'int',\n 'default': <class 'inspect._empty'>,\n 'docment': 'the result of adding `a` to `b`'}}\n\n\nTo evaluate stringified annotations (from python 3.10), use eval_str:\n\ndocments(add, full=True, eval_str=True)['a']\n\n{ 'anno': <class 'int'>,\n 'default': <class 'inspect._empty'>,\n 'docment': 'the 1st number to add'}\n\n\nIf you need more space to document a parameter, place one or more lines of comments above the parameter, or above the return type. You can mix-and-match these docment styles:\n\ndef add(\n # The first operand\n a:int,\n # This is the second of the operands to the *addition* operator.\n # Note that passing a negative value here is the equivalent of the *subtraction* operator.\n b:int,\n)->int: # The result is calculated using Python's builtin `+` operator.\n \"Add `a` to `b`\"\n return a+b\n\n\ndocments(add)\n\n{ 'a': 'The first operand',\n 'b': 'This is the second of the operands to the *addition* operator.\\n'\n 'Note that passing a negative value here is the equivalent of the '\n '*subtraction* operator.',\n 'return': \"The result is calculated using Python's builtin `+` operator.\"}\n\n\nDocments works with async functions, too:\n\nasync def add_async(\n # The first operand\n a:int,\n # This is the second of the operands to the *addition* operator.\n # Note that passing a negative value here is the equivalent of the *subtraction* operator.\n b:int,\n)->int: # The result is calculated using Python's builtin `+` operator.\n \"Add `a` to `b`\"\n return a+b\n\n\ntest_eq(docments(add_async), docments(add))\n\nYou can also use docments with classes and methods:\n\nclass Adder:\n \"An addition calculator\"\n def __init__(self,\n a:int, # First operand\n b:int, # 2nd operand\n ): self.a,self.b = a,b\n \n def calculate(self\n )->int: # Integral result of addition operator\n \"Add `a` to `b`\"\n return a+b\n\n\ndocments(Adder)\n\n{'a': 'First operand', 'b': '2nd operand', 'return': None}\n\n\n\ndocments(Adder.calculate)\n\n{'return': 'Integral result of addition operator', 'self': None}\n\n\ndocments can also be extracted from numpy-style docstrings:\n\nprint(add_np.__doc__)\n\nThe sum of two numbers.\n \n Used to demonstrate numpy-style docstrings.\n\nParameters\n----------\na : int\n the 1st number to add\nb : int\n the 2nd number to add (default: 0)\n\nReturns\n-------\nint\n the result of adding `a` to `b`\n\n\n\ndocments(add_np)\n\n{ 'a': 'the 1st number to add',\n 'b': 'the 2nd number to add (default: 0)',\n 'return': 'the result of adding `a` to `b`'}\n\n\nYou can even mix and match docments and numpy parameters:\n\ndef add_mixed(a:int, # the first number to add\n b\n )->int: # the result\n \"\"\"The sum of two numbers.\n\nParameters\n----------\nb : int\n the 2nd number to add (default: 0)\"\"\"\n return a+b\n\n\ndocments(add_mixed, full=True)\n\n{ 'a': { 'anno': 'int',\n 'default': <class 'inspect._empty'>,\n 'docment': 'the first number to add'},\n 'b': { 'anno': 'int',\n 'default': <class 'inspect._empty'>,\n 'docment': 'the 2nd number to add (default: 0)'},\n 'return': { 'anno': 'int',\n 'default': <class 'inspect._empty'>,\n 'docment': 'the result'}}\n\n\nYou can use docments with dataclasses, however if the class was defined in online notebook, docments will not contain parameters’ comments. This is because the source code is not available in the notebook. After converting the notebook to a module, the docments will be available. Thus, documentation will have correct parameters’ comments.\nDocments even works with delegates:\n\nfrom fastcore.meta import delegates\n\n\ndef _a(a:int=2): return a # First\n\n@delegates(_a)\ndef _b(b:str, **kwargs): return b, (_a(**kwargs)) # Second\n\ndocments(_b)\n\n{'a': 'First', 'b': 'Second', 'return': None}", + "crumbs": [ + "Docments" + ] + } +] \ 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 00000000..285e4448 --- /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 00000000..dbeeb055 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 00000000..2ff60158 --- /dev/null +++ b/site_libs/bootstrap/bootstrap.min.css @@ -0,0 +1,12 @@ +/*! + * Bootstrap v5.3.1 (https://getbootstrap.com/) + * Copyright 2011-2023 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */@import"https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400;700&display=swap";:root,[data-bs-theme=light]{--bs-blue: #2780e3;--bs-indigo: #6610f2;--bs-purple: #613d7c;--bs-pink: #e83e8c;--bs-red: #ff0039;--bs-orange: #f0ad4e;--bs-yellow: #ff7518;--bs-green: #3fb618;--bs-teal: #20c997;--bs-cyan: #9954bb;--bs-black: #000;--bs-white: #fff;--bs-gray: #6c757d;--bs-gray-dark: #343a40;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #343a40;--bs-gray-900: #212529;--bs-default: #343a40;--bs-primary: #2780e3;--bs-secondary: #343a40;--bs-success: #3fb618;--bs-info: #9954bb;--bs-warning: #ff7518;--bs-danger: #ff0039;--bs-light: #f8f9fa;--bs-dark: #343a40;--bs-default-rgb: 52, 58, 64;--bs-primary-rgb: 39, 128, 227;--bs-secondary-rgb: 52, 58, 64;--bs-success-rgb: 63, 182, 24;--bs-info-rgb: 153, 84, 187;--bs-warning-rgb: 255, 117, 24;--bs-danger-rgb: 255, 0, 57;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 52, 58, 64;--bs-primary-text-emphasis: #10335b;--bs-secondary-text-emphasis: #15171a;--bs-success-text-emphasis: #19490a;--bs-info-text-emphasis: #3d224b;--bs-warning-text-emphasis: #662f0a;--bs-danger-text-emphasis: #660017;--bs-light-text-emphasis: #495057;--bs-dark-text-emphasis: #495057;--bs-primary-bg-subtle: #d4e6f9;--bs-secondary-bg-subtle: #d6d8d9;--bs-success-bg-subtle: #d9f0d1;--bs-info-bg-subtle: #ebddf1;--bs-warning-bg-subtle: #ffe3d1;--bs-danger-bg-subtle: #ffccd7;--bs-light-bg-subtle: #fcfcfd;--bs-dark-bg-subtle: #ced4da;--bs-primary-border-subtle: #a9ccf4;--bs-secondary-border-subtle: #aeb0b3;--bs-success-border-subtle: #b2e2a3;--bs-info-border-subtle: #d6bbe4;--bs-warning-border-subtle: #ffc8a3;--bs-danger-border-subtle: #ff99b0;--bs-light-border-subtle: #e9ecef;--bs-dark-border-subtle: #adb5bd;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-font-sans-serif: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-root-font-size: 17px;--bs-body-font-family: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--bs-body-font-size:1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #343a40;--bs-body-color-rgb: 52, 58, 64;--bs-body-bg: #fff;--bs-body-bg-rgb: 255, 255, 255;--bs-emphasis-color: #000;--bs-emphasis-color-rgb: 0, 0, 0;--bs-secondary-color: rgba(52, 58, 64, 0.75);--bs-secondary-color-rgb: 52, 58, 64;--bs-secondary-bg: #e9ecef;--bs-secondary-bg-rgb: 233, 236, 239;--bs-tertiary-color: rgba(52, 58, 64, 0.5);--bs-tertiary-color-rgb: 52, 58, 64;--bs-tertiary-bg: #f8f9fa;--bs-tertiary-bg-rgb: 248, 249, 250;--bs-heading-color: inherit;--bs-link-color: #2761e3;--bs-link-color-rgb: 39, 97, 227;--bs-link-decoration: underline;--bs-link-hover-color: #1f4eb6;--bs-link-hover-color-rgb: 31, 78, 182;--bs-code-color: #7d12ba;--bs-highlight-bg: #ffe3d1;--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, 0.175);--bs-border-radius: 0.25rem;--bs-border-radius-sm: 0.2em;--bs-border-radius-lg: 0.5rem;--bs-border-radius-xl: 1rem;--bs-border-radius-xxl: 2rem;--bs-border-radius-2xl: var(--bs-border-radius-xxl);--bs-border-radius-pill: 50rem;--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width: 0.25rem;--bs-focus-ring-opacity: 0.25;--bs-focus-ring-color: rgba(39, 128, 227, 0.25);--bs-form-valid-color: #3fb618;--bs-form-valid-border-color: #3fb618;--bs-form-invalid-color: #ff0039;--bs-form-invalid-border-color: #ff0039}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color: #dee2e6;--bs-body-color-rgb: 222, 226, 230;--bs-body-bg: #212529;--bs-body-bg-rgb: 33, 37, 41;--bs-emphasis-color: #fff;--bs-emphasis-color-rgb: 255, 255, 255;--bs-secondary-color: rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb: 222, 226, 230;--bs-secondary-bg: #343a40;--bs-secondary-bg-rgb: 52, 58, 64;--bs-tertiary-color: rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb: 222, 226, 230;--bs-tertiary-bg: #2b3035;--bs-tertiary-bg-rgb: 43, 48, 53;--bs-primary-text-emphasis: #7db3ee;--bs-secondary-text-emphasis: #85898c;--bs-success-text-emphasis: #8cd374;--bs-info-text-emphasis: #c298d6;--bs-warning-text-emphasis: #ffac74;--bs-danger-text-emphasis: #ff6688;--bs-light-text-emphasis: #f8f9fa;--bs-dark-text-emphasis: #dee2e6;--bs-primary-bg-subtle: #081a2d;--bs-secondary-bg-subtle: #0a0c0d;--bs-success-bg-subtle: #0d2405;--bs-info-bg-subtle: #1f1125;--bs-warning-bg-subtle: #331705;--bs-danger-bg-subtle: #33000b;--bs-light-bg-subtle: #343a40;--bs-dark-bg-subtle: #1a1d20;--bs-primary-border-subtle: #174d88;--bs-secondary-border-subtle: #1f2326;--bs-success-border-subtle: #266d0e;--bs-info-border-subtle: #5c3270;--bs-warning-border-subtle: #99460e;--bs-danger-border-subtle: #990022;--bs-light-border-subtle: #495057;--bs-dark-border-subtle: #343a40;--bs-heading-color: inherit;--bs-link-color: #7db3ee;--bs-link-hover-color: #97c2f1;--bs-link-color-rgb: 125, 179, 238;--bs-link-hover-color-rgb: 151, 194, 241;--bs-code-color: white;--bs-border-color: #495057;--bs-border-color-translucent: rgba(255, 255, 255, 0.15);--bs-form-valid-color: #8cd374;--bs-form-valid-border-color: #8cd374;--bs-form-invalid-color: #ff6688;--bs-form-invalid-border-color: #ff6688}*,*::before,*::after{box-sizing:border-box}:root{font-size:var(--bs-root-font-size)}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr{margin:1rem 0;color:inherit;border:0;border-top:1px solid;opacity:.25}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:400;line-height:1.2;color:var(--bs-heading-color)}h1,.h1{font-size:calc(1.325rem + 0.9vw)}@media(min-width: 1200px){h1,.h1{font-size:2rem}}h2,.h2{font-size:calc(1.29rem + 0.48vw)}@media(min-width: 1200px){h2,.h2{font-size:1.65rem}}h3,.h3{font-size:calc(1.27rem + 0.24vw)}@media(min-width: 1200px){h3,.h3{font-size:1.45rem}}h4,.h4{font-size:1.25rem}h5,.h5{font-size:1.1rem}h6,.h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{text-decoration:underline dotted;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;-ms-text-decoration:underline dotted;-o-text-decoration:underline dotted;cursor:help;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem;padding:.625rem 1.25rem;border-left:.25rem solid #e9ecef}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}b,strong{font-weight:bolder}small,.small{font-size:0.875em}mark,.mark{padding:.1875em;background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}a:hover{--bs-link-color-rgb: var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875em;color:#000;background-color:#f8f9fa;padding:.5rem;border:1px solid var(--bs-border-color, #dee2e6)}pre code{background-color:rgba(0,0,0,0);font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:var(--bs-code-color);background-color:#f8f9fa;padding:.125rem .25rem;word-wrap:break-word}a>code{color:inherit}kbd{padding:.4rem .4rem;font-size:0.875em;color:#fff;background-color:#343a40}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:rgba(52,58,64,.75);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none !important}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none !important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:0.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:0.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:rgba(52,58,64,.75)}.container,.container-fluid,.container-xxl,.container-xl,.container-lg,.container-md,.container-sm{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;width:100%;padding-right:calc(var(--bs-gutter-x)*.5);padding-left:calc(var(--bs-gutter-x)*.5);margin-right:auto;margin-left:auto}@media(min-width: 576px){.container-sm,.container{max-width:540px}}@media(min-width: 768px){.container-md,.container-sm,.container{max-width:720px}}@media(min-width: 992px){.container-lg,.container-md,.container-sm,.container{max-width:960px}}@media(min-width: 1200px){.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1140px}}@media(min-width: 1400px){.container-xxl,.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1320px}}:root{--bs-breakpoint-xs: 0;--bs-breakpoint-sm: 576px;--bs-breakpoint-md: 768px;--bs-breakpoint-lg: 992px;--bs-breakpoint-xl: 1200px;--bs-breakpoint-xxl: 1400px}.grid{display:grid;grid-template-rows:repeat(var(--bs-rows, 1), 1fr);grid-template-columns:repeat(var(--bs-columns, 12), 1fr);gap:var(--bs-gap, 1.5rem)}.grid .g-col-1{grid-column:auto/span 1}.grid .g-col-2{grid-column:auto/span 2}.grid .g-col-3{grid-column:auto/span 3}.grid .g-col-4{grid-column:auto/span 4}.grid .g-col-5{grid-column:auto/span 5}.grid .g-col-6{grid-column:auto/span 6}.grid .g-col-7{grid-column:auto/span 7}.grid .g-col-8{grid-column:auto/span 8}.grid .g-col-9{grid-column:auto/span 9}.grid .g-col-10{grid-column:auto/span 10}.grid .g-col-11{grid-column:auto/span 11}.grid .g-col-12{grid-column:auto/span 12}.grid .g-start-1{grid-column-start:1}.grid .g-start-2{grid-column-start:2}.grid .g-start-3{grid-column-start:3}.grid .g-start-4{grid-column-start:4}.grid .g-start-5{grid-column-start:5}.grid .g-start-6{grid-column-start:6}.grid .g-start-7{grid-column-start:7}.grid .g-start-8{grid-column-start:8}.grid .g-start-9{grid-column-start:9}.grid .g-start-10{grid-column-start:10}.grid .g-start-11{grid-column-start:11}@media(min-width: 576px){.grid .g-col-sm-1{grid-column:auto/span 1}.grid .g-col-sm-2{grid-column:auto/span 2}.grid .g-col-sm-3{grid-column:auto/span 3}.grid .g-col-sm-4{grid-column:auto/span 4}.grid .g-col-sm-5{grid-column:auto/span 5}.grid .g-col-sm-6{grid-column:auto/span 6}.grid .g-col-sm-7{grid-column:auto/span 7}.grid .g-col-sm-8{grid-column:auto/span 8}.grid .g-col-sm-9{grid-column:auto/span 9}.grid .g-col-sm-10{grid-column:auto/span 10}.grid .g-col-sm-11{grid-column:auto/span 11}.grid .g-col-sm-12{grid-column:auto/span 12}.grid .g-start-sm-1{grid-column-start:1}.grid .g-start-sm-2{grid-column-start:2}.grid .g-start-sm-3{grid-column-start:3}.grid .g-start-sm-4{grid-column-start:4}.grid .g-start-sm-5{grid-column-start:5}.grid .g-start-sm-6{grid-column-start:6}.grid .g-start-sm-7{grid-column-start:7}.grid .g-start-sm-8{grid-column-start:8}.grid .g-start-sm-9{grid-column-start:9}.grid .g-start-sm-10{grid-column-start:10}.grid .g-start-sm-11{grid-column-start:11}}@media(min-width: 768px){.grid .g-col-md-1{grid-column:auto/span 1}.grid .g-col-md-2{grid-column:auto/span 2}.grid .g-col-md-3{grid-column:auto/span 3}.grid .g-col-md-4{grid-column:auto/span 4}.grid .g-col-md-5{grid-column:auto/span 5}.grid .g-col-md-6{grid-column:auto/span 6}.grid .g-col-md-7{grid-column:auto/span 7}.grid .g-col-md-8{grid-column:auto/span 8}.grid .g-col-md-9{grid-column:auto/span 9}.grid .g-col-md-10{grid-column:auto/span 10}.grid .g-col-md-11{grid-column:auto/span 11}.grid .g-col-md-12{grid-column:auto/span 12}.grid .g-start-md-1{grid-column-start:1}.grid .g-start-md-2{grid-column-start:2}.grid .g-start-md-3{grid-column-start:3}.grid .g-start-md-4{grid-column-start:4}.grid .g-start-md-5{grid-column-start:5}.grid .g-start-md-6{grid-column-start:6}.grid .g-start-md-7{grid-column-start:7}.grid .g-start-md-8{grid-column-start:8}.grid .g-start-md-9{grid-column-start:9}.grid .g-start-md-10{grid-column-start:10}.grid .g-start-md-11{grid-column-start:11}}@media(min-width: 992px){.grid .g-col-lg-1{grid-column:auto/span 1}.grid .g-col-lg-2{grid-column:auto/span 2}.grid .g-col-lg-3{grid-column:auto/span 3}.grid .g-col-lg-4{grid-column:auto/span 4}.grid .g-col-lg-5{grid-column:auto/span 5}.grid .g-col-lg-6{grid-column:auto/span 6}.grid .g-col-lg-7{grid-column:auto/span 7}.grid .g-col-lg-8{grid-column:auto/span 8}.grid .g-col-lg-9{grid-column:auto/span 9}.grid .g-col-lg-10{grid-column:auto/span 10}.grid .g-col-lg-11{grid-column:auto/span 11}.grid .g-col-lg-12{grid-column:auto/span 12}.grid .g-start-lg-1{grid-column-start:1}.grid .g-start-lg-2{grid-column-start:2}.grid .g-start-lg-3{grid-column-start:3}.grid .g-start-lg-4{grid-column-start:4}.grid .g-start-lg-5{grid-column-start:5}.grid .g-start-lg-6{grid-column-start:6}.grid .g-start-lg-7{grid-column-start:7}.grid .g-start-lg-8{grid-column-start:8}.grid .g-start-lg-9{grid-column-start:9}.grid .g-start-lg-10{grid-column-start:10}.grid .g-start-lg-11{grid-column-start:11}}@media(min-width: 1200px){.grid .g-col-xl-1{grid-column:auto/span 1}.grid .g-col-xl-2{grid-column:auto/span 2}.grid .g-col-xl-3{grid-column:auto/span 3}.grid .g-col-xl-4{grid-column:auto/span 4}.grid .g-col-xl-5{grid-column:auto/span 5}.grid .g-col-xl-6{grid-column:auto/span 6}.grid .g-col-xl-7{grid-column:auto/span 7}.grid .g-col-xl-8{grid-column:auto/span 8}.grid .g-col-xl-9{grid-column:auto/span 9}.grid .g-col-xl-10{grid-column:auto/span 10}.grid .g-col-xl-11{grid-column:auto/span 11}.grid .g-col-xl-12{grid-column:auto/span 12}.grid .g-start-xl-1{grid-column-start:1}.grid .g-start-xl-2{grid-column-start:2}.grid .g-start-xl-3{grid-column-start:3}.grid .g-start-xl-4{grid-column-start:4}.grid .g-start-xl-5{grid-column-start:5}.grid .g-start-xl-6{grid-column-start:6}.grid .g-start-xl-7{grid-column-start:7}.grid .g-start-xl-8{grid-column-start:8}.grid .g-start-xl-9{grid-column-start:9}.grid .g-start-xl-10{grid-column-start:10}.grid .g-start-xl-11{grid-column-start:11}}@media(min-width: 1400px){.grid .g-col-xxl-1{grid-column:auto/span 1}.grid .g-col-xxl-2{grid-column:auto/span 2}.grid .g-col-xxl-3{grid-column:auto/span 3}.grid .g-col-xxl-4{grid-column:auto/span 4}.grid .g-col-xxl-5{grid-column:auto/span 5}.grid .g-col-xxl-6{grid-column:auto/span 6}.grid .g-col-xxl-7{grid-column:auto/span 7}.grid .g-col-xxl-8{grid-column:auto/span 8}.grid .g-col-xxl-9{grid-column:auto/span 9}.grid .g-col-xxl-10{grid-column:auto/span 10}.grid .g-col-xxl-11{grid-column:auto/span 11}.grid .g-col-xxl-12{grid-column:auto/span 12}.grid .g-start-xxl-1{grid-column-start:1}.grid .g-start-xxl-2{grid-column-start:2}.grid .g-start-xxl-3{grid-column-start:3}.grid .g-start-xxl-4{grid-column-start:4}.grid .g-start-xxl-5{grid-column-start:5}.grid .g-start-xxl-6{grid-column-start:6}.grid .g-start-xxl-7{grid-column-start:7}.grid .g-start-xxl-8{grid-column-start:8}.grid .g-start-xxl-9{grid-column-start:9}.grid .g-start-xxl-10{grid-column-start:10}.grid .g-start-xxl-11{grid-column-start:11}}.table{--bs-table-color-type: initial;--bs-table-bg-type: initial;--bs-table-color-state: initial;--bs-table-bg-state: initial;--bs-table-color: #343a40;--bs-table-bg: #fff;--bs-table-border-color: #dee2e6;--bs-table-accent-bg: transparent;--bs-table-striped-color: #343a40;--bs-table-striped-bg: rgba(0, 0, 0, 0.05);--bs-table-active-color: #343a40;--bs-table-active-bg: rgba(0, 0, 0, 0.1);--bs-table-hover-color: #343a40;--bs-table-hover-bg: rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(1px*2) solid #b2bac1}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(even){--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-active{--bs-table-color-state: var(--bs-table-active-color);--bs-table-bg-state: var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state: var(--bs-table-hover-color);--bs-table-bg-state: var(--bs-table-hover-bg)}.table-primary{--bs-table-color: #000;--bs-table-bg: #d4e6f9;--bs-table-border-color: #bfcfe0;--bs-table-striped-bg: #c9dbed;--bs-table-striped-color: #000;--bs-table-active-bg: #bfcfe0;--bs-table-active-color: #000;--bs-table-hover-bg: #c4d5e6;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color: #000;--bs-table-bg: #d6d8d9;--bs-table-border-color: #c1c2c3;--bs-table-striped-bg: #cbcdce;--bs-table-striped-color: #000;--bs-table-active-bg: #c1c2c3;--bs-table-active-color: #000;--bs-table-hover-bg: #c6c8c9;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color: #000;--bs-table-bg: #d9f0d1;--bs-table-border-color: #c3d8bc;--bs-table-striped-bg: #cee4c7;--bs-table-striped-color: #000;--bs-table-active-bg: #c3d8bc;--bs-table-active-color: #000;--bs-table-hover-bg: #c9dec1;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color: #000;--bs-table-bg: #ebddf1;--bs-table-border-color: #d4c7d9;--bs-table-striped-bg: #dfd2e5;--bs-table-striped-color: #000;--bs-table-active-bg: #d4c7d9;--bs-table-active-color: #000;--bs-table-hover-bg: #d9ccdf;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color: #000;--bs-table-bg: #ffe3d1;--bs-table-border-color: #e6ccbc;--bs-table-striped-bg: #f2d8c7;--bs-table-striped-color: #000;--bs-table-active-bg: #e6ccbc;--bs-table-active-color: #000;--bs-table-hover-bg: #ecd2c1;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color: #000;--bs-table-bg: #ffccd7;--bs-table-border-color: #e6b8c2;--bs-table-striped-bg: #f2c2cc;--bs-table-striped-color: #000;--bs-table-active-bg: #e6b8c2;--bs-table-active-color: #000;--bs-table-hover-bg: #ecbdc7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color: #000;--bs-table-bg: #f8f9fa;--bs-table-border-color: #dfe0e1;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color: #fff;--bs-table-bg: #343a40;--bs-table-border-color: #484e53;--bs-table-striped-bg: #3e444a;--bs-table-striped-color: #fff;--bs-table-active-bg: #484e53;--bs-table-active-color: #fff;--bs-table-hover-bg: #43494e;--bs-table-hover-color: #fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label,.shiny-input-container .control-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(0.375rem + 1px);padding-bottom:calc(0.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(0.5rem + 1px);padding-bottom:calc(0.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(0.25rem + 1px);padding-bottom:calc(0.25rem + 1px);font-size:0.875rem}.form-text{margin-top:.25rem;font-size:0.875em;color:rgba(52,58,64,.75)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#343a40;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#fff;background-clip:padding-box;border:1px solid #dee2e6;border-radius:0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#343a40;background-color:#fff;border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:rgba(52,58,64,.75);opacity:1}.form-control:disabled{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#343a40;background-color:#f8f9fa;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#e9ecef}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#343a40;background-color:rgba(0,0,0,0);border:solid rgba(0,0,0,0);border-width:1px 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(1px * 2));padding:.25rem .5rem;font-size:0.875rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(1px * 2));padding:.5rem 1rem;font-size:1.25rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + 0.75rem + calc(1px * 2))}textarea.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(1px * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(1px * 2))}.form-control-color{width:3rem;height:calc(1.5em + 0.75rem + calc(1px * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0 !important}.form-control-color::-webkit-color-swatch{border:0 !important}.form-control-color.form-control-sm{height:calc(1.5em + 0.5rem + calc(1px * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(1px * 2))}.form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#343a40;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#fff;background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #dee2e6;border-radius:0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:rgba(0,0,0,0);text-shadow:0 0 0 #343a40}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check,.shiny-input-container .checkbox,.shiny-input-container .radio{display:block;min-height:1.5rem;padding-left:0;margin-bottom:.125rem}.form-check .form-check-input,.form-check .shiny-input-container .checkbox input,.form-check .shiny-input-container .radio input,.shiny-input-container .checkbox .form-check-input,.shiny-input-container .checkbox .shiny-input-container .checkbox input,.shiny-input-container .checkbox .shiny-input-container .radio input,.shiny-input-container .radio .form-check-input,.shiny-input-container .radio .shiny-input-container .checkbox input,.shiny-input-container .radio .shiny-input-container .radio input{float:left;margin-left:0}.form-check-reverse{padding-right:0;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:0;margin-left:0}.form-check-input,.shiny-input-container .checkbox input,.shiny-input-container .checkbox-inline input,.shiny-input-container .radio input,.shiny-input-container .radio-inline input{--bs-form-check-bg: #fff;width:1em;height:1em;margin-top:.25em;vertical-align:top;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid #dee2e6;print-color-adjust:exact}.form-check-input[type=radio],.shiny-input-container .checkbox input[type=radio],.shiny-input-container .checkbox-inline input[type=radio],.shiny-input-container .radio input[type=radio],.shiny-input-container .radio-inline input[type=radio]{border-radius:50%}.form-check-input:active,.shiny-input-container .checkbox input:active,.shiny-input-container .checkbox-inline input:active,.shiny-input-container .radio input:active,.shiny-input-container .radio-inline input:active{filter:brightness(90%)}.form-check-input:focus,.shiny-input-container .checkbox input:focus,.shiny-input-container .checkbox-inline input:focus,.shiny-input-container .radio input:focus,.shiny-input-container .radio-inline input:focus{border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-check-input:checked,.shiny-input-container .checkbox input:checked,.shiny-input-container .checkbox-inline input:checked,.shiny-input-container .radio input:checked,.shiny-input-container .radio-inline input:checked{background-color:#2780e3;border-color:#2780e3}.form-check-input:checked[type=checkbox],.shiny-input-container .checkbox input:checked[type=checkbox],.shiny-input-container .checkbox-inline input:checked[type=checkbox],.shiny-input-container .radio input:checked[type=checkbox],.shiny-input-container .radio-inline input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio],.shiny-input-container .checkbox input:checked[type=radio],.shiny-input-container .checkbox-inline input:checked[type=radio],.shiny-input-container .radio input:checked[type=radio],.shiny-input-container .radio-inline input:checked[type=radio]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate,.shiny-input-container .checkbox input[type=checkbox]:indeterminate,.shiny-input-container .checkbox-inline input[type=checkbox]:indeterminate,.shiny-input-container .radio input[type=checkbox]:indeterminate,.shiny-input-container .radio-inline input[type=checkbox]:indeterminate{background-color:#2780e3;border-color:#2780e3;--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled,.shiny-input-container .checkbox input:disabled,.shiny-input-container .checkbox-inline input:disabled,.shiny-input-container .radio input:disabled,.shiny-input-container .radio-inline input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input[disabled]~span,.form-check-input:disabled~.form-check-label,.form-check-input:disabled~span,.shiny-input-container .checkbox input[disabled]~.form-check-label,.shiny-input-container .checkbox input[disabled]~span,.shiny-input-container .checkbox input:disabled~.form-check-label,.shiny-input-container .checkbox input:disabled~span,.shiny-input-container .checkbox-inline input[disabled]~.form-check-label,.shiny-input-container .checkbox-inline input[disabled]~span,.shiny-input-container .checkbox-inline input:disabled~.form-check-label,.shiny-input-container .checkbox-inline input:disabled~span,.shiny-input-container .radio input[disabled]~.form-check-label,.shiny-input-container .radio input[disabled]~span,.shiny-input-container .radio input:disabled~.form-check-label,.shiny-input-container .radio input:disabled~span,.shiny-input-container .radio-inline input[disabled]~.form-check-label,.shiny-input-container .radio-inline input[disabled]~span,.shiny-input-container .radio-inline input:disabled~.form-check-label,.shiny-input-container .radio-inline input:disabled~span{cursor:default;opacity:.5}.form-check-label,.shiny-input-container .checkbox label,.shiny-input-container .checkbox-inline label,.shiny-input-container .radio label,.shiny-input-container .radio-inline label{cursor:pointer}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;transition:background-position .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2393c0f1'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:rgba(0,0,0,0)}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(39,128,227,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(39,128,227,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#2780e3;border:0;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#bed9f7}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#f8f9fa;border-color:rgba(0,0,0,0)}.form-range::-moz-range-thumb{width:1rem;height:1rem;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;background-color:#2780e3;border:0;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#bed9f7}.form-range::-moz-range-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#f8f9fa;border-color:rgba(0,0,0,0)}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:rgba(52,58,64,.75)}.form-range:disabled::-moz-range-thumb{background-color:rgba(52,58,64,.75)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(1px * 2));min-height:calc(3.5rem + calc(1px * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:1px solid rgba(0,0,0,0);transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media(prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown),.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill,.form-floating>.form-control-plaintext:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-control-plaintext~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem .375rem;z-index:-1;height:1.5em;content:"";background-color:#fff}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control-plaintext~label{border-width:1px 0}.form-floating>:disabled~label,.form-floating>.form-control:disabled~label{color:#6c757d}.form-floating>:disabled~label::after,.form-floating>.form-control:disabled~label::after{background-color:#e9ecef}.input-group{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:stretch;-webkit-align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select,.input-group>.form-floating{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus,.input-group>.form-floating:focus-within{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#343a40;text-align:center;white-space:nowrap;background-color:#f8f9fa;border:1px solid #dee2e6}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(1px*-1)}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#3fb618}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:#3fb618}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#3fb618;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%233fb618' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#3fb618;box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:#3fb618}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%233fb618' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:#3fb618;box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:#3fb618}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:#3fb618}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#3fb618}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):valid,.input-group>.form-control:not(:focus).is-valid,.was-validated .input-group>.form-select:not(:focus):valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.input-group>.form-floating:not(:focus-within).is-valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#ff0039}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:#ff0039}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#ff0039;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff0039'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff0039' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#ff0039;box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:#ff0039}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff0039'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff0039' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:#ff0039;box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:#ff0039}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:#ff0039}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#ff0039}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):invalid,.input-group>.form-control:not(:focus).is-invalid,.was-validated .input-group>.form-select:not(:focus):invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.input-group>.form-floating:not(:focus-within).is-invalid{z-index:4}.btn{--bs-btn-padding-x: 0.75rem;--bs-btn-padding-y: 0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.5;--bs-btn-color: #343a40;--bs-btn-bg: transparent;--bs-btn-border-width: 1px;--bs-btn-border-color: transparent;--bs-btn-border-radius: 0.25rem;--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity: 0.65;--bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;vertical-align:middle;cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-default{--bs-btn-color: #fff;--bs-btn-bg: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #2c3136;--bs-btn-hover-border-color: #2a2e33;--bs-btn-focus-shadow-rgb: 82, 88, 93;--bs-btn-active-color: #fff;--bs-btn-active-bg: #2a2e33;--bs-btn-active-border-color: #272c30;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #343a40;--bs-btn-disabled-border-color: #343a40}.btn-primary{--bs-btn-color: #fff;--bs-btn-bg: #2780e3;--bs-btn-border-color: #2780e3;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #216dc1;--bs-btn-hover-border-color: #1f66b6;--bs-btn-focus-shadow-rgb: 71, 147, 231;--bs-btn-active-color: #fff;--bs-btn-active-bg: #1f66b6;--bs-btn-active-border-color: #1d60aa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #2780e3;--bs-btn-disabled-border-color: #2780e3}.btn-secondary{--bs-btn-color: #fff;--bs-btn-bg: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #2c3136;--bs-btn-hover-border-color: #2a2e33;--bs-btn-focus-shadow-rgb: 82, 88, 93;--bs-btn-active-color: #fff;--bs-btn-active-bg: #2a2e33;--bs-btn-active-border-color: #272c30;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #343a40;--bs-btn-disabled-border-color: #343a40}.btn-success{--bs-btn-color: #fff;--bs-btn-bg: #3fb618;--bs-btn-border-color: #3fb618;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #369b14;--bs-btn-hover-border-color: #329213;--bs-btn-focus-shadow-rgb: 92, 193, 59;--bs-btn-active-color: #fff;--bs-btn-active-bg: #329213;--bs-btn-active-border-color: #2f8912;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #3fb618;--bs-btn-disabled-border-color: #3fb618}.btn-info{--bs-btn-color: #fff;--bs-btn-bg: #9954bb;--bs-btn-border-color: #9954bb;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #82479f;--bs-btn-hover-border-color: #7a4396;--bs-btn-focus-shadow-rgb: 168, 110, 197;--bs-btn-active-color: #fff;--bs-btn-active-bg: #7a4396;--bs-btn-active-border-color: #733f8c;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #9954bb;--bs-btn-disabled-border-color: #9954bb}.btn-warning{--bs-btn-color: #fff;--bs-btn-bg: #ff7518;--bs-btn-border-color: #ff7518;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #d96314;--bs-btn-hover-border-color: #cc5e13;--bs-btn-focus-shadow-rgb: 255, 138, 59;--bs-btn-active-color: #fff;--bs-btn-active-bg: #cc5e13;--bs-btn-active-border-color: #bf5812;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #ff7518;--bs-btn-disabled-border-color: #ff7518}.btn-danger{--bs-btn-color: #fff;--bs-btn-bg: #ff0039;--bs-btn-border-color: #ff0039;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #d90030;--bs-btn-hover-border-color: #cc002e;--bs-btn-focus-shadow-rgb: 255, 38, 87;--bs-btn-active-color: #fff;--bs-btn-active-bg: #cc002e;--bs-btn-active-border-color: #bf002b;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #ff0039;--bs-btn-disabled-border-color: #ff0039}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #d3d4d5;--bs-btn-hover-border-color: #c6c7c8;--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: #c6c7c8;--bs-btn-active-border-color: #babbbc;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-dark{--bs-btn-color: #fff;--bs-btn-bg: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #52585d;--bs-btn-hover-border-color: #484e53;--bs-btn-focus-shadow-rgb: 82, 88, 93;--bs-btn-active-color: #fff;--bs-btn-active-bg: #5d6166;--bs-btn-active-border-color: #484e53;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #343a40;--bs-btn-disabled-border-color: #343a40}.btn-outline-default{--bs-btn-color: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #343a40;--bs-btn-hover-border-color: #343a40;--bs-btn-focus-shadow-rgb: 52, 58, 64;--bs-btn-active-color: #fff;--bs-btn-active-bg: #343a40;--bs-btn-active-border-color: #343a40;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #343a40;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #343a40;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-primary{--bs-btn-color: #2780e3;--bs-btn-border-color: #2780e3;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #2780e3;--bs-btn-hover-border-color: #2780e3;--bs-btn-focus-shadow-rgb: 39, 128, 227;--bs-btn-active-color: #fff;--bs-btn-active-bg: #2780e3;--bs-btn-active-border-color: #2780e3;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #2780e3;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #2780e3;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-secondary{--bs-btn-color: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #343a40;--bs-btn-hover-border-color: #343a40;--bs-btn-focus-shadow-rgb: 52, 58, 64;--bs-btn-active-color: #fff;--bs-btn-active-bg: #343a40;--bs-btn-active-border-color: #343a40;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #343a40;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #343a40;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-success{--bs-btn-color: #3fb618;--bs-btn-border-color: #3fb618;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #3fb618;--bs-btn-hover-border-color: #3fb618;--bs-btn-focus-shadow-rgb: 63, 182, 24;--bs-btn-active-color: #fff;--bs-btn-active-bg: #3fb618;--bs-btn-active-border-color: #3fb618;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #3fb618;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #3fb618;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-info{--bs-btn-color: #9954bb;--bs-btn-border-color: #9954bb;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #9954bb;--bs-btn-hover-border-color: #9954bb;--bs-btn-focus-shadow-rgb: 153, 84, 187;--bs-btn-active-color: #fff;--bs-btn-active-bg: #9954bb;--bs-btn-active-border-color: #9954bb;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #9954bb;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #9954bb;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-warning{--bs-btn-color: #ff7518;--bs-btn-border-color: #ff7518;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #ff7518;--bs-btn-hover-border-color: #ff7518;--bs-btn-focus-shadow-rgb: 255, 117, 24;--bs-btn-active-color: #fff;--bs-btn-active-bg: #ff7518;--bs-btn-active-border-color: #ff7518;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ff7518;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ff7518;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-danger{--bs-btn-color: #ff0039;--bs-btn-border-color: #ff0039;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #ff0039;--bs-btn-hover-border-color: #ff0039;--bs-btn-focus-shadow-rgb: 255, 0, 57;--bs-btn-active-color: #fff;--bs-btn-active-bg: #ff0039;--bs-btn-active-border-color: #ff0039;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ff0039;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ff0039;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-light{--bs-btn-color: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #f8f9fa;--bs-btn-hover-border-color: #f8f9fa;--bs-btn-focus-shadow-rgb: 248, 249, 250;--bs-btn-active-color: #000;--bs-btn-active-bg: #f8f9fa;--bs-btn-active-border-color: #f8f9fa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #f8f9fa;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #f8f9fa;--bs-btn-bg: transparent;--bs-gradient: none}.btn-outline-dark{--bs-btn-color: #343a40;--bs-btn-border-color: #343a40;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #343a40;--bs-btn-hover-border-color: #343a40;--bs-btn-focus-shadow-rgb: 52, 58, 64;--bs-btn-active-color: #fff;--bs-btn-active-bg: #343a40;--bs-btn-active-border-color: #343a40;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #343a40;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #343a40;--bs-btn-bg: transparent;--bs-gradient: none}.btn-link{--bs-btn-font-weight: 400;--bs-btn-color: #2761e3;--bs-btn-bg: transparent;--bs-btn-border-color: transparent;--bs-btn-hover-color: #1f4eb6;--bs-btn-hover-border-color: transparent;--bs-btn-active-color: #1f4eb6;--bs-btn-active-border-color: transparent;--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-border-color: transparent;--bs-btn-box-shadow: 0 0 0 #000;--bs-btn-focus-shadow-rgb: 71, 121, 231;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--bs-btn-padding-y: 0.5rem;--bs-btn-padding-x: 1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius: 0.5rem}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: 0.25rem;--bs-btn-padding-x: 0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius: 0.2em}.fade{transition:opacity .15s linear}@media(prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .2s ease}@media(prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media(prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid rgba(0,0,0,0);border-bottom:0;border-left:.3em solid rgba(0,0,0,0)}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex: 1000;--bs-dropdown-min-width: 10rem;--bs-dropdown-padding-x: 0;--bs-dropdown-padding-y: 0.5rem;--bs-dropdown-spacer: 0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color: #343a40;--bs-dropdown-bg: #fff;--bs-dropdown-border-color: rgba(0, 0, 0, 0.175);--bs-dropdown-border-radius: 0.25rem;--bs-dropdown-border-width: 1px;--bs-dropdown-inner-border-radius: calc(0.25rem - 1px);--bs-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--bs-dropdown-divider-margin-y: 0.5rem;--bs-dropdown-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-dropdown-link-color: #343a40;--bs-dropdown-link-hover-color: #343a40;--bs-dropdown-link-hover-bg: #f8f9fa;--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #2780e3;--bs-dropdown-link-disabled-color: rgba(52, 58, 64, 0.5);--bs-dropdown-item-padding-x: 1rem;--bs-dropdown-item-padding-y: 0.25rem;--bs-dropdown-header-color: #6c757d;--bs-dropdown-header-padding-x: 1rem;--bs-dropdown-header-padding-y: 0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid rgba(0,0,0,0);border-bottom:.3em solid;border-left:.3em solid rgba(0,0,0,0)}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:0;border-bottom:.3em solid rgba(0,0,0,0);border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:.3em solid;border-bottom:.3em solid rgba(0,0,0,0)}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap;background-color:rgba(0,0,0,0);border:0}.dropdown-item:hover,.dropdown-item:focus{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:rgba(0,0,0,0)}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:0.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color: #dee2e6;--bs-dropdown-bg: #343a40;--bs-dropdown-border-color: rgba(0, 0, 0, 0.175);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color: #dee2e6;--bs-dropdown-link-hover-color: #fff;--bs-dropdown-divider-bg: rgba(0, 0, 0, 0.175);--bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #2780e3;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-header-color: #adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;justify-content:flex-start;-webkit-justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:calc(1px*-1)}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;-webkit-flex-direction:column;align-items:flex-start;-webkit-align-items:flex-start;justify-content:center;-webkit-justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:calc(1px*-1)}.nav{--bs-nav-link-padding-x: 1rem;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: #2761e3;--bs-nav-link-hover-color: #1f4eb6;--bs-nav-link-disabled-color: rgba(52, 58, 64, 0.75);display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background:none;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media(prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width: 1px;--bs-nav-tabs-border-color: #dee2e6;--bs-nav-tabs-border-radius: 0.25rem;--bs-nav-tabs-link-hover-border-color: #e9ecef #e9ecef #dee2e6;--bs-nav-tabs-link-active-color: #000;--bs-nav-tabs-link-active-bg: #fff;--bs-nav-tabs-link-active-border-color: #dee2e6 #dee2e6 #fff;border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1*var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid rgba(0,0,0,0)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1*var(--bs-nav-tabs-border-width))}.nav-pills{--bs-nav-pills-border-radius: 0.25rem;--bs-nav-pills-link-active-color: #fff;--bs-nav-pills-link-active-bg: #2780e3}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap: 1rem;--bs-nav-underline-border-width: 0.125rem;--bs-nav-underline-link-active-color: #000;gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid rgba(0,0,0,0)}.nav-underline .nav-link:hover,.nav-underline .nav-link:focus{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;-webkit-flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;-webkit-flex-basis:0;flex-grow:1;-webkit-flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x: 0;--bs-navbar-padding-y: 0.5rem;--bs-navbar-color: #fdfeff;--bs-navbar-hover-color: rgba(253, 253, 255, 0.8);--bs-navbar-disabled-color: rgba(253, 254, 255, 0.75);--bs-navbar-active-color: #fdfdff;--bs-navbar-brand-padding-y: 0.3125rem;--bs-navbar-brand-margin-end: 1rem;--bs-navbar-brand-font-size: 1.25rem;--bs-navbar-brand-color: #fdfeff;--bs-navbar-brand-hover-color: #fdfdff;--bs-navbar-nav-link-padding-x: 0.5rem;--bs-navbar-toggler-padding-y: 0.25;--bs-navbar-toggler-padding-x: 0;--bs-navbar-toggler-font-size: 1.25rem;--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfeff' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color: rgba(253, 254, 255, 0);--bs-navbar-toggler-border-radius: 0.25rem;--bs-navbar-toggler-focus-width: 0.25rem;--bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out;position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;display:-webkit-flex;flex-wrap:inherit;-webkit-flex-wrap:inherit;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x: 0;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-navbar-color);--bs-nav-link-hover-color: var(--bs-navbar-hover-color);--bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;-webkit-flex-basis:100%;flex-grow:1;-webkit-flex-grow:1;align-items:center;-webkit-align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:rgba(0,0,0,0);border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);transition:var(--bs-navbar-toggler-transition)}@media(prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;-webkit-flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color: #fdfeff;--bs-navbar-hover-color: rgba(253, 253, 255, 0.8);--bs-navbar-disabled-color: rgba(253, 254, 255, 0.75);--bs-navbar-active-color: #fdfdff;--bs-navbar-brand-color: #fdfeff;--bs-navbar-brand-hover-color: #fdfdff;--bs-navbar-toggler-border-color: rgba(253, 254, 255, 0);--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfeff' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfeff' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: 0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: 1px;--bs-card-border-color: rgba(0, 0, 0, 0.175);--bs-card-border-radius: 0.25rem;--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc(0.25rem - 1px);--bs-card-cap-padding-y: 0.5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(52, 58, 64, 0.25);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: #fff;--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: 0.75rem;position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0}.card>.list-group:last-child{border-bottom-width:0}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;-webkit-flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-0.5*var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header-tabs{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-bottom:calc(-1*var(--bs-card-cap-padding-y));margin-left:calc(-0.5*var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-left:calc(-0.5*var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media(min-width: 576px){.card-group{display:flex;display:-webkit-flex;flex-flow:row wrap;-webkit-flex-flow:row wrap}.card-group>.card{flex:1 0 0%;-webkit-flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}}.accordion{--bs-accordion-color: #343a40;--bs-accordion-bg: #fff;--bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;--bs-accordion-border-color: #dee2e6;--bs-accordion-border-width: 1px;--bs-accordion-border-radius: 0.25rem;--bs-accordion-inner-border-radius: calc(0.25rem - 1px);--bs-accordion-btn-padding-x: 1.25rem;--bs-accordion-btn-padding-y: 1rem;--bs-accordion-btn-color: #343a40;--bs-accordion-btn-bg: #fff;--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23343a40'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width: 1.25rem;--bs-accordion-btn-icon-transform: rotate(-180deg);--bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2310335b'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-focus-border-color: #93c0f1;--bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(39, 128, 227, 0.25);--bs-accordion-body-padding-x: 1.25rem;--bs-accordion-body-padding-y: 1rem;--bs-accordion-active-color: #10335b;--bs-accordion-active-bg: #d4e6f9}.accordion-button{position:relative;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media(prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1*var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;-webkit-flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media(prefers-reduced-motion: reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:var(--bs-accordion-btn-focus-border-color);outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:not(:first-of-type){border-top:0}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%237db3ee'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%237db3ee'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x: 0;--bs-breadcrumb-padding-y: 0;--bs-breadcrumb-margin-bottom: 1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color: rgba(52, 58, 64, 0.75);--bs-breadcrumb-item-padding-x: 0.5rem;--bs-breadcrumb-item-active-color: rgba(52, 58, 64, 0.75);display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, ">") /* rtl: var(--bs-breadcrumb-divider, ">") */}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x: 0.75rem;--bs-pagination-padding-y: 0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color: #2761e3;--bs-pagination-bg: #fff;--bs-pagination-border-width: 1px;--bs-pagination-border-color: #dee2e6;--bs-pagination-border-radius: 0.25rem;--bs-pagination-hover-color: #1f4eb6;--bs-pagination-hover-bg: #f8f9fa;--bs-pagination-hover-border-color: #dee2e6;--bs-pagination-focus-color: #1f4eb6;--bs-pagination-focus-bg: #e9ecef;--bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(39, 128, 227, 0.25);--bs-pagination-active-color: #fff;--bs-pagination-active-bg: #2780e3;--bs-pagination-active-border-color: #2780e3;--bs-pagination-disabled-color: rgba(52, 58, 64, 0.75);--bs-pagination-disabled-bg: #e9ecef;--bs-pagination-disabled-border-color: #dee2e6;display:flex;display:-webkit-flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(1px*-1)}.pagination-lg{--bs-pagination-padding-x: 1.5rem;--bs-pagination-padding-y: 0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius: 0.5rem}.pagination-sm{--bs-pagination-padding-x: 0.5rem;--bs-pagination-padding-y: 0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius: 0.2em}.badge{--bs-badge-padding-x: 0.65em;--bs-badge-padding-y: 0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight: 700;--bs-badge-color: #fff;--bs-badge-border-radius: 0.25rem;display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg: transparent;--bs-alert-padding-x: 1rem;--bs-alert-padding-y: 1rem;--bs-alert-margin-bottom: 1rem;--bs-alert-color: inherit;--bs-alert-border-color: transparent;--bs-alert-border: 0 solid var(--bs-alert-border-color);--bs-alert-border-radius: 0.25rem;--bs-alert-link-color: inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-default{--bs-alert-color: var(--bs-default-text-emphasis);--bs-alert-bg: var(--bs-default-bg-subtle);--bs-alert-border-color: var(--bs-default-border-subtle);--bs-alert-link-color: var(--bs-default-text-emphasis)}.alert-primary{--bs-alert-color: var(--bs-primary-text-emphasis);--bs-alert-bg: var(--bs-primary-bg-subtle);--bs-alert-border-color: var(--bs-primary-border-subtle);--bs-alert-link-color: var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color: var(--bs-secondary-text-emphasis);--bs-alert-bg: var(--bs-secondary-bg-subtle);--bs-alert-border-color: var(--bs-secondary-border-subtle);--bs-alert-link-color: var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color: var(--bs-success-text-emphasis);--bs-alert-bg: var(--bs-success-bg-subtle);--bs-alert-border-color: var(--bs-success-border-subtle);--bs-alert-link-color: var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color: var(--bs-info-text-emphasis);--bs-alert-bg: var(--bs-info-bg-subtle);--bs-alert-border-color: var(--bs-info-border-subtle);--bs-alert-link-color: var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color: var(--bs-warning-text-emphasis);--bs-alert-bg: var(--bs-warning-bg-subtle);--bs-alert-border-color: var(--bs-warning-border-subtle);--bs-alert-link-color: var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color: var(--bs-danger-text-emphasis);--bs-alert-bg: var(--bs-danger-bg-subtle);--bs-alert-border-color: var(--bs-danger-border-subtle);--bs-alert-link-color: var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color: var(--bs-light-text-emphasis);--bs-alert-bg: var(--bs-light-bg-subtle);--bs-alert-border-color: var(--bs-light-border-subtle);--bs-alert-link-color: var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color: var(--bs-dark-text-emphasis);--bs-alert-bg: var(--bs-dark-bg-subtle);--bs-alert-border-color: var(--bs-dark-border-subtle);--bs-alert-link-color: var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:.5rem}}.progress,.progress-stacked{--bs-progress-height: 0.5rem;--bs-progress-font-size:0.75rem;--bs-progress-bg: #e9ecef;--bs-progress-border-radius: 0.25rem;--bs-progress-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-progress-bar-color: #fff;--bs-progress-bar-bg: #2780e3;--bs-progress-bar-transition: width 0.6s ease;display:flex;display:-webkit-flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg)}.progress-bar{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;justify-content:center;-webkit-justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media(prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color: #343a40;--bs-list-group-bg: #fff;--bs-list-group-border-color: #dee2e6;--bs-list-group-border-width: 1px;--bs-list-group-border-radius: 0.25rem;--bs-list-group-item-padding-x: 1rem;--bs-list-group-item-padding-y: 0.5rem;--bs-list-group-action-color: rgba(52, 58, 64, 0.75);--bs-list-group-action-hover-color: #000;--bs-list-group-action-hover-bg: #f8f9fa;--bs-list-group-action-active-color: #343a40;--bs-list-group-action-active-bg: #e9ecef;--bs-list-group-disabled-color: rgba(52, 58, 64, 0.75);--bs-list-group-disabled-bg: #fff;--bs-list-group-active-color: #fff;--bs-list-group-active-bg: #2780e3;--bs-list-group-active-border-color: #2780e3;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1*var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-default{--bs-list-group-color: var(--bs-default-text-emphasis);--bs-list-group-bg: var(--bs-default-bg-subtle);--bs-list-group-border-color: var(--bs-default-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-default-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-default-border-subtle);--bs-list-group-active-color: var(--bs-default-bg-subtle);--bs-list-group-active-bg: var(--bs-default-text-emphasis);--bs-list-group-active-border-color: var(--bs-default-text-emphasis)}.list-group-item-primary{--bs-list-group-color: var(--bs-primary-text-emphasis);--bs-list-group-bg: var(--bs-primary-bg-subtle);--bs-list-group-border-color: var(--bs-primary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-primary-border-subtle);--bs-list-group-active-color: var(--bs-primary-bg-subtle);--bs-list-group-active-bg: var(--bs-primary-text-emphasis);--bs-list-group-active-border-color: var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color: var(--bs-secondary-text-emphasis);--bs-list-group-bg: var(--bs-secondary-bg-subtle);--bs-list-group-border-color: var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);--bs-list-group-active-color: var(--bs-secondary-bg-subtle);--bs-list-group-active-bg: var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color: var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color: var(--bs-success-text-emphasis);--bs-list-group-bg: var(--bs-success-bg-subtle);--bs-list-group-border-color: var(--bs-success-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-success-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-success-border-subtle);--bs-list-group-active-color: var(--bs-success-bg-subtle);--bs-list-group-active-bg: var(--bs-success-text-emphasis);--bs-list-group-active-border-color: var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color: var(--bs-info-text-emphasis);--bs-list-group-bg: var(--bs-info-bg-subtle);--bs-list-group-border-color: var(--bs-info-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-info-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-info-border-subtle);--bs-list-group-active-color: var(--bs-info-bg-subtle);--bs-list-group-active-bg: var(--bs-info-text-emphasis);--bs-list-group-active-border-color: var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color: var(--bs-warning-text-emphasis);--bs-list-group-bg: var(--bs-warning-bg-subtle);--bs-list-group-border-color: var(--bs-warning-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-warning-border-subtle);--bs-list-group-active-color: var(--bs-warning-bg-subtle);--bs-list-group-active-bg: var(--bs-warning-text-emphasis);--bs-list-group-active-border-color: var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color: var(--bs-danger-text-emphasis);--bs-list-group-bg: var(--bs-danger-bg-subtle);--bs-list-group-border-color: var(--bs-danger-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-danger-border-subtle);--bs-list-group-active-color: var(--bs-danger-bg-subtle);--bs-list-group-active-bg: var(--bs-danger-text-emphasis);--bs-list-group-active-border-color: var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color: var(--bs-light-text-emphasis);--bs-list-group-bg: var(--bs-light-bg-subtle);--bs-list-group-border-color: var(--bs-light-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-light-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-light-border-subtle);--bs-list-group-active-color: var(--bs-light-bg-subtle);--bs-list-group-active-bg: var(--bs-light-text-emphasis);--bs-list-group-active-border-color: var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color: var(--bs-dark-text-emphasis);--bs-list-group-bg: var(--bs-dark-bg-subtle);--bs-list-group-border-color: var(--bs-dark-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-dark-border-subtle);--bs-list-group-active-color: var(--bs-dark-bg-subtle);--bs-list-group-active-bg: var(--bs-dark-text-emphasis);--bs-list-group-active-border-color: var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color: #000;--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity: 0.5;--bs-btn-close-hover-opacity: 0.75;--bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(39, 128, 227, 0.25);--bs-btn-close-focus-opacity: 1;--bs-btn-close-disabled-opacity: 0.25;--bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:rgba(0,0,0,0) var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex: 1090;--bs-toast-padding-x: 0.75rem;--bs-toast-padding-y: 0.5rem;--bs-toast-spacing: 1.5rem;--bs-toast-max-width: 350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg: rgba(255, 255, 255, 0.85);--bs-toast-border-width: 1px;--bs-toast-border-color: rgba(0, 0, 0, 0.175);--bs-toast-border-radius: 0.25rem;--bs-toast-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-toast-header-color: rgba(52, 58, 64, 0.75);--bs-toast-header-bg: rgba(255, 255, 255, 0.85);--bs-toast-header-border-color: rgba(0, 0, 0, 0.175);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex: 1090;position:absolute;z-index:var(--bs-toast-zindex);width:max-content;width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:-o-max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color)}.toast-header .btn-close{margin-right:calc(-0.5*var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex: 1055;--bs-modal-width: 500px;--bs-modal-padding: 1rem;--bs-modal-margin: 0.5rem;--bs-modal-color: ;--bs-modal-bg: #fff;--bs-modal-border-color: rgba(0, 0, 0, 0.175);--bs-modal-border-width: 1px;--bs-modal-border-radius: 0.5rem;--bs-modal-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-modal-inner-border-radius: calc(0.5rem - 1px);--bs-modal-header-padding-x: 1rem;--bs-modal-header-padding-y: 1rem;--bs-modal-header-padding: 1rem 1rem;--bs-modal-header-border-color: #dee2e6;--bs-modal-header-border-width: 1px;--bs-modal-title-line-height: 1.5;--bs-modal-footer-gap: 0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color: #dee2e6;--bs-modal-footer-border-width: 1px;position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -50px)}@media(prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin)*2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;min-height:calc(100% - var(--bs-modal-margin)*2)}.modal-content{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);outline:0}.modal-backdrop{--bs-backdrop-zindex: 1050;--bs-backdrop-bg: #000;--bs-backdrop-opacity: 0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y)*.5) calc(var(--bs-modal-header-padding-x)*.5);margin:calc(-0.5*var(--bs-modal-header-padding-y)) calc(-0.5*var(--bs-modal-header-padding-x)) calc(-0.5*var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:flex-end;-webkit-justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap)*.5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap)*.5)}@media(min-width: 576px){.modal{--bs-modal-margin: 1.75rem;--bs-modal-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width: 300px}}@media(min-width: 992px){.modal-lg,.modal-xl{--bs-modal-width: 800px}}@media(min-width: 1200px){.modal-xl{--bs-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0}.modal-fullscreen .modal-body{overflow-y:auto}@media(max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media(max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media(max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media(max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media(max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex: 1080;--bs-tooltip-max-width: 200px;--bs-tooltip-padding-x: 0.5rem;--bs-tooltip-padding-y: 0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color: #fff;--bs-tooltip-bg: #000;--bs-tooltip-border-radius: 0.25rem;--bs-tooltip-opacity: 0.9;--bs-tooltip-arrow-width: 0.8rem;--bs-tooltip-arrow-height: 0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:"Source Sans Pro",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-bottom .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) 0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg)}.popover{--bs-popover-zindex: 1070;--bs-popover-max-width: 276px;--bs-popover-font-size:0.875rem;--bs-popover-bg: #fff;--bs-popover-border-width: 1px;--bs-popover-border-color: rgba(0, 0, 0, 0.175);--bs-popover-border-radius: 0.5rem;--bs-popover-inner-border-radius: calc(0.5rem - 1px);--bs-popover-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-popover-header-padding-x: 1rem;--bs-popover-header-padding-y: 0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color: inherit;--bs-popover-header-bg: #e9ecef;--bs-popover-body-padding-x: 1rem;--bs-popover-body-padding-y: 1rem;--bs-popover-body-color: #343a40;--bs-popover-arrow-width: 1rem;--bs-popover-arrow-height: 0.5rem;--bs-popover-arrow-border: var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:"Source Sans Pro",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:rgba(0,0,0,0);border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{border-width:0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-0.5*var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) 0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y;-webkit-touch-action:pan-y;-moz-touch-action:pan-y;-ms-touch-action:pan-y;-o-touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:center;-webkit-justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;display:-webkit-flex;justify-content:center;-webkit-justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;-webkit-flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid rgba(0,0,0,0);border-bottom:10px solid rgba(0,0,0,0);opacity:.5;transition:opacity .6s ease}@media(prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-grow,.spinner-border{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-border-width: 0.25em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:rgba(0,0,0,0)}.spinner-border-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem;--bs-spinner-border-width: 0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--bs-offcanvas-zindex: 1045;--bs-offcanvas-width: 400px;--bs-offcanvas-height: 30vh;--bs-offcanvas-padding-x: 1rem;--bs-offcanvas-padding-y: 1rem;--bs-offcanvas-color: #343a40;--bs-offcanvas-bg: #fff;--bs-offcanvas-border-width: 1px;--bs-offcanvas-border-color: rgba(0, 0, 0, 0.175);--bs-offcanvas-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-offcanvas-transition: transform 0.3s ease-in-out;--bs-offcanvas-title-line-height: 1.5}@media(max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 575.98px)and (prefers-reduced-motion: reduce){.offcanvas-sm{transition:none}}@media(max-width: 575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.showing,.offcanvas-sm.show:not(.hiding){transform:none}.offcanvas-sm.showing,.offcanvas-sm.hiding,.offcanvas-sm.show{visibility:visible}}@media(min-width: 576px){.offcanvas-sm{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 767.98px)and (prefers-reduced-motion: reduce){.offcanvas-md{transition:none}}@media(max-width: 767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.showing,.offcanvas-md.show:not(.hiding){transform:none}.offcanvas-md.showing,.offcanvas-md.hiding,.offcanvas-md.show{visibility:visible}}@media(min-width: 768px){.offcanvas-md{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 991.98px)and (prefers-reduced-motion: reduce){.offcanvas-lg{transition:none}}@media(max-width: 991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.showing,.offcanvas-lg.show:not(.hiding){transform:none}.offcanvas-lg.showing,.offcanvas-lg.hiding,.offcanvas-lg.show{visibility:visible}}@media(min-width: 992px){.offcanvas-lg{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1199.98px)and (prefers-reduced-motion: reduce){.offcanvas-xl{transition:none}}@media(max-width: 1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.showing,.offcanvas-xl.show:not(.hiding){transform:none}.offcanvas-xl.showing,.offcanvas-xl.hiding,.offcanvas-xl.show{visibility:visible}}@media(min-width: 1200px){.offcanvas-xl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1399.98px)and (prefers-reduced-motion: reduce){.offcanvas-xxl{transition:none}}@media(max-width: 1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.showing,.offcanvas-xxl.show:not(.hiding){transform:none}.offcanvas-xxl.showing,.offcanvas-xxl.hiding,.offcanvas-xxl.show{visibility:visible}}@media(min-width: 1400px){.offcanvas-xxl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media(prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y)*.5) calc(var(--bs-offcanvas-padding-x)*.5);margin-top:calc(-0.5*var(--bs-offcanvas-padding-y));margin-right:calc(-0.5*var(--bs-offcanvas-padding-x));margin-bottom:calc(-0.5*var(--bs-offcanvas-padding-y))}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;-webkit-flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);-webkit-mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);mask-size:200% 100%;-webkit-mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{mask-position:-200% 0%;-webkit-mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-default{color:#fff !important;background-color:RGBA(var(--bs-default-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-primary{color:#fff !important;background-color:RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-secondary{color:#fff !important;background-color:RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-success{color:#fff !important;background-color:RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-info{color:#fff !important;background-color:RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-warning{color:#fff !important;background-color:RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-danger{color:#fff !important;background-color:RGBA(var(--bs-danger-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-light{color:#000 !important;background-color:RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-dark{color:#fff !important;background-color:RGBA(var(--bs-dark-rgb), var(--bs-bg-opacity, 1)) !important}.link-default{color:RGBA(var(--bs-default-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-default-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-default:hover,.link-default:focus{color:RGBA(42, 46, 51, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(42, 46, 51, var(--bs-link-underline-opacity, 1)) !important}.link-primary{color:RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-primary:hover,.link-primary:focus{color:RGBA(31, 102, 182, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(31, 102, 182, var(--bs-link-underline-opacity, 1)) !important}.link-secondary{color:RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-secondary:hover,.link-secondary:focus{color:RGBA(42, 46, 51, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(42, 46, 51, var(--bs-link-underline-opacity, 1)) !important}.link-success{color:RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-success:hover,.link-success:focus{color:RGBA(50, 146, 19, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(50, 146, 19, var(--bs-link-underline-opacity, 1)) !important}.link-info{color:RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-info:hover,.link-info:focus{color:RGBA(122, 67, 150, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(122, 67, 150, var(--bs-link-underline-opacity, 1)) !important}.link-warning{color:RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-warning:hover,.link-warning:focus{color:RGBA(204, 94, 19, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(204, 94, 19, var(--bs-link-underline-opacity, 1)) !important}.link-danger{color:RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-danger:hover,.link-danger:focus{color:RGBA(204, 0, 46, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(204, 0, 46, var(--bs-link-underline-opacity, 1)) !important}.link-light{color:RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-light:hover,.link-light:focus{color:RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important}.link-dark{color:RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-dark:hover,.link-dark:focus{color:RGBA(42, 46, 51, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(42, 46, 51, var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis:hover,.link-body-emphasis:focus{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 0.75)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-align-items:center;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));text-underline-offset:.25em;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;-webkit-flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media(prefers-reduced-motion: reduce){.icon-link>.bi{transition:none}}.icon-link-hover:hover>.bi,.icon-link-hover:focus-visible>.bi{transform:var(--bs-icon-link-transform, translate3d(0.25em, 0, 0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}.sticky-bottom{position:sticky;bottom:0;z-index:1020}@media(min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;display:-webkit-flex;flex-direction:row;-webkit-flex-direction:row;align-items:center;-webkit-align-items:center;align-self:stretch;-webkit-align-self:stretch}.vstack{display:flex;display:-webkit-flex;flex:1 1 auto;-webkit-flex:1 1 auto;flex-direction:column;-webkit-flex-direction:column;align-self:stretch;-webkit-align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}.visually-hidden:not(caption),.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption){position:absolute !important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;-webkit-align-self:stretch;width:1px;min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.object-fit-contain{object-fit:contain !important}.object-fit-cover{object-fit:cover !important}.object-fit-fill{object-fit:fill !important}.object-fit-scale{object-fit:scale-down !important}.object-fit-none{object-fit:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.overflow-x-auto{overflow-x:auto !important}.overflow-x-hidden{overflow-x:hidden !important}.overflow-x-visible{overflow-x:visible !important}.overflow-x-scroll{overflow-x:scroll !important}.overflow-y-auto{overflow-y:auto !important}.overflow-y-hidden{overflow-y:hidden !important}.overflow-y-visible{overflow-y:visible !important}.overflow-y-scroll{overflow-y:scroll !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-grid{display:grid !important}.d-inline-grid{display:inline-grid !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:flex !important}.d-inline-flex{display:inline-flex !important}.d-none{display:none !important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15) !important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075) !important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175) !important}.shadow-none{box-shadow:none !important}.focus-ring-default{--bs-focus-ring-color: rgba(var(--bs-default-rgb), var(--bs-focus-ring-opacity))}.focus-ring-primary{--bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.top-0{top:0 !important}.top-50{top:50% !important}.top-100{top:100% !important}.bottom-0{bottom:0 !important}.bottom-50{bottom:50% !important}.bottom-100{bottom:100% !important}.start-0{left:0 !important}.start-50{left:50% !important}.start-100{left:100% !important}.end-0{right:0 !important}.end-50{right:50% !important}.end-100{right:100% !important}.translate-middle{transform:translate(-50%, -50%) !important}.translate-middle-x{transform:translateX(-50%) !important}.translate-middle-y{transform:translateY(-50%) !important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-0{border:0 !important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-top-0{border-top:0 !important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-start-0{border-left:0 !important}.border-default{--bs-border-opacity: 1;border-color:rgba(var(--bs-default-rgb), var(--bs-border-opacity)) !important}.border-primary{--bs-border-opacity: 1;border-color:rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important}.border-secondary{--bs-border-opacity: 1;border-color:rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important}.border-success{--bs-border-opacity: 1;border-color:rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important}.border-info{--bs-border-opacity: 1;border-color:rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important}.border-warning{--bs-border-opacity: 1;border-color:rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important}.border-danger{--bs-border-opacity: 1;border-color:rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important}.border-light{--bs-border-opacity: 1;border-color:rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important}.border-dark{--bs-border-opacity: 1;border-color:rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important}.border-black{--bs-border-opacity: 1;border-color:rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important}.border-white{--bs-border-opacity: 1;border-color:rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle) !important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle) !important}.border-success-subtle{border-color:var(--bs-success-border-subtle) !important}.border-info-subtle{border-color:var(--bs-info-border-subtle) !important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle) !important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle) !important}.border-light-subtle{border-color:var(--bs-light-border-subtle) !important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle) !important}.border-1{border-width:1px !important}.border-2{border-width:2px !important}.border-3{border-width:3px !important}.border-4{border-width:4px !important}.border-5{border-width:5px !important}.border-opacity-10{--bs-border-opacity: 0.1}.border-opacity-25{--bs-border-opacity: 0.25}.border-opacity-50{--bs-border-opacity: 0.5}.border-opacity-75{--bs-border-opacity: 0.75}.border-opacity-100{--bs-border-opacity: 1}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.mw-100{max-width:100% !important}.vw-100{width:100vw !important}.min-vw-100{min-width:100vw !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mh-100{max-height:100% !important}.vh-100{height:100vh !important}.min-vh-100{min-height:100vh !important}.flex-fill{flex:1 1 auto !important}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.flex-shrink-0{flex-shrink:0 !important}.flex-shrink-1{flex-shrink:1 !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.justify-content-evenly{justify-content:space-evenly !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}.order-first{order:-1 !important}.order-0{order:0 !important}.order-1{order:1 !important}.order-2{order:2 !important}.order-3{order:3 !important}.order-4{order:4 !important}.order-5{order:5 !important}.order-last{order:6 !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.m-auto{margin:auto !important}.mx-0{margin-right:0 !important;margin-left:0 !important}.mx-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-3{margin-right:1rem !important;margin-left:1rem !important}.mx-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-5{margin-right:3rem !important;margin-left:3rem !important}.mx-auto{margin-right:auto !important;margin-left:auto !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mt-auto{margin-top:auto !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.me-auto{margin-right:auto !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.mb-auto{margin-bottom:auto !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.ms-auto{margin-left:auto !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.px-0{padding-right:0 !important;padding-left:0 !important}.px-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-3{padding-right:1rem !important;padding-left:1rem !important}.px-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-5{padding-right:3rem !important;padding-left:3rem !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.row-gap-0{row-gap:0 !important}.row-gap-1{row-gap:.25rem !important}.row-gap-2{row-gap:.5rem !important}.row-gap-3{row-gap:1rem !important}.row-gap-4{row-gap:1.5rem !important}.row-gap-5{row-gap:3rem !important}.column-gap-0{column-gap:0 !important}.column-gap-1{column-gap:.25rem !important}.column-gap-2{column-gap:.5rem !important}.column-gap-3{column-gap:1rem !important}.column-gap-4{column-gap:1.5rem !important}.column-gap-5{column-gap:3rem !important}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.325rem + 0.9vw) !important}.fs-2{font-size:calc(1.29rem + 0.48vw) !important}.fs-3{font-size:calc(1.27rem + 0.24vw) !important}.fs-4{font-size:1.25rem !important}.fs-5{font-size:1.1rem !important}.fs-6{font-size:1rem !important}.fst-italic{font-style:italic !important}.fst-normal{font-style:normal !important}.fw-lighter{font-weight:lighter !important}.fw-light{font-weight:300 !important}.fw-normal{font-weight:400 !important}.fw-medium{font-weight:500 !important}.fw-semibold{font-weight:600 !important}.fw-bold{font-weight:700 !important}.fw-bolder{font-weight:bolder !important}.lh-1{line-height:1 !important}.lh-sm{line-height:1.25 !important}.lh-base{line-height:1.5 !important}.lh-lg{line-height:2 !important}.text-start{text-align:left !important}.text-end{text-align:right !important}.text-center{text-align:center !important}.text-decoration-none{text-decoration:none !important}.text-decoration-underline{text-decoration:underline !important}.text-decoration-line-through{text-decoration:line-through !important}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-wrap{white-space:normal !important}.text-nowrap{white-space:nowrap !important}.text-break{word-wrap:break-word !important;word-break:break-word !important}.text-default{--bs-text-opacity: 1;color:rgba(var(--bs-default-rgb), var(--bs-text-opacity)) !important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-black-50{--bs-text-opacity: 1;color:rgba(0,0,0,.5) !important}.text-white-50{--bs-text-opacity: 1;color:rgba(255,255,255,.5) !important}.text-body-secondary{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-body-tertiary{--bs-text-opacity: 1;color:var(--bs-tertiary-color) !important}.text-body-emphasis{--bs-text-opacity: 1;color:var(--bs-emphasis-color) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis) !important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis) !important}.text-success-emphasis{color:var(--bs-success-text-emphasis) !important}.text-info-emphasis{color:var(--bs-info-text-emphasis) !important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis) !important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis) !important}.text-light-emphasis{color:var(--bs-light-text-emphasis) !important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis) !important}.link-opacity-10{--bs-link-opacity: 0.1}.link-opacity-10-hover:hover{--bs-link-opacity: 0.1}.link-opacity-25{--bs-link-opacity: 0.25}.link-opacity-25-hover:hover{--bs-link-opacity: 0.25}.link-opacity-50{--bs-link-opacity: 0.5}.link-opacity-50-hover:hover{--bs-link-opacity: 0.5}.link-opacity-75{--bs-link-opacity: 0.75}.link-opacity-75-hover:hover{--bs-link-opacity: 0.75}.link-opacity-100{--bs-link-opacity: 1}.link-opacity-100-hover:hover{--bs-link-opacity: 1}.link-offset-1{text-underline-offset:.125em !important}.link-offset-1-hover:hover{text-underline-offset:.125em !important}.link-offset-2{text-underline-offset:.25em !important}.link-offset-2-hover:hover{text-underline-offset:.25em !important}.link-offset-3{text-underline-offset:.375em !important}.link-offset-3-hover:hover{text-underline-offset:.375em !important}.link-underline-default{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-default-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-primary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-secondary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-success{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-info{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-warning{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-danger{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-light{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-dark{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important}.link-underline{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-underline-opacity-0{--bs-link-underline-opacity: 0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity: 0}.link-underline-opacity-10{--bs-link-underline-opacity: 0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity: 0.1}.link-underline-opacity-25{--bs-link-underline-opacity: 0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity: 0.25}.link-underline-opacity-50{--bs-link-underline-opacity: 0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity: 0.5}.link-underline-opacity-75{--bs-link-underline-opacity: 0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity: 0.75}.link-underline-opacity-100{--bs-link-underline-opacity: 1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity: 1}.bg-default{--bs-bg-opacity: 1;background-color:rgba(var(--bs-default-rgb), var(--bs-bg-opacity)) !important}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:rgba(0,0,0,0) !important}.bg-body-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-body-tertiary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-tertiary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle) !important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle) !important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle) !important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle) !important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle) !important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle) !important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle) !important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle) !important}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{user-select:all !important}.user-select-auto{user-select:auto !important}.user-select-none{user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:var(--bs-border-radius) !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:var(--bs-border-radius-sm) !important}.rounded-2{border-radius:var(--bs-border-radius) !important}.rounded-3{border-radius:var(--bs-border-radius-lg) !important}.rounded-4{border-radius:var(--bs-border-radius-xl) !important}.rounded-5{border-radius:var(--bs-border-radius-xxl) !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:var(--bs-border-radius-pill) !important}.rounded-top{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-0{border-top-left-radius:0 !important;border-top-right-radius:0 !important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm) !important;border-top-right-radius:var(--bs-border-radius-sm) !important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg) !important;border-top-right-radius:var(--bs-border-radius-lg) !important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl) !important;border-top-right-radius:var(--bs-border-radius-xl) !important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl) !important;border-top-right-radius:var(--bs-border-radius-xxl) !important}.rounded-top-circle{border-top-left-radius:50% !important;border-top-right-radius:50% !important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill) !important;border-top-right-radius:var(--bs-border-radius-pill) !important}.rounded-end{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-0{border-top-right-radius:0 !important;border-bottom-right-radius:0 !important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm) !important;border-bottom-right-radius:var(--bs-border-radius-sm) !important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg) !important;border-bottom-right-radius:var(--bs-border-radius-lg) !important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl) !important;border-bottom-right-radius:var(--bs-border-radius-xl) !important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-right-radius:var(--bs-border-radius-xxl) !important}.rounded-end-circle{border-top-right-radius:50% !important;border-bottom-right-radius:50% !important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill) !important;border-bottom-right-radius:var(--bs-border-radius-pill) !important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-0{border-bottom-right-radius:0 !important;border-bottom-left-radius:0 !important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm) !important;border-bottom-left-radius:var(--bs-border-radius-sm) !important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg) !important;border-bottom-left-radius:var(--bs-border-radius-lg) !important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl) !important;border-bottom-left-radius:var(--bs-border-radius-xl) !important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-left-radius:var(--bs-border-radius-xxl) !important}.rounded-bottom-circle{border-bottom-right-radius:50% !important;border-bottom-left-radius:50% !important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill) !important;border-bottom-left-radius:var(--bs-border-radius-pill) !important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-0{border-bottom-left-radius:0 !important;border-top-left-radius:0 !important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm) !important;border-top-left-radius:var(--bs-border-radius-sm) !important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg) !important;border-top-left-radius:var(--bs-border-radius-lg) !important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl) !important;border-top-left-radius:var(--bs-border-radius-xl) !important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl) !important;border-top-left-radius:var(--bs-border-radius-xxl) !important}.rounded-start-circle{border-bottom-left-radius:50% !important;border-top-left-radius:50% !important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill) !important;border-top-left-radius:var(--bs-border-radius-pill) !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}.z-n1{z-index:-1 !important}.z-0{z-index:0 !important}.z-1{z-index:1 !important}.z-2{z-index:2 !important}.z-3{z-index:3 !important}@media(min-width: 576px){.float-sm-start{float:left !important}.float-sm-end{float:right !important}.float-sm-none{float:none !important}.object-fit-sm-contain{object-fit:contain !important}.object-fit-sm-cover{object-fit:cover !important}.object-fit-sm-fill{object-fit:fill !important}.object-fit-sm-scale{object-fit:scale-down !important}.object-fit-sm-none{object-fit:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-grid{display:grid !important}.d-sm-inline-grid{display:inline-grid !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:flex !important}.d-sm-inline-flex{display:inline-flex !important}.d-sm-none{display:none !important}.flex-sm-fill{flex:1 1 auto !important}.flex-sm-row{flex-direction:row !important}.flex-sm-column{flex-direction:column !important}.flex-sm-row-reverse{flex-direction:row-reverse !important}.flex-sm-column-reverse{flex-direction:column-reverse !important}.flex-sm-grow-0{flex-grow:0 !important}.flex-sm-grow-1{flex-grow:1 !important}.flex-sm-shrink-0{flex-shrink:0 !important}.flex-sm-shrink-1{flex-shrink:1 !important}.flex-sm-wrap{flex-wrap:wrap !important}.flex-sm-nowrap{flex-wrap:nowrap !important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-sm-start{justify-content:flex-start !important}.justify-content-sm-end{justify-content:flex-end !important}.justify-content-sm-center{justify-content:center !important}.justify-content-sm-between{justify-content:space-between !important}.justify-content-sm-around{justify-content:space-around !important}.justify-content-sm-evenly{justify-content:space-evenly !important}.align-items-sm-start{align-items:flex-start !important}.align-items-sm-end{align-items:flex-end !important}.align-items-sm-center{align-items:center !important}.align-items-sm-baseline{align-items:baseline !important}.align-items-sm-stretch{align-items:stretch !important}.align-content-sm-start{align-content:flex-start !important}.align-content-sm-end{align-content:flex-end !important}.align-content-sm-center{align-content:center !important}.align-content-sm-between{align-content:space-between !important}.align-content-sm-around{align-content:space-around !important}.align-content-sm-stretch{align-content:stretch !important}.align-self-sm-auto{align-self:auto !important}.align-self-sm-start{align-self:flex-start !important}.align-self-sm-end{align-self:flex-end !important}.align-self-sm-center{align-self:center !important}.align-self-sm-baseline{align-self:baseline !important}.align-self-sm-stretch{align-self:stretch !important}.order-sm-first{order:-1 !important}.order-sm-0{order:0 !important}.order-sm-1{order:1 !important}.order-sm-2{order:2 !important}.order-sm-3{order:3 !important}.order-sm-4{order:4 !important}.order-sm-5{order:5 !important}.order-sm-last{order:6 !important}.m-sm-0{margin:0 !important}.m-sm-1{margin:.25rem !important}.m-sm-2{margin:.5rem !important}.m-sm-3{margin:1rem !important}.m-sm-4{margin:1.5rem !important}.m-sm-5{margin:3rem !important}.m-sm-auto{margin:auto !important}.mx-sm-0{margin-right:0 !important;margin-left:0 !important}.mx-sm-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-sm-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-sm-3{margin-right:1rem !important;margin-left:1rem !important}.mx-sm-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-sm-5{margin-right:3rem !important;margin-left:3rem !important}.mx-sm-auto{margin-right:auto !important;margin-left:auto !important}.my-sm-0{margin-top:0 !important;margin-bottom:0 !important}.my-sm-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-sm-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-sm-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-sm-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-sm-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-sm-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-sm-0{margin-top:0 !important}.mt-sm-1{margin-top:.25rem !important}.mt-sm-2{margin-top:.5rem !important}.mt-sm-3{margin-top:1rem !important}.mt-sm-4{margin-top:1.5rem !important}.mt-sm-5{margin-top:3rem !important}.mt-sm-auto{margin-top:auto !important}.me-sm-0{margin-right:0 !important}.me-sm-1{margin-right:.25rem !important}.me-sm-2{margin-right:.5rem !important}.me-sm-3{margin-right:1rem !important}.me-sm-4{margin-right:1.5rem !important}.me-sm-5{margin-right:3rem !important}.me-sm-auto{margin-right:auto !important}.mb-sm-0{margin-bottom:0 !important}.mb-sm-1{margin-bottom:.25rem !important}.mb-sm-2{margin-bottom:.5rem !important}.mb-sm-3{margin-bottom:1rem !important}.mb-sm-4{margin-bottom:1.5rem !important}.mb-sm-5{margin-bottom:3rem !important}.mb-sm-auto{margin-bottom:auto !important}.ms-sm-0{margin-left:0 !important}.ms-sm-1{margin-left:.25rem !important}.ms-sm-2{margin-left:.5rem !important}.ms-sm-3{margin-left:1rem !important}.ms-sm-4{margin-left:1.5rem !important}.ms-sm-5{margin-left:3rem !important}.ms-sm-auto{margin-left:auto !important}.p-sm-0{padding:0 !important}.p-sm-1{padding:.25rem !important}.p-sm-2{padding:.5rem !important}.p-sm-3{padding:1rem !important}.p-sm-4{padding:1.5rem !important}.p-sm-5{padding:3rem !important}.px-sm-0{padding-right:0 !important;padding-left:0 !important}.px-sm-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-sm-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-sm-3{padding-right:1rem !important;padding-left:1rem !important}.px-sm-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-sm-5{padding-right:3rem !important;padding-left:3rem !important}.py-sm-0{padding-top:0 !important;padding-bottom:0 !important}.py-sm-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-sm-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-sm-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-sm-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-sm-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-sm-0{padding-top:0 !important}.pt-sm-1{padding-top:.25rem !important}.pt-sm-2{padding-top:.5rem !important}.pt-sm-3{padding-top:1rem !important}.pt-sm-4{padding-top:1.5rem !important}.pt-sm-5{padding-top:3rem !important}.pe-sm-0{padding-right:0 !important}.pe-sm-1{padding-right:.25rem !important}.pe-sm-2{padding-right:.5rem !important}.pe-sm-3{padding-right:1rem !important}.pe-sm-4{padding-right:1.5rem !important}.pe-sm-5{padding-right:3rem !important}.pb-sm-0{padding-bottom:0 !important}.pb-sm-1{padding-bottom:.25rem !important}.pb-sm-2{padding-bottom:.5rem !important}.pb-sm-3{padding-bottom:1rem !important}.pb-sm-4{padding-bottom:1.5rem !important}.pb-sm-5{padding-bottom:3rem !important}.ps-sm-0{padding-left:0 !important}.ps-sm-1{padding-left:.25rem !important}.ps-sm-2{padding-left:.5rem !important}.ps-sm-3{padding-left:1rem !important}.ps-sm-4{padding-left:1.5rem !important}.ps-sm-5{padding-left:3rem !important}.gap-sm-0{gap:0 !important}.gap-sm-1{gap:.25rem !important}.gap-sm-2{gap:.5rem !important}.gap-sm-3{gap:1rem !important}.gap-sm-4{gap:1.5rem !important}.gap-sm-5{gap:3rem !important}.row-gap-sm-0{row-gap:0 !important}.row-gap-sm-1{row-gap:.25rem !important}.row-gap-sm-2{row-gap:.5rem !important}.row-gap-sm-3{row-gap:1rem !important}.row-gap-sm-4{row-gap:1.5rem !important}.row-gap-sm-5{row-gap:3rem !important}.column-gap-sm-0{column-gap:0 !important}.column-gap-sm-1{column-gap:.25rem !important}.column-gap-sm-2{column-gap:.5rem !important}.column-gap-sm-3{column-gap:1rem !important}.column-gap-sm-4{column-gap:1.5rem !important}.column-gap-sm-5{column-gap:3rem !important}.text-sm-start{text-align:left !important}.text-sm-end{text-align:right !important}.text-sm-center{text-align:center !important}}@media(min-width: 768px){.float-md-start{float:left !important}.float-md-end{float:right !important}.float-md-none{float:none !important}.object-fit-md-contain{object-fit:contain !important}.object-fit-md-cover{object-fit:cover !important}.object-fit-md-fill{object-fit:fill !important}.object-fit-md-scale{object-fit:scale-down !important}.object-fit-md-none{object-fit:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-grid{display:grid !important}.d-md-inline-grid{display:inline-grid !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:flex !important}.d-md-inline-flex{display:inline-flex !important}.d-md-none{display:none !important}.flex-md-fill{flex:1 1 auto !important}.flex-md-row{flex-direction:row !important}.flex-md-column{flex-direction:column !important}.flex-md-row-reverse{flex-direction:row-reverse !important}.flex-md-column-reverse{flex-direction:column-reverse !important}.flex-md-grow-0{flex-grow:0 !important}.flex-md-grow-1{flex-grow:1 !important}.flex-md-shrink-0{flex-shrink:0 !important}.flex-md-shrink-1{flex-shrink:1 !important}.flex-md-wrap{flex-wrap:wrap !important}.flex-md-nowrap{flex-wrap:nowrap !important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-md-start{justify-content:flex-start !important}.justify-content-md-end{justify-content:flex-end !important}.justify-content-md-center{justify-content:center !important}.justify-content-md-between{justify-content:space-between !important}.justify-content-md-around{justify-content:space-around !important}.justify-content-md-evenly{justify-content:space-evenly !important}.align-items-md-start{align-items:flex-start !important}.align-items-md-end{align-items:flex-end !important}.align-items-md-center{align-items:center !important}.align-items-md-baseline{align-items:baseline !important}.align-items-md-stretch{align-items:stretch !important}.align-content-md-start{align-content:flex-start !important}.align-content-md-end{align-content:flex-end !important}.align-content-md-center{align-content:center !important}.align-content-md-between{align-content:space-between !important}.align-content-md-around{align-content:space-around !important}.align-content-md-stretch{align-content:stretch !important}.align-self-md-auto{align-self:auto !important}.align-self-md-start{align-self:flex-start !important}.align-self-md-end{align-self:flex-end !important}.align-self-md-center{align-self:center !important}.align-self-md-baseline{align-self:baseline !important}.align-self-md-stretch{align-self:stretch !important}.order-md-first{order:-1 !important}.order-md-0{order:0 !important}.order-md-1{order:1 !important}.order-md-2{order:2 !important}.order-md-3{order:3 !important}.order-md-4{order:4 !important}.order-md-5{order:5 !important}.order-md-last{order:6 !important}.m-md-0{margin:0 !important}.m-md-1{margin:.25rem !important}.m-md-2{margin:.5rem !important}.m-md-3{margin:1rem !important}.m-md-4{margin:1.5rem !important}.m-md-5{margin:3rem !important}.m-md-auto{margin:auto !important}.mx-md-0{margin-right:0 !important;margin-left:0 !important}.mx-md-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-md-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-md-3{margin-right:1rem !important;margin-left:1rem !important}.mx-md-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-md-5{margin-right:3rem !important;margin-left:3rem !important}.mx-md-auto{margin-right:auto !important;margin-left:auto !important}.my-md-0{margin-top:0 !important;margin-bottom:0 !important}.my-md-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-md-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-md-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-md-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-md-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-md-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-md-0{margin-top:0 !important}.mt-md-1{margin-top:.25rem !important}.mt-md-2{margin-top:.5rem !important}.mt-md-3{margin-top:1rem !important}.mt-md-4{margin-top:1.5rem !important}.mt-md-5{margin-top:3rem !important}.mt-md-auto{margin-top:auto !important}.me-md-0{margin-right:0 !important}.me-md-1{margin-right:.25rem !important}.me-md-2{margin-right:.5rem !important}.me-md-3{margin-right:1rem !important}.me-md-4{margin-right:1.5rem !important}.me-md-5{margin-right:3rem !important}.me-md-auto{margin-right:auto !important}.mb-md-0{margin-bottom:0 !important}.mb-md-1{margin-bottom:.25rem !important}.mb-md-2{margin-bottom:.5rem !important}.mb-md-3{margin-bottom:1rem !important}.mb-md-4{margin-bottom:1.5rem !important}.mb-md-5{margin-bottom:3rem !important}.mb-md-auto{margin-bottom:auto !important}.ms-md-0{margin-left:0 !important}.ms-md-1{margin-left:.25rem !important}.ms-md-2{margin-left:.5rem !important}.ms-md-3{margin-left:1rem !important}.ms-md-4{margin-left:1.5rem !important}.ms-md-5{margin-left:3rem !important}.ms-md-auto{margin-left:auto !important}.p-md-0{padding:0 !important}.p-md-1{padding:.25rem !important}.p-md-2{padding:.5rem !important}.p-md-3{padding:1rem !important}.p-md-4{padding:1.5rem !important}.p-md-5{padding:3rem !important}.px-md-0{padding-right:0 !important;padding-left:0 !important}.px-md-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-md-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-md-3{padding-right:1rem !important;padding-left:1rem !important}.px-md-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-md-5{padding-right:3rem !important;padding-left:3rem !important}.py-md-0{padding-top:0 !important;padding-bottom:0 !important}.py-md-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-md-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-md-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-md-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-md-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-md-0{padding-top:0 !important}.pt-md-1{padding-top:.25rem !important}.pt-md-2{padding-top:.5rem !important}.pt-md-3{padding-top:1rem !important}.pt-md-4{padding-top:1.5rem !important}.pt-md-5{padding-top:3rem !important}.pe-md-0{padding-right:0 !important}.pe-md-1{padding-right:.25rem !important}.pe-md-2{padding-right:.5rem !important}.pe-md-3{padding-right:1rem !important}.pe-md-4{padding-right:1.5rem !important}.pe-md-5{padding-right:3rem !important}.pb-md-0{padding-bottom:0 !important}.pb-md-1{padding-bottom:.25rem !important}.pb-md-2{padding-bottom:.5rem !important}.pb-md-3{padding-bottom:1rem !important}.pb-md-4{padding-bottom:1.5rem !important}.pb-md-5{padding-bottom:3rem !important}.ps-md-0{padding-left:0 !important}.ps-md-1{padding-left:.25rem !important}.ps-md-2{padding-left:.5rem !important}.ps-md-3{padding-left:1rem !important}.ps-md-4{padding-left:1.5rem !important}.ps-md-5{padding-left:3rem !important}.gap-md-0{gap:0 !important}.gap-md-1{gap:.25rem !important}.gap-md-2{gap:.5rem !important}.gap-md-3{gap:1rem !important}.gap-md-4{gap:1.5rem !important}.gap-md-5{gap:3rem !important}.row-gap-md-0{row-gap:0 !important}.row-gap-md-1{row-gap:.25rem !important}.row-gap-md-2{row-gap:.5rem !important}.row-gap-md-3{row-gap:1rem !important}.row-gap-md-4{row-gap:1.5rem !important}.row-gap-md-5{row-gap:3rem !important}.column-gap-md-0{column-gap:0 !important}.column-gap-md-1{column-gap:.25rem !important}.column-gap-md-2{column-gap:.5rem !important}.column-gap-md-3{column-gap:1rem !important}.column-gap-md-4{column-gap:1.5rem !important}.column-gap-md-5{column-gap:3rem !important}.text-md-start{text-align:left !important}.text-md-end{text-align:right !important}.text-md-center{text-align:center !important}}@media(min-width: 992px){.float-lg-start{float:left !important}.float-lg-end{float:right !important}.float-lg-none{float:none !important}.object-fit-lg-contain{object-fit:contain !important}.object-fit-lg-cover{object-fit:cover !important}.object-fit-lg-fill{object-fit:fill !important}.object-fit-lg-scale{object-fit:scale-down !important}.object-fit-lg-none{object-fit:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-grid{display:grid !important}.d-lg-inline-grid{display:inline-grid !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:flex !important}.d-lg-inline-flex{display:inline-flex !important}.d-lg-none{display:none !important}.flex-lg-fill{flex:1 1 auto !important}.flex-lg-row{flex-direction:row !important}.flex-lg-column{flex-direction:column !important}.flex-lg-row-reverse{flex-direction:row-reverse !important}.flex-lg-column-reverse{flex-direction:column-reverse !important}.flex-lg-grow-0{flex-grow:0 !important}.flex-lg-grow-1{flex-grow:1 !important}.flex-lg-shrink-0{flex-shrink:0 !important}.flex-lg-shrink-1{flex-shrink:1 !important}.flex-lg-wrap{flex-wrap:wrap !important}.flex-lg-nowrap{flex-wrap:nowrap !important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-lg-start{justify-content:flex-start !important}.justify-content-lg-end{justify-content:flex-end !important}.justify-content-lg-center{justify-content:center !important}.justify-content-lg-between{justify-content:space-between !important}.justify-content-lg-around{justify-content:space-around !important}.justify-content-lg-evenly{justify-content:space-evenly !important}.align-items-lg-start{align-items:flex-start !important}.align-items-lg-end{align-items:flex-end !important}.align-items-lg-center{align-items:center !important}.align-items-lg-baseline{align-items:baseline !important}.align-items-lg-stretch{align-items:stretch !important}.align-content-lg-start{align-content:flex-start !important}.align-content-lg-end{align-content:flex-end !important}.align-content-lg-center{align-content:center !important}.align-content-lg-between{align-content:space-between !important}.align-content-lg-around{align-content:space-around !important}.align-content-lg-stretch{align-content:stretch !important}.align-self-lg-auto{align-self:auto !important}.align-self-lg-start{align-self:flex-start !important}.align-self-lg-end{align-self:flex-end !important}.align-self-lg-center{align-self:center !important}.align-self-lg-baseline{align-self:baseline !important}.align-self-lg-stretch{align-self:stretch !important}.order-lg-first{order:-1 !important}.order-lg-0{order:0 !important}.order-lg-1{order:1 !important}.order-lg-2{order:2 !important}.order-lg-3{order:3 !important}.order-lg-4{order:4 !important}.order-lg-5{order:5 !important}.order-lg-last{order:6 !important}.m-lg-0{margin:0 !important}.m-lg-1{margin:.25rem !important}.m-lg-2{margin:.5rem !important}.m-lg-3{margin:1rem !important}.m-lg-4{margin:1.5rem !important}.m-lg-5{margin:3rem !important}.m-lg-auto{margin:auto !important}.mx-lg-0{margin-right:0 !important;margin-left:0 !important}.mx-lg-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-lg-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-lg-3{margin-right:1rem !important;margin-left:1rem !important}.mx-lg-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-lg-5{margin-right:3rem !important;margin-left:3rem !important}.mx-lg-auto{margin-right:auto !important;margin-left:auto !important}.my-lg-0{margin-top:0 !important;margin-bottom:0 !important}.my-lg-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-lg-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-lg-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-lg-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-lg-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-lg-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-lg-0{margin-top:0 !important}.mt-lg-1{margin-top:.25rem !important}.mt-lg-2{margin-top:.5rem !important}.mt-lg-3{margin-top:1rem !important}.mt-lg-4{margin-top:1.5rem !important}.mt-lg-5{margin-top:3rem !important}.mt-lg-auto{margin-top:auto !important}.me-lg-0{margin-right:0 !important}.me-lg-1{margin-right:.25rem !important}.me-lg-2{margin-right:.5rem !important}.me-lg-3{margin-right:1rem !important}.me-lg-4{margin-right:1.5rem !important}.me-lg-5{margin-right:3rem !important}.me-lg-auto{margin-right:auto !important}.mb-lg-0{margin-bottom:0 !important}.mb-lg-1{margin-bottom:.25rem !important}.mb-lg-2{margin-bottom:.5rem !important}.mb-lg-3{margin-bottom:1rem !important}.mb-lg-4{margin-bottom:1.5rem !important}.mb-lg-5{margin-bottom:3rem !important}.mb-lg-auto{margin-bottom:auto !important}.ms-lg-0{margin-left:0 !important}.ms-lg-1{margin-left:.25rem !important}.ms-lg-2{margin-left:.5rem !important}.ms-lg-3{margin-left:1rem !important}.ms-lg-4{margin-left:1.5rem !important}.ms-lg-5{margin-left:3rem !important}.ms-lg-auto{margin-left:auto !important}.p-lg-0{padding:0 !important}.p-lg-1{padding:.25rem !important}.p-lg-2{padding:.5rem !important}.p-lg-3{padding:1rem !important}.p-lg-4{padding:1.5rem !important}.p-lg-5{padding:3rem !important}.px-lg-0{padding-right:0 !important;padding-left:0 !important}.px-lg-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-lg-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-lg-3{padding-right:1rem !important;padding-left:1rem !important}.px-lg-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-lg-5{padding-right:3rem !important;padding-left:3rem !important}.py-lg-0{padding-top:0 !important;padding-bottom:0 !important}.py-lg-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-lg-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-lg-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-lg-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-lg-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-lg-0{padding-top:0 !important}.pt-lg-1{padding-top:.25rem !important}.pt-lg-2{padding-top:.5rem !important}.pt-lg-3{padding-top:1rem !important}.pt-lg-4{padding-top:1.5rem !important}.pt-lg-5{padding-top:3rem !important}.pe-lg-0{padding-right:0 !important}.pe-lg-1{padding-right:.25rem !important}.pe-lg-2{padding-right:.5rem !important}.pe-lg-3{padding-right:1rem !important}.pe-lg-4{padding-right:1.5rem !important}.pe-lg-5{padding-right:3rem !important}.pb-lg-0{padding-bottom:0 !important}.pb-lg-1{padding-bottom:.25rem !important}.pb-lg-2{padding-bottom:.5rem !important}.pb-lg-3{padding-bottom:1rem !important}.pb-lg-4{padding-bottom:1.5rem !important}.pb-lg-5{padding-bottom:3rem !important}.ps-lg-0{padding-left:0 !important}.ps-lg-1{padding-left:.25rem !important}.ps-lg-2{padding-left:.5rem !important}.ps-lg-3{padding-left:1rem !important}.ps-lg-4{padding-left:1.5rem !important}.ps-lg-5{padding-left:3rem !important}.gap-lg-0{gap:0 !important}.gap-lg-1{gap:.25rem !important}.gap-lg-2{gap:.5rem !important}.gap-lg-3{gap:1rem !important}.gap-lg-4{gap:1.5rem !important}.gap-lg-5{gap:3rem !important}.row-gap-lg-0{row-gap:0 !important}.row-gap-lg-1{row-gap:.25rem !important}.row-gap-lg-2{row-gap:.5rem !important}.row-gap-lg-3{row-gap:1rem !important}.row-gap-lg-4{row-gap:1.5rem !important}.row-gap-lg-5{row-gap:3rem !important}.column-gap-lg-0{column-gap:0 !important}.column-gap-lg-1{column-gap:.25rem !important}.column-gap-lg-2{column-gap:.5rem !important}.column-gap-lg-3{column-gap:1rem !important}.column-gap-lg-4{column-gap:1.5rem !important}.column-gap-lg-5{column-gap:3rem !important}.text-lg-start{text-align:left !important}.text-lg-end{text-align:right !important}.text-lg-center{text-align:center !important}}@media(min-width: 1200px){.float-xl-start{float:left !important}.float-xl-end{float:right !important}.float-xl-none{float:none !important}.object-fit-xl-contain{object-fit:contain !important}.object-fit-xl-cover{object-fit:cover !important}.object-fit-xl-fill{object-fit:fill !important}.object-fit-xl-scale{object-fit:scale-down !important}.object-fit-xl-none{object-fit:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-grid{display:grid !important}.d-xl-inline-grid{display:inline-grid !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:flex !important}.d-xl-inline-flex{display:inline-flex !important}.d-xl-none{display:none !important}.flex-xl-fill{flex:1 1 auto !important}.flex-xl-row{flex-direction:row !important}.flex-xl-column{flex-direction:column !important}.flex-xl-row-reverse{flex-direction:row-reverse !important}.flex-xl-column-reverse{flex-direction:column-reverse !important}.flex-xl-grow-0{flex-grow:0 !important}.flex-xl-grow-1{flex-grow:1 !important}.flex-xl-shrink-0{flex-shrink:0 !important}.flex-xl-shrink-1{flex-shrink:1 !important}.flex-xl-wrap{flex-wrap:wrap !important}.flex-xl-nowrap{flex-wrap:nowrap !important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-xl-start{justify-content:flex-start !important}.justify-content-xl-end{justify-content:flex-end !important}.justify-content-xl-center{justify-content:center !important}.justify-content-xl-between{justify-content:space-between !important}.justify-content-xl-around{justify-content:space-around !important}.justify-content-xl-evenly{justify-content:space-evenly !important}.align-items-xl-start{align-items:flex-start !important}.align-items-xl-end{align-items:flex-end !important}.align-items-xl-center{align-items:center !important}.align-items-xl-baseline{align-items:baseline !important}.align-items-xl-stretch{align-items:stretch !important}.align-content-xl-start{align-content:flex-start !important}.align-content-xl-end{align-content:flex-end !important}.align-content-xl-center{align-content:center !important}.align-content-xl-between{align-content:space-between !important}.align-content-xl-around{align-content:space-around !important}.align-content-xl-stretch{align-content:stretch !important}.align-self-xl-auto{align-self:auto !important}.align-self-xl-start{align-self:flex-start !important}.align-self-xl-end{align-self:flex-end !important}.align-self-xl-center{align-self:center !important}.align-self-xl-baseline{align-self:baseline !important}.align-self-xl-stretch{align-self:stretch !important}.order-xl-first{order:-1 !important}.order-xl-0{order:0 !important}.order-xl-1{order:1 !important}.order-xl-2{order:2 !important}.order-xl-3{order:3 !important}.order-xl-4{order:4 !important}.order-xl-5{order:5 !important}.order-xl-last{order:6 !important}.m-xl-0{margin:0 !important}.m-xl-1{margin:.25rem !important}.m-xl-2{margin:.5rem !important}.m-xl-3{margin:1rem !important}.m-xl-4{margin:1.5rem !important}.m-xl-5{margin:3rem !important}.m-xl-auto{margin:auto !important}.mx-xl-0{margin-right:0 !important;margin-left:0 !important}.mx-xl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xl-auto{margin-right:auto !important;margin-left:auto !important}.my-xl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xl-0{margin-top:0 !important}.mt-xl-1{margin-top:.25rem !important}.mt-xl-2{margin-top:.5rem !important}.mt-xl-3{margin-top:1rem !important}.mt-xl-4{margin-top:1.5rem !important}.mt-xl-5{margin-top:3rem !important}.mt-xl-auto{margin-top:auto !important}.me-xl-0{margin-right:0 !important}.me-xl-1{margin-right:.25rem !important}.me-xl-2{margin-right:.5rem !important}.me-xl-3{margin-right:1rem !important}.me-xl-4{margin-right:1.5rem !important}.me-xl-5{margin-right:3rem !important}.me-xl-auto{margin-right:auto !important}.mb-xl-0{margin-bottom:0 !important}.mb-xl-1{margin-bottom:.25rem !important}.mb-xl-2{margin-bottom:.5rem !important}.mb-xl-3{margin-bottom:1rem !important}.mb-xl-4{margin-bottom:1.5rem !important}.mb-xl-5{margin-bottom:3rem !important}.mb-xl-auto{margin-bottom:auto !important}.ms-xl-0{margin-left:0 !important}.ms-xl-1{margin-left:.25rem !important}.ms-xl-2{margin-left:.5rem !important}.ms-xl-3{margin-left:1rem !important}.ms-xl-4{margin-left:1.5rem !important}.ms-xl-5{margin-left:3rem !important}.ms-xl-auto{margin-left:auto !important}.p-xl-0{padding:0 !important}.p-xl-1{padding:.25rem !important}.p-xl-2{padding:.5rem !important}.p-xl-3{padding:1rem !important}.p-xl-4{padding:1.5rem !important}.p-xl-5{padding:3rem !important}.px-xl-0{padding-right:0 !important;padding-left:0 !important}.px-xl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xl-0{padding-top:0 !important}.pt-xl-1{padding-top:.25rem !important}.pt-xl-2{padding-top:.5rem !important}.pt-xl-3{padding-top:1rem !important}.pt-xl-4{padding-top:1.5rem !important}.pt-xl-5{padding-top:3rem !important}.pe-xl-0{padding-right:0 !important}.pe-xl-1{padding-right:.25rem !important}.pe-xl-2{padding-right:.5rem !important}.pe-xl-3{padding-right:1rem !important}.pe-xl-4{padding-right:1.5rem !important}.pe-xl-5{padding-right:3rem !important}.pb-xl-0{padding-bottom:0 !important}.pb-xl-1{padding-bottom:.25rem !important}.pb-xl-2{padding-bottom:.5rem !important}.pb-xl-3{padding-bottom:1rem !important}.pb-xl-4{padding-bottom:1.5rem !important}.pb-xl-5{padding-bottom:3rem !important}.ps-xl-0{padding-left:0 !important}.ps-xl-1{padding-left:.25rem !important}.ps-xl-2{padding-left:.5rem !important}.ps-xl-3{padding-left:1rem !important}.ps-xl-4{padding-left:1.5rem !important}.ps-xl-5{padding-left:3rem !important}.gap-xl-0{gap:0 !important}.gap-xl-1{gap:.25rem !important}.gap-xl-2{gap:.5rem !important}.gap-xl-3{gap:1rem !important}.gap-xl-4{gap:1.5rem !important}.gap-xl-5{gap:3rem !important}.row-gap-xl-0{row-gap:0 !important}.row-gap-xl-1{row-gap:.25rem !important}.row-gap-xl-2{row-gap:.5rem !important}.row-gap-xl-3{row-gap:1rem !important}.row-gap-xl-4{row-gap:1.5rem !important}.row-gap-xl-5{row-gap:3rem !important}.column-gap-xl-0{column-gap:0 !important}.column-gap-xl-1{column-gap:.25rem !important}.column-gap-xl-2{column-gap:.5rem !important}.column-gap-xl-3{column-gap:1rem !important}.column-gap-xl-4{column-gap:1.5rem !important}.column-gap-xl-5{column-gap:3rem !important}.text-xl-start{text-align:left !important}.text-xl-end{text-align:right !important}.text-xl-center{text-align:center !important}}@media(min-width: 1400px){.float-xxl-start{float:left !important}.float-xxl-end{float:right !important}.float-xxl-none{float:none !important}.object-fit-xxl-contain{object-fit:contain !important}.object-fit-xxl-cover{object-fit:cover !important}.object-fit-xxl-fill{object-fit:fill !important}.object-fit-xxl-scale{object-fit:scale-down !important}.object-fit-xxl-none{object-fit:none !important}.d-xxl-inline{display:inline !important}.d-xxl-inline-block{display:inline-block !important}.d-xxl-block{display:block !important}.d-xxl-grid{display:grid !important}.d-xxl-inline-grid{display:inline-grid !important}.d-xxl-table{display:table !important}.d-xxl-table-row{display:table-row !important}.d-xxl-table-cell{display:table-cell !important}.d-xxl-flex{display:flex !important}.d-xxl-inline-flex{display:inline-flex !important}.d-xxl-none{display:none !important}.flex-xxl-fill{flex:1 1 auto !important}.flex-xxl-row{flex-direction:row !important}.flex-xxl-column{flex-direction:column !important}.flex-xxl-row-reverse{flex-direction:row-reverse !important}.flex-xxl-column-reverse{flex-direction:column-reverse !important}.flex-xxl-grow-0{flex-grow:0 !important}.flex-xxl-grow-1{flex-grow:1 !important}.flex-xxl-shrink-0{flex-shrink:0 !important}.flex-xxl-shrink-1{flex-shrink:1 !important}.flex-xxl-wrap{flex-wrap:wrap !important}.flex-xxl-nowrap{flex-wrap:nowrap !important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse !important}.justify-content-xxl-start{justify-content:flex-start !important}.justify-content-xxl-end{justify-content:flex-end !important}.justify-content-xxl-center{justify-content:center !important}.justify-content-xxl-between{justify-content:space-between !important}.justify-content-xxl-around{justify-content:space-around !important}.justify-content-xxl-evenly{justify-content:space-evenly !important}.align-items-xxl-start{align-items:flex-start !important}.align-items-xxl-end{align-items:flex-end !important}.align-items-xxl-center{align-items:center !important}.align-items-xxl-baseline{align-items:baseline !important}.align-items-xxl-stretch{align-items:stretch !important}.align-content-xxl-start{align-content:flex-start !important}.align-content-xxl-end{align-content:flex-end !important}.align-content-xxl-center{align-content:center !important}.align-content-xxl-between{align-content:space-between !important}.align-content-xxl-around{align-content:space-around !important}.align-content-xxl-stretch{align-content:stretch !important}.align-self-xxl-auto{align-self:auto !important}.align-self-xxl-start{align-self:flex-start !important}.align-self-xxl-end{align-self:flex-end !important}.align-self-xxl-center{align-self:center !important}.align-self-xxl-baseline{align-self:baseline !important}.align-self-xxl-stretch{align-self:stretch !important}.order-xxl-first{order:-1 !important}.order-xxl-0{order:0 !important}.order-xxl-1{order:1 !important}.order-xxl-2{order:2 !important}.order-xxl-3{order:3 !important}.order-xxl-4{order:4 !important}.order-xxl-5{order:5 !important}.order-xxl-last{order:6 !important}.m-xxl-0{margin:0 !important}.m-xxl-1{margin:.25rem !important}.m-xxl-2{margin:.5rem !important}.m-xxl-3{margin:1rem !important}.m-xxl-4{margin:1.5rem !important}.m-xxl-5{margin:3rem !important}.m-xxl-auto{margin:auto !important}.mx-xxl-0{margin-right:0 !important;margin-left:0 !important}.mx-xxl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xxl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xxl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xxl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xxl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xxl-auto{margin-right:auto !important;margin-left:auto !important}.my-xxl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xxl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xxl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xxl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xxl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xxl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xxl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xxl-0{margin-top:0 !important}.mt-xxl-1{margin-top:.25rem !important}.mt-xxl-2{margin-top:.5rem !important}.mt-xxl-3{margin-top:1rem !important}.mt-xxl-4{margin-top:1.5rem !important}.mt-xxl-5{margin-top:3rem !important}.mt-xxl-auto{margin-top:auto !important}.me-xxl-0{margin-right:0 !important}.me-xxl-1{margin-right:.25rem !important}.me-xxl-2{margin-right:.5rem !important}.me-xxl-3{margin-right:1rem !important}.me-xxl-4{margin-right:1.5rem !important}.me-xxl-5{margin-right:3rem !important}.me-xxl-auto{margin-right:auto !important}.mb-xxl-0{margin-bottom:0 !important}.mb-xxl-1{margin-bottom:.25rem !important}.mb-xxl-2{margin-bottom:.5rem !important}.mb-xxl-3{margin-bottom:1rem !important}.mb-xxl-4{margin-bottom:1.5rem !important}.mb-xxl-5{margin-bottom:3rem !important}.mb-xxl-auto{margin-bottom:auto !important}.ms-xxl-0{margin-left:0 !important}.ms-xxl-1{margin-left:.25rem !important}.ms-xxl-2{margin-left:.5rem !important}.ms-xxl-3{margin-left:1rem !important}.ms-xxl-4{margin-left:1.5rem !important}.ms-xxl-5{margin-left:3rem !important}.ms-xxl-auto{margin-left:auto !important}.p-xxl-0{padding:0 !important}.p-xxl-1{padding:.25rem !important}.p-xxl-2{padding:.5rem !important}.p-xxl-3{padding:1rem !important}.p-xxl-4{padding:1.5rem !important}.p-xxl-5{padding:3rem !important}.px-xxl-0{padding-right:0 !important;padding-left:0 !important}.px-xxl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xxl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xxl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xxl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xxl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xxl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xxl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xxl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xxl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xxl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xxl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xxl-0{padding-top:0 !important}.pt-xxl-1{padding-top:.25rem !important}.pt-xxl-2{padding-top:.5rem !important}.pt-xxl-3{padding-top:1rem !important}.pt-xxl-4{padding-top:1.5rem !important}.pt-xxl-5{padding-top:3rem !important}.pe-xxl-0{padding-right:0 !important}.pe-xxl-1{padding-right:.25rem !important}.pe-xxl-2{padding-right:.5rem !important}.pe-xxl-3{padding-right:1rem !important}.pe-xxl-4{padding-right:1.5rem !important}.pe-xxl-5{padding-right:3rem !important}.pb-xxl-0{padding-bottom:0 !important}.pb-xxl-1{padding-bottom:.25rem !important}.pb-xxl-2{padding-bottom:.5rem !important}.pb-xxl-3{padding-bottom:1rem !important}.pb-xxl-4{padding-bottom:1.5rem !important}.pb-xxl-5{padding-bottom:3rem !important}.ps-xxl-0{padding-left:0 !important}.ps-xxl-1{padding-left:.25rem !important}.ps-xxl-2{padding-left:.5rem !important}.ps-xxl-3{padding-left:1rem !important}.ps-xxl-4{padding-left:1.5rem !important}.ps-xxl-5{padding-left:3rem !important}.gap-xxl-0{gap:0 !important}.gap-xxl-1{gap:.25rem !important}.gap-xxl-2{gap:.5rem !important}.gap-xxl-3{gap:1rem !important}.gap-xxl-4{gap:1.5rem !important}.gap-xxl-5{gap:3rem !important}.row-gap-xxl-0{row-gap:0 !important}.row-gap-xxl-1{row-gap:.25rem !important}.row-gap-xxl-2{row-gap:.5rem !important}.row-gap-xxl-3{row-gap:1rem !important}.row-gap-xxl-4{row-gap:1.5rem !important}.row-gap-xxl-5{row-gap:3rem !important}.column-gap-xxl-0{column-gap:0 !important}.column-gap-xxl-1{column-gap:.25rem !important}.column-gap-xxl-2{column-gap:.5rem !important}.column-gap-xxl-3{column-gap:1rem !important}.column-gap-xxl-4{column-gap:1.5rem !important}.column-gap-xxl-5{column-gap:3rem !important}.text-xxl-start{text-align:left !important}.text-xxl-end{text-align:right !important}.text-xxl-center{text-align:center !important}}.bg-default{color:#fff}.bg-primary{color:#fff}.bg-secondary{color:#fff}.bg-success{color:#fff}.bg-info{color:#fff}.bg-warning{color:#fff}.bg-danger{color:#fff}.bg-light{color:#000}.bg-dark{color:#fff}@media(min-width: 1200px){.fs-1{font-size:2rem !important}.fs-2{font-size:1.65rem !important}.fs-3{font-size:1.45rem !important}}@media print{.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-grid{display:grid !important}.d-print-inline-grid{display:inline-grid !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:flex !important}.d-print-inline-flex{display:inline-flex !important}.d-print-none{display:none !important}}.bg-blue{--bslib-color-bg: #2780e3;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-blue{--bslib-color-fg: #2780e3;color:var(--bslib-color-fg)}.bg-indigo{--bslib-color-bg: #6610f2;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-indigo{--bslib-color-fg: #6610f2;color:var(--bslib-color-fg)}.bg-purple{--bslib-color-bg: #613d7c;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-purple{--bslib-color-fg: #613d7c;color:var(--bslib-color-fg)}.bg-pink{--bslib-color-bg: #e83e8c;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-pink{--bslib-color-fg: #e83e8c;color:var(--bslib-color-fg)}.bg-red{--bslib-color-bg: #ff0039;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-red{--bslib-color-fg: #ff0039;color:var(--bslib-color-fg)}.bg-orange{--bslib-color-bg: #f0ad4e;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-orange{--bslib-color-fg: #f0ad4e;color:var(--bslib-color-fg)}.bg-yellow{--bslib-color-bg: #ff7518;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-yellow{--bslib-color-fg: #ff7518;color:var(--bslib-color-fg)}.bg-green{--bslib-color-bg: #3fb618;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-green{--bslib-color-fg: #3fb618;color:var(--bslib-color-fg)}.bg-teal{--bslib-color-bg: #20c997;--bslib-color-fg: #000;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-teal{--bslib-color-fg: #20c997;color:var(--bslib-color-fg)}.bg-cyan{--bslib-color-bg: #9954bb;--bslib-color-fg: #fff;background-color:var(--bslib-color-bg);color:var(--bslib-color-fg)}.text-cyan{--bslib-color-fg: #9954bb;color:var(--bslib-color-fg)}.text-default{--bslib-color-fg: #343a40}.bg-default{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.text-primary{--bslib-color-fg: #2780e3}.bg-primary{--bslib-color-bg: #2780e3;--bslib-color-fg: #fff}.text-secondary{--bslib-color-fg: #343a40}.bg-secondary{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.text-success{--bslib-color-fg: #3fb618}.bg-success{--bslib-color-bg: #3fb618;--bslib-color-fg: #fff}.text-info{--bslib-color-fg: #9954bb}.bg-info{--bslib-color-bg: #9954bb;--bslib-color-fg: #fff}.text-warning{--bslib-color-fg: #ff7518}.bg-warning{--bslib-color-bg: #ff7518;--bslib-color-fg: #fff}.text-danger{--bslib-color-fg: #ff0039}.bg-danger{--bslib-color-bg: #ff0039;--bslib-color-fg: #fff}.text-light{--bslib-color-fg: #f8f9fa}.bg-light{--bslib-color-bg: #f8f9fa;--bslib-color-fg: #000}.text-dark{--bslib-color-fg: #343a40}.bg-dark{--bslib-color-bg: #343a40;--bslib-color-fg: #fff}.bg-gradient-blue-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #4053e9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #4053e9;color:#fff}.bg-gradient-blue-purple{--bslib-color-fg: #fff;--bslib-color-bg: #3e65ba;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #3e65ba;color:#fff}.bg-gradient-blue-pink{--bslib-color-fg: #fff;--bslib-color-bg: #7466c0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #7466c0;color:#fff}.bg-gradient-blue-red{--bslib-color-fg: #fff;--bslib-color-bg: #7d4d9f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #7d4d9f;color:#fff}.bg-gradient-blue-orange{--bslib-color-fg: #fff;--bslib-color-bg: #7792a7;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #7792a7;color:#fff}.bg-gradient-blue-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #7d7c92;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #7d7c92;color:#fff}.bg-gradient-blue-green{--bslib-color-fg: #fff;--bslib-color-bg: #319692;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #319692;color:#fff}.bg-gradient-blue-teal{--bslib-color-fg: #fff;--bslib-color-bg: #249dc5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #249dc5;color:#fff}.bg-gradient-blue-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #556ed3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #2780e3 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #556ed3;color:#fff}.bg-gradient-indigo-blue{--bslib-color-fg: #fff;--bslib-color-bg: #4d3dec;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #4d3dec;color:#fff}.bg-gradient-indigo-purple{--bslib-color-fg: #fff;--bslib-color-bg: #6422c3;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #6422c3;color:#fff}.bg-gradient-indigo-pink{--bslib-color-fg: #fff;--bslib-color-bg: #9a22c9;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #9a22c9;color:#fff}.bg-gradient-indigo-red{--bslib-color-fg: #fff;--bslib-color-bg: #a30aa8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #a30aa8;color:#fff}.bg-gradient-indigo-orange{--bslib-color-fg: #fff;--bslib-color-bg: #9d4fb0;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #9d4fb0;color:#fff}.bg-gradient-indigo-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #a3389b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #a3389b;color:#fff}.bg-gradient-indigo-green{--bslib-color-fg: #fff;--bslib-color-bg: #56529b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #56529b;color:#fff}.bg-gradient-indigo-teal{--bslib-color-fg: #fff;--bslib-color-bg: #4a5ace;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #4a5ace;color:#fff}.bg-gradient-indigo-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #7a2bdc;background:linear-gradient(var(--bg-gradient-deg, 140deg), #6610f2 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #7a2bdc;color:#fff}.bg-gradient-purple-blue{--bslib-color-fg: #fff;--bslib-color-bg: #4a58a5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #4a58a5;color:#fff}.bg-gradient-purple-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #632bab;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #632bab;color:#fff}.bg-gradient-purple-pink{--bslib-color-fg: #fff;--bslib-color-bg: #973d82;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #973d82;color:#fff}.bg-gradient-purple-red{--bslib-color-fg: #fff;--bslib-color-bg: #a02561;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #a02561;color:#fff}.bg-gradient-purple-orange{--bslib-color-fg: #fff;--bslib-color-bg: #9a6a6a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #9a6a6a;color:#fff}.bg-gradient-purple-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #a05354;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #a05354;color:#fff}.bg-gradient-purple-green{--bslib-color-fg: #fff;--bslib-color-bg: #536d54;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #536d54;color:#fff}.bg-gradient-purple-teal{--bslib-color-fg: #fff;--bslib-color-bg: #477587;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #477587;color:#fff}.bg-gradient-purple-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #774695;background:linear-gradient(var(--bg-gradient-deg, 140deg), #613d7c var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #774695;color:#fff}.bg-gradient-pink-blue{--bslib-color-fg: #fff;--bslib-color-bg: #9b58af;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #9b58af;color:#fff}.bg-gradient-pink-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #b42cb5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #b42cb5;color:#fff}.bg-gradient-pink-purple{--bslib-color-fg: #fff;--bslib-color-bg: #b23e86;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #b23e86;color:#fff}.bg-gradient-pink-red{--bslib-color-fg: #fff;--bslib-color-bg: #f1256b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #f1256b;color:#fff}.bg-gradient-pink-orange{--bslib-color-fg: #fff;--bslib-color-bg: #eb6a73;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #eb6a73;color:#fff}.bg-gradient-pink-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #f1545e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #f1545e;color:#fff}.bg-gradient-pink-green{--bslib-color-fg: #fff;--bslib-color-bg: #a46e5e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #a46e5e;color:#fff}.bg-gradient-pink-teal{--bslib-color-fg: #fff;--bslib-color-bg: #987690;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #987690;color:#fff}.bg-gradient-pink-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #c8479f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #e83e8c var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #c8479f;color:#fff}.bg-gradient-red-blue{--bslib-color-fg: #fff;--bslib-color-bg: #a9337d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #a9337d;color:#fff}.bg-gradient-red-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #c20683;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c20683;color:#fff}.bg-gradient-red-purple{--bslib-color-fg: #fff;--bslib-color-bg: #c01854;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #c01854;color:#fff}.bg-gradient-red-pink{--bslib-color-fg: #fff;--bslib-color-bg: #f6195a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #f6195a;color:#fff}.bg-gradient-red-orange{--bslib-color-fg: #fff;--bslib-color-bg: #f94541;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #f94541;color:#fff}.bg-gradient-red-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #ff2f2c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #ff2f2c;color:#fff}.bg-gradient-red-green{--bslib-color-fg: #fff;--bslib-color-bg: #b2492c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #b2492c;color:#fff}.bg-gradient-red-teal{--bslib-color-fg: #fff;--bslib-color-bg: #a6505f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a6505f;color:#fff}.bg-gradient-red-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #d6226d;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff0039 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #d6226d;color:#fff}.bg-gradient-orange-blue{--bslib-color-fg: #fff;--bslib-color-bg: #a09b8a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #a09b8a;color:#fff}.bg-gradient-orange-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #b96e90;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #b96e90;color:#fff}.bg-gradient-orange-purple{--bslib-color-fg: #fff;--bslib-color-bg: #b78060;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #b78060;color:#fff}.bg-gradient-orange-pink{--bslib-color-fg: #fff;--bslib-color-bg: #ed8167;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #ed8167;color:#fff}.bg-gradient-orange-red{--bslib-color-fg: #fff;--bslib-color-bg: #f66846;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #f66846;color:#fff}.bg-gradient-orange-yellow{--bslib-color-fg: #000;--bslib-color-bg: #f69738;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #f69738;color:#000}.bg-gradient-orange-green{--bslib-color-fg: #000;--bslib-color-bg: #a9b138;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #a9b138;color:#000}.bg-gradient-orange-teal{--bslib-color-fg: #000;--bslib-color-bg: #9db86b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #9db86b;color:#000}.bg-gradient-orange-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #cd897a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #f0ad4e var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #cd897a;color:#fff}.bg-gradient-yellow-blue{--bslib-color-fg: #fff;--bslib-color-bg: #a97969;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #a97969;color:#fff}.bg-gradient-yellow-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #c24d6f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #c24d6f;color:#fff}.bg-gradient-yellow-purple{--bslib-color-fg: #fff;--bslib-color-bg: #c05f40;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #c05f40;color:#fff}.bg-gradient-yellow-pink{--bslib-color-fg: #fff;--bslib-color-bg: #f65f46;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #f65f46;color:#fff}.bg-gradient-yellow-red{--bslib-color-fg: #fff;--bslib-color-bg: #ff4625;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #ff4625;color:#fff}.bg-gradient-yellow-orange{--bslib-color-fg: #000;--bslib-color-bg: #f98b2e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #f98b2e;color:#000}.bg-gradient-yellow-green{--bslib-color-fg: #fff;--bslib-color-bg: #b28f18;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #b28f18;color:#fff}.bg-gradient-yellow-teal{--bslib-color-fg: #fff;--bslib-color-bg: #a6974b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #a6974b;color:#fff}.bg-gradient-yellow-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #d66859;background:linear-gradient(var(--bg-gradient-deg, 140deg), #ff7518 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #d66859;color:#fff}.bg-gradient-green-blue{--bslib-color-fg: #fff;--bslib-color-bg: #35a069;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #35a069;color:#fff}.bg-gradient-green-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #4f746f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #4f746f;color:#fff}.bg-gradient-green-purple{--bslib-color-fg: #fff;--bslib-color-bg: #4d8640;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #4d8640;color:#fff}.bg-gradient-green-pink{--bslib-color-fg: #fff;--bslib-color-bg: #838646;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #838646;color:#fff}.bg-gradient-green-red{--bslib-color-fg: #fff;--bslib-color-bg: #8c6d25;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #8c6d25;color:#fff}.bg-gradient-green-orange{--bslib-color-fg: #000;--bslib-color-bg: #86b22e;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #86b22e;color:#000}.bg-gradient-green-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #8c9c18;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #8c9c18;color:#fff}.bg-gradient-green-teal{--bslib-color-fg: #000;--bslib-color-bg: #33be4b;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #33be4b;color:#000}.bg-gradient-green-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #638f59;background:linear-gradient(var(--bg-gradient-deg, 140deg), #3fb618 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #638f59;color:#fff}.bg-gradient-teal-blue{--bslib-color-fg: #fff;--bslib-color-bg: #23acb5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #23acb5;color:#fff}.bg-gradient-teal-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #3c7fbb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #3c7fbb;color:#fff}.bg-gradient-teal-purple{--bslib-color-fg: #fff;--bslib-color-bg: #3a918c;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #3a918c;color:#fff}.bg-gradient-teal-pink{--bslib-color-fg: #fff;--bslib-color-bg: #709193;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #709193;color:#fff}.bg-gradient-teal-red{--bslib-color-fg: #fff;--bslib-color-bg: #797971;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #797971;color:#fff}.bg-gradient-teal-orange{--bslib-color-fg: #000;--bslib-color-bg: #73be7a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #73be7a;color:#000}.bg-gradient-teal-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #79a764;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #79a764;color:#fff}.bg-gradient-teal-green{--bslib-color-fg: #000;--bslib-color-bg: #2cc164;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #2cc164;color:#000}.bg-gradient-teal-cyan{--bslib-color-fg: #fff;--bslib-color-bg: #509aa5;background:linear-gradient(var(--bg-gradient-deg, 140deg), #20c997 var(--bg-gradient-start, 36%), #9954bb var(--bg-gradient-end, 180%)) #509aa5;color:#fff}.bg-gradient-cyan-blue{--bslib-color-fg: #fff;--bslib-color-bg: #6b66cb;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #2780e3 var(--bg-gradient-end, 180%)) #6b66cb;color:#fff}.bg-gradient-cyan-indigo{--bslib-color-fg: #fff;--bslib-color-bg: #8539d1;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #6610f2 var(--bg-gradient-end, 180%)) #8539d1;color:#fff}.bg-gradient-cyan-purple{--bslib-color-fg: #fff;--bslib-color-bg: #834ba2;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #613d7c var(--bg-gradient-end, 180%)) #834ba2;color:#fff}.bg-gradient-cyan-pink{--bslib-color-fg: #fff;--bslib-color-bg: #b94ba8;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #e83e8c var(--bg-gradient-end, 180%)) #b94ba8;color:#fff}.bg-gradient-cyan-red{--bslib-color-fg: #fff;--bslib-color-bg: #c23287;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #ff0039 var(--bg-gradient-end, 180%)) #c23287;color:#fff}.bg-gradient-cyan-orange{--bslib-color-fg: #fff;--bslib-color-bg: #bc788f;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #f0ad4e var(--bg-gradient-end, 180%)) #bc788f;color:#fff}.bg-gradient-cyan-yellow{--bslib-color-fg: #fff;--bslib-color-bg: #c2617a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #ff7518 var(--bg-gradient-end, 180%)) #c2617a;color:#fff}.bg-gradient-cyan-green{--bslib-color-fg: #fff;--bslib-color-bg: #757b7a;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #3fb618 var(--bg-gradient-end, 180%)) #757b7a;color:#fff}.bg-gradient-cyan-teal{--bslib-color-fg: #fff;--bslib-color-bg: #6983ad;background:linear-gradient(var(--bg-gradient-deg, 140deg), #9954bb var(--bg-gradient-start, 36%), #20c997 var(--bg-gradient-end, 180%)) #6983ad;color:#fff}:root{--bslib-spacer: 1rem;--bslib-mb-spacer: var(--bslib-spacer, 1rem)}.bslib-mb-spacing{margin-bottom:var(--bslib-mb-spacer)}.bslib-gap-spacing{gap:var(--bslib-mb-spacer)}.bslib-gap-spacing>.bslib-mb-spacing,.bslib-gap-spacing>.form-group,.bslib-gap-spacing>p,.bslib-gap-spacing>pre{margin-bottom:0}.html-fill-container>.html-fill-item.bslib-mb-spacing{margin-bottom:0}.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}.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}@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-grid{display:grid !important;gap:var(--bslib-spacer, 1rem);height:var(--bslib-grid-height)}.bslib-grid.grid{grid-template-columns:repeat(var(--bs-columns, 12), minmax(0, 1fr));grid-template-rows:unset;grid-auto-rows:var(--bslib-grid--row-heights);--bslib-grid--row-heights--xs: unset;--bslib-grid--row-heights--sm: unset;--bslib-grid--row-heights--md: unset;--bslib-grid--row-heights--lg: unset;--bslib-grid--row-heights--xl: unset;--bslib-grid--row-heights--xxl: unset}.bslib-grid.grid.bslib-grid--row-heights--xs{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xs)}@media(min-width: 576px){.bslib-grid.grid.bslib-grid--row-heights--sm{--bslib-grid--row-heights: var(--bslib-grid--row-heights--sm)}}@media(min-width: 768px){.bslib-grid.grid.bslib-grid--row-heights--md{--bslib-grid--row-heights: var(--bslib-grid--row-heights--md)}}@media(min-width: 992px){.bslib-grid.grid.bslib-grid--row-heights--lg{--bslib-grid--row-heights: var(--bslib-grid--row-heights--lg)}}@media(min-width: 1200px){.bslib-grid.grid.bslib-grid--row-heights--xl{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xl)}}@media(min-width: 1400px){.bslib-grid.grid.bslib-grid--row-heights--xxl{--bslib-grid--row-heights: var(--bslib-grid--row-heights--xxl)}}.bslib-grid>*>.shiny-input-container{width:100%}.bslib-grid-item{grid-column:auto/span 1}@media(max-width: 767.98px){.bslib-grid-item{grid-column:1/-1}}@media(max-width: 575.98px){.bslib-grid{grid-template-columns:1fr !important;height:var(--bslib-grid-height-mobile)}.bslib-grid.grid{height:unset !important;grid-auto-rows:var(--bslib-grid--row-heights--xs, auto)}}.bslib-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}}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)}}.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-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%)}.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)}.accordion .accordion-header{font-size:calc(1.29rem + 0.48vw);margin-top:0;margin-bottom:.5rem;font-weight:400;line-height:1.2;color:var(--bs-heading-color);margin-bottom:0}@media(min-width: 1200px){.accordion .accordion-header{font-size:1.65rem}}.accordion .accordion-icon:not(:empty){margin-right:.75rem;display:flex}.accordion .accordion-button:not(.collapsed){box-shadow:none}.accordion .accordion-button:not(.collapsed):focus{box-shadow:var(--bs-accordion-btn-focus-box-shadow)}:root{--bslib-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}.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] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] 35px [page-end-inset page-end] 5fr [screen-end-inset] 1.5em}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 3em [body-end] 50px [body-end-outset] minmax(0px, 250px) [page-end-inset] minmax(50px, 100px) [page-end] 1fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 100px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 150px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 991.98px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(1250px - 3em)) [body-content-end body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(1000px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 4fr [screen-end-inset] 1.5em [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] 1.5em [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] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [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] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [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] 1.5em [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: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}.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 00000000..e8f21f70 --- /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 00000000..1103f811 --- /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 00000000..e3726d72 --- /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 00000000..b30ce576 --- /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 00000000..e6ae635c --- /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 00000000..ca292be3 --- /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 00000000..b08f1dff --- /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 00000000..38cc4305 --- /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 00000000..ae0063aa --- /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 00000000..adc28356 --- /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 00000000..d788a958 --- /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 00000000..3aa49acd --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,71 @@ + + + + https://fastcore.fast.ai/xml.html + 2024-08-11T08:47:27.258Z + + + https://fastcore.fast.ai/net.html + 2024-08-11T08:47:27.238Z + + + https://fastcore.fast.ai/test.html + 2024-08-11T08:47:28.574Z + + + https://fastcore.fast.ai/xdg.html + 2024-08-11T08:47:26.926Z + + + https://fastcore.fast.ai/meta.html + 2024-08-11T08:47:26.810Z + + + https://fastcore.fast.ai/script.html + 2024-08-11T08:47:26.518Z + + + https://fastcore.fast.ai/parallel.html + 2024-08-11T08:47:26.410Z + + + https://fastcore.fast.ai/tour.html + 2024-08-11T08:47:24.582Z + + + https://fastcore.fast.ai/style.html + 2024-08-11T08:47:24.586Z + + + https://fastcore.fast.ai/basics.html + 2024-08-11T08:47:27.098Z + + + https://fastcore.fast.ai/xtras.html + 2024-08-11T08:47:26.958Z + + + https://fastcore.fast.ai/foundation.html + 2024-08-11T08:47:26.850Z + + + https://fastcore.fast.ai/py2pyi.html + 2024-08-11T08:47:26.662Z + + + https://fastcore.fast.ai/dispatch.html + 2024-08-11T08:47:27.006Z + + + https://fastcore.fast.ai/index.html + 2024-08-11T08:47:26.966Z + + + https://fastcore.fast.ai/transform.html + 2024-08-11T08:47:27.170Z + + + https://fastcore.fast.ai/docments.html + 2024-08-11T08:47:27.214Z + + diff --git a/style.html b/style.html new file mode 100644 index 00000000..2f3f8ba3 --- /dev/null +++ b/style.html @@ -0,0 +1,876 @@ + + + + + + + + + + +Style – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Style

+
+ +
+
+ Fast styling for friendly CLIs. +
+
+ + +
+ + + + +
+ + + +
+ + + +
+
+
+ +
+
+Note +
+
+
+

Styled outputs don’t show in Quarto documentation. Please use a notebook editor to correctly view this page.

+
+
+
+

source

+
+

StyleCode

+
+
 StyleCode (name, code, typ)
+
+

An escape sequence for styling terminal text.

+

The primary building block of the S API.

+
+
print(str(StyleCode('blue', 34, 'fg')) + 'hello' + str(StyleCode('default', 39, 'fg')) + ' world')
+
+
hello world
+
+
+
+

source

+
+
+

Style

+
+
 Style (codes=None)
+
+

A minimal terminal text styler.

+

The main way to use it is via the exported S object.

+
+
+Exported source +
S = Style()
+
+
+

We start with an empty style:

+
+
S
+
+
<Style: none>
+
+
+

Define a new style by chaining attributes:

+
+
s = S.blue.bold.underline
+s
+
+
<Style: blue bold underline>
+
+
+

You can see a full list of available styles with auto-complete by typing S . Tab.

+

Apply a style by calling it with a string:

+
+
s('hello world')
+
+
'\x1b[34m\x1b[1m\x1b[4mhello world\x1b[22m\x1b[24m\x1b[39m'
+
+
+

That’s a raw string with the underlying escape sequences that tell the terminal how to format text. To see the styled version we have to print it:

+
+
print(s('hello world'))
+
+
hello world
+
+
+

You can also nest styles:

+
+
print(S.bold(S.blue('key') + ' = value ') + S.light_gray(' ' + S.underline('# With a comment')) + ' and unstyled text')
+
+
key = value  # With a comment and unstyled text
+
+
+
+
print(S.blue('this '+S.bold('is')+' a test'))
+
+
this is a test
+
+
+
+

source

+
+
+

demo

+
+
 demo ()
+
+

Demonstrate all available styles and their codes.

+
+
demo()
+
+
 30    black           
+ 31    red             
+ 32    green           
+ 33    yellow          
+ 34    blue            
+ 35    magenta         
+ 36    cyan            
+ 37    light_gray      
+ 39    default         
+ 90    dark_gray       
+ 91    light_red       
+ 92    light_green     
+ 93    light_yellow    
+ 94    light_blue      
+ 95    light_magenta   
+ 96    light_cyan      
+ 97    white           
+ 40    black_bg        
+ 41    red_bg          
+ 42    green_bg        
+ 43    yellow_bg       
+ 44    blue_bg         
+ 45    magenta_bg      
+ 46    cyan_bg         
+ 47    light_gray_bg   
+ 49    default_bg      
+100    dark_gray_bg    
+101    light_red_bg    
+102    light_green_bg  
+103    light_yellow_bg 
+104    light_blue_bg   
+105    light_magenta_bg
+106    light_cyan_bg   
+107    white_bg        
+  1    bold            
+  2    dim             
+  3    italic          
+  4    underline       
+  5    blink           
+  7    invert          
+  8    hidden          
+  9    strikethrough   
+ 22    reset_bold      
+ 22    reset_dim       
+ 23    reset_italic    
+ 24    reset_underline 
+ 25    reset_blink     
+ 27    reset_invert    
+ 28    reset_hidden    
+ 29    reset_strikethrough
+  0    reset           
+
+
+ + +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/styles.css b/styles.css new file mode 100644 index 00000000..b46c2093 --- /dev/null +++ b/styles.css @@ -0,0 +1,18 @@ +.cell-output 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 { + background: none; + margin-top: 0; + } + + .cell > .sourceCode { + margin-bottom: 0; + } + \ No newline at end of file diff --git a/test.html b/test.html new file mode 100644 index 00000000..649a80b7 --- /dev/null +++ b/test.html @@ -0,0 +1,1062 @@ + + + + + + + + + + +Test – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Test

+
+ +
+
+ Helper functions to quickly write tests in notebooks +
+
+ + +
+ + + + +
+ + + +
+ + + +
+

Simple test functions

+

We can check that code raises an exception when that’s expected (test_fail).

+

To test for equality or inequality (with different types of things) we define a simple function test that compares two objects with a given cmp operator.

+
+

source

+
+

test_fail

+
+
 test_fail (f, msg='', contains='', args=None, kwargs=None)
+
+

Fails with msg unless f() raises an exception and (optionally) has contains in e.args

+
+
def _fail(): raise Exception("foobar")
+test_fail(_fail, contains="foo")
+
+def _fail(): raise Exception()
+test_fail(_fail)
+
+

We can also pass args and kwargs to function to check if it fails with special inputs.

+
+
def _fail_args(a):
+    if a == 5:
+        raise ValueError
+test_fail(_fail_args, args=(5,))
+test_fail(_fail_args, kwargs=dict(a=5))
+
+
+

source

+
+
+

test

+
+
 test (a, b, cmp, cname=None)
+
+

assert that cmp(a,b); display inputs and cname or cmp.__name__ if it fails

+
+
test([1,2],[1,2], operator.eq)
+test_fail(lambda: test([1,2],[1], operator.eq))
+test([1,2],[1],   operator.ne)
+test_fail(lambda: test([1,2],[1,2], operator.ne))
+
+
+
+
+

all_equal

+
+
 all_equal (a, b)
+
+

Compares whether a and b are the same length and have the same contents

+
+
test(['abc'], ['abc'], all_equal)
+test_fail(lambda: test(['abc'],['cab'], all_equal))
+
+
+
+
+

equals

+
+
 equals (a, b)
+
+

Compares a and b for equality; supports sublists, tensors and arrays too

+
+
test([['abc'],['a']], [['abc'],['a']],  equals)
+test([['abc'],['a'],'b', [['x']]], [['abc'],['a'],'b', [['x']]],  equals) # supports any depth and nested structure
+
+
+

source

+
+
+

nequals

+
+
 nequals (a, b)
+
+

Compares a and b for not equals

+
+
test(['abc'], ['ab' ], nequals)
+
+
+
+
+

test_eq test_ne, etc…

+

Just use test_eq/test_ne to test for ==/!=. test_eq_type checks things are equal and of the same type. We define them using test:

+
+

source

+
+

test_eq

+
+
 test_eq (a, b)
+
+

test that a==b

+
+
test_eq([1,2],[1,2])
+test_eq([1,2],map(int,[1,2]))
+test_eq(array([1,2]),array([1,2]))
+test_eq(array([1,2]),array([1,2]))
+test_eq([array([1,2]),3],[array([1,2]),3])
+test_eq(dict(a=1,b=2), dict(b=2,a=1))
+test_fail(lambda: test_eq([1,2], 1), contains="==")
+test_fail(lambda: test_eq(None, np.array([1,2])), contains="==")
+test_eq({'a', 'b', 'c'}, {'c', 'a', 'b'})
+
+
+
df1 = pd.DataFrame(dict(a=[1,2],b=['a','b']))
+df2 = pd.DataFrame(dict(a=[1,2],b=['a','b']))
+df3 = pd.DataFrame(dict(a=[1,2],b=['a','c']))
+
+test_eq(df1,df2)
+test_eq(df1.a,df2.a)
+test_fail(lambda: test_eq(df1,df3), contains='==')
+class T(pd.Series): pass
+test_eq(df1.iloc[0], T(df2.iloc[0])) # works with subclasses
+
+
+
test_eq(torch.zeros(10), torch.zeros(10, dtype=torch.float64))
+test_eq(torch.zeros(10), torch.ones(10)-1)
+test_fail(lambda:test_eq(torch.zeros(10), torch.ones(1, 10)), contains='==')
+test_eq(torch.zeros(3), [0,0,0])
+
+
+

source

+
+
+

test_eq_type

+
+
 test_eq_type (a, b)
+
+

test that a==b and are same type

+
+
test_eq_type(1,1)
+test_fail(lambda: test_eq_type(1,1.))
+test_eq_type([1,1],[1,1])
+test_fail(lambda: test_eq_type([1,1],(1,1)))
+test_fail(lambda: test_eq_type([1,1],[1,1.]))
+
+
+

source

+
+
+

test_ne

+
+
 test_ne (a, b)
+
+

test that a!=b

+
+
test_ne([1,2],[1])
+test_ne([1,2],[1,3])
+test_ne(array([1,2]),array([1,1]))
+test_ne(array([1,2]),array([1,1]))
+test_ne([array([1,2]),3],[array([1,2])])
+test_ne([3,4],array([3]))
+test_ne([3,4],array([3,5]))
+test_ne(dict(a=1,b=2), ['a', 'b'])
+test_ne(['a', 'b'], dict(a=1,b=2))
+
+
+

source

+
+
+

is_close

+
+
 is_close (a, b, eps=1e-05)
+
+

Is a within eps of b

+
+

source

+
+
+

test_close

+
+
 test_close (a, b, eps=1e-05)
+
+

test that a is within eps of b

+
+
test_close(1,1.001,eps=1e-2)
+test_fail(lambda: test_close(1,1.001))
+test_close([-0.001,1.001], [0.,1.], eps=1e-2)
+test_close(np.array([-0.001,1.001]), np.array([0.,1.]), eps=1e-2)
+test_close(array([-0.001,1.001]), array([0.,1.]), eps=1e-2)
+
+
+

source

+
+
+

test_is

+
+
 test_is (a, b)
+
+

test that a is b

+
+
test_fail(lambda: test_is([1], [1]))
+a = [1]
+test_is(a, a)
+b = [2]; test_fail(lambda: test_is(a, b))
+
+
+

source

+
+
+

test_shuffled

+
+
 test_shuffled (a, b)
+
+

test that a and b are shuffled versions of the same sequence of items

+
+
a = list(range(50))
+b = copy(a)
+random.shuffle(b)
+test_shuffled(a,b)
+test_fail(lambda:test_shuffled(a,a))
+
+
+
a = 'abc'
+b = 'abcabc'
+test_fail(lambda:test_shuffled(a,b))
+
+
+
a = ['a', 42, True] 
+b = [42, True, 'a']
+test_shuffled(a,b)
+
+
+

source

+
+
+

test_stdout

+
+
 test_stdout (f, exp, regex=False)
+
+

Test that f prints exp to stdout, optionally checking as regex

+
+
test_stdout(lambda: print('hi'), 'hi')
+test_fail(lambda: test_stdout(lambda: print('hi'), 'ho'))
+test_stdout(lambda: 1+1, '')
+test_stdout(lambda: print('hi there!'), r'^hi.*!$', regex=True)
+
+
+

source

+
+
+

test_warns

+
+
 test_warns (f, show=False)
+
+
+
test_warns(lambda: warnings.warn("Oh no!"))
+test_fail(lambda: test_warns(lambda: 2+2), contains='No warnings raised')
+
+
+
test_warns(lambda: warnings.warn("Oh no!"), show=True)
+
+
<class 'UserWarning'>: Oh no!
+
+
+
+
im = Image.open(TEST_IMAGE).resize((128,128)); im
+
+
+
+

+
+
+
+
+
+
im = Image.open(TEST_IMAGE_BW).resize((128,128)); im
+
+
+
+

+
+
+
+
+
+

source

+
+
+

test_fig_exists

+
+
 test_fig_exists (ax)
+
+

Test there is a figure displayed in ax

+
+
fig,ax = plt.subplots()
+ax.imshow(array(im));
+
+
+
+

+
+
+
+
+
+
test_fig_exists(ax)
+
+
+

source

+
+
+

ExceptionExpected

+
+
 ExceptionExpected (ex=<class 'Exception'>, regex='')
+
+

Context manager that tests if an exception is raised

+
+
def _tst_1(): assert False, "This is a test"
+def _tst_2(): raise SyntaxError
+
+with ExceptionExpected(): _tst_1()
+with ExceptionExpected(ex=AssertionError, regex="This is a test"): _tst_1()
+with ExceptionExpected(ex=SyntaxError): _tst_2()
+
+

exception is an abbreviation for ExceptionExpected().

+
+
with exception: _tst_1()
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/tour.html b/tour.html new file mode 100644 index 00000000..820e01af --- /dev/null +++ b/tour.html @@ -0,0 +1,936 @@ + + + + + + + + + +A tour of fastcore – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

A tour of fastcore

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

Here’s a (somewhat) quick tour of a few higlights from fastcore.

+
+

Documentation

+

All fast.ai projects, including this one, are built with nbdev, which is a full literate programming environment built on Jupyter Notebooks. That means that every piece of documentation, including the page you’re reading now, can be accessed as interactive Jupyter notebooks. In fact, you can even grab a link directly to a notebook running interactively on Google Colab - if you want to follow along with this tour, click the link below:

+
+
colab_link('index')
+ +
+

The full docs are available at fastcore.fast.ai. The code in the examples and in all fast.ai libraries follow the fast.ai style guide. In order to support interactive programming, all fast.ai libraries are designed to allow for import * to be used safely, particular by ensuring that __all__ is defined in all packages. In order to see where a function is from, just type it:

+
+
coll_repr
+
+
<function fastcore.foundation.coll_repr(c, max_n=10)>
+
+
+

For more details, including a link to the full documentation and source code, use doc, which pops up a window with this information:

+
doc(coll_repr)
+

+

The documentation also contains links to any related functions or classes, which appear like this: coll_repr (in the notebook itself you will just see a word with back-ticks around it; the links are auto-generated in the documentation site). The documentation will generally show one or more examples of use, along with any background context necessary to understand them. As you’ll see, the examples for each function and method are shown as tests, rather than example outputs, so let’s start by explaining that.

+
+
+

Testing

+

fastcore’s testing module is designed to work well with nbdev, which is a full literate programming environment built on Jupyter Notebooks. That means that your tests, docs, and code all live together in the same notebook. fastcore and nbdev’s approach to testing starts with the premise that all your tests should pass. If one fails, no more tests in a notebook are run.

+

Tests look like this:

+
+
test_eq(coll_repr(range(1000), 5), '(#1000) [0,1,2,3,4...]')
+
+

That’s an example from the docs for coll_repr. As you see, it’s not showing you the output directly. Here’s what that would look like:

+
+
coll_repr(range(1000), 5)
+
+
'(#1000) [0,1,2,3,4...]'
+
+
+

So, the test is actually showing you what the output looks like, because if the function call didn’t return '(#1000) [0,1,2,3,4...]', then the test would have failed.

+

So every test shown in the docs is also showing you the behavior of the library — and vice versa!

+

Test functions always start with test_, and then follow with the operation being tested. So test_eq tests for equality (as you saw in the example above). This includes tests for equality of arrays and tensors, lists and generators, and many more:

+
+
test_eq([0,1,2,3], np.arange(4))
+
+

When a test fails, it prints out information about what was expected:

+
test_eq([0,1,2,3], np.arange(3))
+
----
+  AssertionError: ==:
+  [0, 1, 2, 3]
+  [0 1 2]
+

If you want to check that objects are the same type, rather than the just contain the same collection, use test_eq_type.

+

You can test with any comparison function using test, e.g test whether an object is less than:

+
+
test(2, 3, operator.lt)
+
+

You can even test that exceptions are raised:

+
+
def divide_zero(): return 1/0
+test_fail(divide_zero)
+
+

…and test that things are printed to stdout:

+
+
test_stdout(lambda: print('hi'), 'hi')
+
+
+
+

Foundations

+

fast.ai is unusual in that we often use mixins in our code. Mixins are widely used in many programming languages, such as Ruby, but not so much in Python. We use mixins to attach new behavior to existing libraries, or to allow modules to add new behavior to our own classes, such as in extension modules. One useful example of a mixin we define is Path.ls, which lists a directory and returns an L (an extended list class which we’ll discuss shortly):

+
+
p = Path('images')
+p.ls()
+
+
(#6) [Path('images/mnist3.png'),Path('images/att_00000.png'),Path('images/puppy.jpg'),Path('images/att_00005.png'),Path('images/att_00007.png'),Path('images/att_00006.png')]
+
+
+

You can easily add you own mixins with the patch decorator, which takes advantage of Python 3 function annotations to say what class to patch:

+
+
@patch
+def num_items(self:Path): return len(self.ls())
+
+p.num_items()
+
+
6
+
+
+

We also use **kwargs frequently. In python **kwargs in a parameter like means “put any additional keyword arguments into a dict called kwargs”. Normally, using kwargs makes an API quite difficult to work with, because it breaks things like tab-completion and popup lists of signatures. utils provides use_kwargs and delegates to avoid this problem. See our detailed article on delegation on this topic.

+

GetAttr solves a similar problem (and is also discussed in the article linked above): it’s allows you to use Python’s exceptionally useful __getattr__ magic method, but avoids the problem that normally in Python tab-completion and docs break when using this. For instance, you can see here that Python’s dir function, which is used to find the attributes of a python object, finds everything inside the self.default attribute here:

+
+
class Author:
+    def __init__(self, name): self.name = name
+
+class ProductPage(GetAttr):
+    _default = 'author'
+    def __init__(self,author,price,cost): self.author,self.price,self.cost = author,price,cost
+
+p = ProductPage(Author("Jeremy"), 1.50, 0.50)
+[o for o in dir(p) if not o.startswith('_')]
+
+
['author', 'cost', 'name', 'price']
+
+
+

Looking at that ProductPage example, it’s rather verbose and duplicates a lot of attribute names, which can lead to bugs later if you change them only in one place. fastcore provides store_attr to simplify this common pattern. It also provides basic_repr to give simple objects a useful repr:

+
+
class ProductPage:
+    def __init__(self,author,price,cost): store_attr()
+    __repr__ = basic_repr('author,price,cost')
+
+ProductPage("Jeremy", 1.50, 0.50)
+
+
__main__.ProductPage(author='Jeremy', price=1.5, cost=0.5)
+
+
+

One of the most interesting fastcore functions is the funcs_kwargs decorator. This allows class behavior to be modified without sub-classing. This can allow folks that aren’t familiar with object-oriented programming to customize your class more easily. Here’s an example of a class that uses funcs_kwargs:

+
+
@funcs_kwargs
+class T:
+    _methods=['some_method']
+    def __init__(self, **kwargs): assert not kwargs, f'Passed unknown args: {kwargs}'
+
+p = T(some_method = print)
+p.some_method("hello")
+
+
hello
+
+
+

The assert not kwargs above is used to ensure that the user doesn’t pass an unknown parameter (i.e one that’s not in _methods). fastai uses funcs_kwargs in many places, for instance, you can customize any part of a DataLoader by passing your own methods.

+

fastcore also provides many utility functions that make a Python programmer’s life easier, in fastcore.utils. We won’t look at many here, since you can easily look at the docs yourself. To get you started, have a look at the docs for chunked (remember, if you’re in a notebook, type doc(chunked)), which is a handy function for creating lazily generated batches from a collection.

+

Python’s ProcessPoolExecutor is extended to allow max_workers to be set to 0, to easily turn off parallel processing. This makes it easy to debug your code in serial, then run it in parallel. It also allows you to pass arguments to your parallel function, and to ensure there’s a pause between calls, in case the process you are running has race conditions. parallel makes parallel processing even easier to use, and even adds an optional progress bar.

+
+
+

L

+

Like most languages, Python allows for very concise syntax for some very common types, such as list, which can be constructed with [1,2,3]. Perl’s designer Larry Wall explained the reasoning for this kind of syntax:

+
+

In metaphorical honor of Huffman’s compression code that assigns smaller numbers of bits to more common bytes. In terms of syntax, it simply means that commonly used things should be shorter, but you shouldn’t waste short sequences on less common constructs.

+
+

On this basis, fastcore has just one type that has a single letter name: L. The reason for this is that it is designed to be a replacement for list, so we want it to be just as easy to use as [1,2,3]. Here’s how to create that as an L:

+
+
L(1,2,3)
+
+
(#3) [1,2,3]
+
+
+

The first thing to notice is that an L object includes in its representation its number of elements; that’s the (#3) in the output above. If there’s more than 10 elements, it will automatically truncate the list:

+
+
p = L.range(20).shuffle()
+p
+
+
(#20) [5,1,9,10,18,13,6,17,3,16...]
+
+
+

L contains many of the same indexing ideas that NumPy’s array does, including indexing with a list of indexes, or a boolean mask list:

+
+
p[2,4,6]
+
+
(#3) [9,18,6]
+
+
+

It also contains other methods used in array, such as L.argwhere:

+
+
p.argwhere(ge(15))
+
+
(#5) [4,7,9,18,19]
+
+
+

As you can see from this example, fastcore also includes a number of features that make a functional style of programming easier, such as a full range of boolean functions (e.g ge, gt, etc) which give the same answer as the functions from Python’s operator module if given two parameters, but return a curried function if given one parameter.

+

There’s too much functionality to show it all here, so be sure to check the docs. Many little things are added that we thought should have been in list in the first place, such as making this do what you’d expect (which is an error with list, but works fine with L):

+
+
1 + L(2,3,4)
+
+
(#4) [1,2,3,4]
+
+
+
+
+

Transforms

+

A Transform is the main building block of the fastai data pipelines. In the most general terms a transform can be any function you want to apply to your data, however the Transform class provides several mechanisms that make the process of building them easy and flexible (see the docs for information about each of these):

+
    +
  • Type dispatch
  • +
  • Dispatch over tuples
  • +
  • Reversability
  • +
  • Type propagation
  • +
  • Preprocessing
  • +
  • Filtering based on the dataset type
  • +
  • Ordering
  • +
  • Appending new behavior with decorators
  • +
+

Transform looks for three special methods, encodes, decodes, and setups, which provide the implementation for __call__, decode, and setup respectively. For instance:

+
+
class A(Transform):
+    def encodes(self, x): return x+1
+
+A()(1)
+
+
2
+
+
+

For simple transforms like this, you can also use Transform as a decorator:

+
+
@Transform
+def f(x): return x+1
+
+f(1)
+
+
2
+
+
+

Transforms can be composed into a Pipeline:

+
+
@Transform
+def g(x): return x/2
+
+pipe = Pipeline([f,g])
+pipe(3)
+
+
2.0
+
+
+

The power of Transform and Pipeline is best understood by seeing how they’re used to create a complete data processing pipeline. This is explained in chapter 11 of the fastai book, which is available for free in Jupyter Notebook format.

+ + +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/transform.html b/transform.html new file mode 100644 index 00000000..6e022ca3 --- /dev/null +++ b/transform.html @@ -0,0 +1,1433 @@ + + + + + + + + + + +Transforms – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Transforms

+
+ +
+
+ Definition of Transform and Pipeline +
+
+ + +
+ + + + +
+ + + +
+ + + +
+
from __future__ import annotations
+from nbdev.showdoc import *
+from fastcore.test import *
+from fastcore.nb_imports import *
+
+

The classes here provide functionality for creating a composition of partially reversible functions. By “partially reversible” we mean that a transform can be decoded, creating a form suitable for display. This is not necessarily identical to the original form (e.g. a transform that changes a byte tensor to a float tensor does not recreate a byte tensor when decoded, since that may lose precision, and a float tensor can be displayed already).

+

Classes are also provided and for composing transforms, and mapping them over collections. Pipeline is a transform which composes several Transform, knowing how to decode them or show an encoded item.

+
+

source

+
+

Transform

+
+
 Transform (enc=None, dec=None, split_idx=None, order=None)
+
+

Delegates (__call__,decode,setup) to (encodes,decodes,setups) if split_idx matches

+

A Transform is the main building block of the fastai data pipelines. In the most general terms a transform can be any function you want to apply to your data, however the Transform class provides several mechanisms that make the process of building them easy and flexible.

+
+
+

The main Transform features:

+
    +
  • Type dispatch - Type annotations are used to determine if a transform should be applied to the given argument. It also gives an option to provide several implementations and it choses the one to run based on the type. This is useful for example when running both independent and dependent variables through the pipeline where some transforms only make sense for one and not the other. Another usecase is designing a transform that handles different data formats. Note that if a transform takes multiple arguments only the type of the first one is used for dispatch.
  • +
  • Handling of tuples - When a tuple (or a subclass of tuple) of data is passed to a transform it will get applied to each element separately. You can opt out of this behavior by passing a list or an L, as only tuples gets this specific behavior. An alternative is to use ItemTransform defined below, which will always take the input as a whole.
  • +
  • Reversability - A transform can be made reversible by implementing the decodes method. This is mainly used to turn something like a category which is encoded as a number back into a label understandable by humans for showing purposes. Like the regular call method, the decode method that is used to decode will be applied over each element of a tuple separately.
  • +
  • Type propagation - Whenever possible a transform tries to return data of the same type it received. Mainly used to maintain semantics of things like ArrayImage which is a thin wrapper of pytorch’s Tensor. You can opt out of this behavior by adding ->None return type annotation.
  • +
  • Preprocessing - The setup method can be used to perform any one-time calculations to be later used by the transform, for example generating a vocabulary to encode categorical data.
  • +
  • Filtering based on the dataset type - By setting the split_idx flag you can make the transform be used only in a specific DataSource subset like in training, but not validation.
  • +
  • Ordering - You can set the order attribute which the Pipeline uses when it needs to merge two lists of transforms.
  • +
  • Appending new behavior with decorators - You can easily extend an existing Transform by creating encodes or decodes methods for new data types. You can put those new methods outside the original transform definition and decorate them with the class you wish them patched into. This can be used by the fastai library users to add their own behavior, or multiple modules contributing to the same transform.
  • +
+
+
+

Defining a Transform

+

There are a few ways to create a transform with different ratios of simplicity to flexibility. - Extending the Transform class - Use inheritence to implement the methods you want. - Passing methods to the constructor - Instantiate the Transform class and pass your functions as enc and dec arguments. - @Transform decorator - Turn any function into a Transform by just adding a decorator - very straightforward if all you need is a single encodes implementation. - Passing a function to fastai APIs - Same as above, but when passing a function to other transform aware classes like Pipeline or TfmdDS you don’t even need a decorator. Your function will get converted to a Transform automatically.

+

A simple way to create a Transform is to pass a function to the constructor. In the below example, we pass an anonymous function that does integer division by 2:

+
+
f = Transform(lambda o:o//2)
+
+

If you call this transform, it will apply the transformation:

+
+
test_eq_type(f(2), 1)
+
+

Another way to define a Transform is to extend the Transform class:

+
+
class A(Transform): pass
+
+

However, to enable your transform to do something, you have to define an encodes method. Note that we can use the class name as a decorator to add this method to the original class.

+
+
@A
+def encodes(self, x): return x+1
+
+f1 = A()
+test_eq(f1(1), 2) # f1(1) is the same as f1.encode(1)
+
+

In addition to adding an encodes method, we can also add a decodes method. This enables you to call the decode method (without an s). For more information about the purpose of decodes, see the discussion about Reversibility in the above section.

+

Just like with encodes, you can add a decodes method to the original class by using the class name as a decorator:

+
+
class B(A): pass
+
+@B
+def decodes(self, x): return x-1
+
+f2 = B()
+test_eq(f2.decode(2), 1)
+
+test_eq(f2(1), 2) # uses A's encode method from the parent class
+
+

If you do not define an encodes or decodes method the original value will be returned:

+
+
class _Tst(Transform): pass 
+
+f3 = _Tst() # no encodes or decodes method have been defined
+test_eq_type(f3.decode(2.0), 2.0)
+test_eq_type(f3(2), 2)
+
+

Transforms can be created from class methods too:

+
+
class A:
+    @classmethod
+    def create(cls, x:int): return x+1
+test_eq(Transform(A.create)(1), 2)
+
+
+

Defining Transforms With A Decorator

+

Transform can be used as a decorator to turn a function into a Transform.

+
+
@Transform
+def f(x): return x//2
+test_eq_type(f(2), 1)
+test_eq_type(f.decode(2.0), 2.0)
+
+@Transform
+def f(x): return x*2
+test_eq_type(f(2), 4)
+test_eq_type(f.decode(2.0), 2.0)
+
+
+
+

Typed Dispatch and Transforms

+

We can also apply different transformations depending on the type of the input passed by using TypedDispatch. TypedDispatch automatically works with Transform when using type hints:

+
+
class A(Transform): pass
+
+@A
+def encodes(self, x:int): return x//2
+
+@A
+def encodes(self, x:float): return x+1
+
+

When we pass in an int, this calls the first encodes method:

+
+
f = A()
+test_eq_type(f(3), 1)
+
+

When we pass in a float, this calls the second encodes method:

+
+
test_eq_type(f(2.), 3.)
+
+

When we pass in a type that is not specified in encodes, the original value is returned:

+
+
test_eq(f('a'), 'a')
+
+

If the type annotation is a tuple, then any type in the tuple will match:

+
+
class MyClass(int): pass
+
+class A(Transform):
+    def encodes(self, x:MyClass|float): return x/2
+    def encodes(self, x:str|list): return str(x)+'_1'
+
+f = A()
+
+

The below two examples match the first encodes, with a type of MyClass and float, respectively:

+
+
test_eq(f(MyClass(2)), 1.) # input is of type MyClass 
+test_eq(f(6.0), 3.0) # input is of type float
+
+

The next two examples match the second encodes method, with a type of str and list, respectively:

+
+
test_eq(f('a'), 'a_1') # input is of type str
+test_eq(f(['a','b','c']), "['a', 'b', 'c']_1") # input is of type list
+
+
+
+

Casting Types With Transform

+

Without any intervention it is easy for operations to change types in Python. For example, FloatSubclass (defined below) becomes a float after performing multiplication:

+
+
class FloatSubclass(float): pass
+test_eq_type(FloatSubclass(3.0) * 2, 6.0)
+
+

This behavior is often not desirable when performing transformations on data. Therefore, Transform will attempt to cast the output to be of the same type as the input by default. In the below example, the output will be cast to a FloatSubclass type to match the type of the input:

+
+
@Transform
+def f(x): return x*2
+
+test_eq_type(f(FloatSubclass(3.0)), FloatSubclass(6.0))
+
+

We can optionally turn off casting by annotating the transform function with a return type of None:

+
+
@Transform
+def f(x)-> None: return x*2 # Same transform as above, but with a -> None annotation
+
+test_eq_type(f(FloatSubclass(3.0)), 6.0)  # Casting is turned off because of -> None annotation
+
+

However, Transform will only cast output back to the input type when the input is a subclass of the output. In the below example, the input is of type FloatSubclass which is not a subclass of the output which is of type str. Therefore, the output doesn’t get cast back to FloatSubclass and stays as type str:

+
+
@Transform
+def f(x): return str(x)
+    
+test_eq_type(f(Float(2.)), '2.0')
+
+

Just like encodes, the decodes method will cast outputs to match the input type in the same way. In the below example, the output of decodes remains of type MySubclass:

+
+
class MySubclass(int): pass
+
+def enc(x): return MySubclass(x+1)
+def dec(x): return x-1
+
+
+f = Transform(enc,dec)
+t = f(1) # t is of type MySubclass
+test_eq_type(f.decode(t), MySubclass(1)) # the output of decode is cast to MySubclass to match the input type.
+
+
+
+

Apply Transforms On Subsets With split_idx

+

You can apply transformations to subsets of data by specifying a split_idx property. If a transform has a split_idx then it’s only applied if the split_idx param matches. In the below example, we set split_idx equal to 1:

+
+
def enc(x): return x+1
+def dec(x): return x-1
+f = Transform(enc,dec)
+f.split_idx = 1
+
+

The transformations are applied when a matching split_idx parameter is passed:

+
+
test_eq(f(1, split_idx=1),2)
+test_eq(f.decode(2, split_idx=1),1)
+
+

On the other hand, transformations are ignored when the split_idx parameter does not match:

+
+
test_eq(f(1, split_idx=0), 1)
+test_eq(f.decode(2, split_idx=0), 2)
+
+
+
+

Transforms on Lists

+

Transform operates on lists as a whole, not element-wise:

+
+
class A(Transform):
+    def encodes(self, x): return dict(x)
+    def decodes(self, x): return list(x.items())
+    
+f = A()
+_inp = [(1,2), (3,4)]
+t = f(_inp)
+
+test_eq(t, dict(_inp))
+test_eq(f.decodes(t), _inp)
+
+

If you want a transform to operate on a list elementwise, you must implement this appropriately in the encodes and decodes methods:

+
+
class AL(Transform): pass
+
+@AL
+def encodes(self, x): return [x_+1 for x_ in x]
+
+@AL
+def decodes(self, x): return [x_-1 for x_ in x]
+
+f = AL()
+t = f([1,2])
+
+test_eq(t, [2,3])
+test_eq(f.decode(t), [1,2])
+
+
+
+

Transforms on Tuples

+

Unlike lists, Transform operates on tuples element-wise.

+
+
def neg_int(x): return -x
+f = Transform(neg_int)
+
+test_eq(f((1,2,3)), (-1,-2,-3))
+
+

Transforms will also apply TypedDispatch element-wise on tuples when an input type annotation is specified. In the below example, the values 1.0 and 3.0 are ignored because they are of type float, not int:

+
+
def neg_int(x:int): return -x
+f = Transform(neg_int)
+
+test_eq(f((1.0, 2, 3.0)), (1.0, -2, 3.0))
+
+

Another example of how Transform can use TypedDispatch with tuples is shown below:

+
+
class B(Transform): pass
+
+@B
+def encodes(self, x:int): return x+1
+
+@B
+def encodes(self, x:str): return x+'hello'
+
+@B
+def encodes(self, x): return str(x)+'!'
+
+

If the input is not an int or str, the third encodes method will apply:

+
+
b = B()
+test_eq(b([1]), '[1]!') 
+test_eq(b([1.0]), '[1.0]!')
+
+

However, if the input is a tuple, then the appropriate method will apply according to the type of each element in the tuple:

+
+
test_eq(b(('1',)), ('1hello',))
+test_eq(b((1,2)), (2,3))
+test_eq(b(('a',1.0)), ('ahello','1.0!'))
+
+

Dispatching over tuples works recursively, by the way:

+
+
class B(Transform):
+    def encodes(self, x:int): return x+1
+    def encodes(self, x:str): return x+'_hello'
+    def decodes(self, x:int): return x-1
+    def decodes(self, x:str): return x.replace('_hello', '')
+
+f = B()
+start = (1.,(2,'3'))
+t = f(start)
+test_eq_type(t, (1.,(3,'3_hello')))
+test_eq(f.decode(t), start)
+
+

Dispatching also works with typing module type classes, like numbers.integral:

+
+
@Transform
+def f(x:numbers.Integral): return x+1
+
+t = f((1,'1',1))
+test_eq(t, (2, '1', 2))
+
+
+

source

+
+
+
+

InplaceTransform

+
+
 InplaceTransform (enc=None, dec=None, split_idx=None, order=None)
+
+

A Transform that modifies in-place and just returns whatever it’s passed

+
+
class A(InplaceTransform): pass
+
+@A
+def encodes(self, x:pd.Series): x.fillna(10, inplace=True)
+    
+f = A()
+
+test_eq_type(f(pd.Series([1,2,None])),pd.Series([1,2,10],dtype=np.float64)) #fillna fills with floats.
+
+
+

source

+
+
+

DisplayedTransform

+
+
 DisplayedTransform (enc=None, dec=None, split_idx=None, order=None)
+
+

A transform with a __repr__ that shows its attrs

+

Transforms normally are represented by just their class name and a list of encodes and decodes implementations:

+
+
class A(Transform): encodes,decodes = noop,noop
+f = A()
+f
+
+
A:
+encodes: (object,object) -> noop
+decodes: (object,object) -> noop
+
+
+

A DisplayedTransform will in addition show the contents of all attributes listed in the comma-delimited string self.store_attrs:

+
+
class A(DisplayedTransform):
+    encodes = noop
+    def __init__(self, a, b=2):
+        super().__init__()
+        store_attr()
+    
+A(a=1,b=2)
+
+
A -- {'a': 1, 'b': 2}:
+encodes: (object,object) -> noop
+decodes: 
+
+
+
+

source

+
+
+

ItemTransform

+
+
 ItemTransform (enc=None, dec=None, split_idx=None, order=None)
+
+

A transform that always take tuples as items

+

ItemTransform is the class to use to opt out of the default behavior of Transform.

+
+
class AIT(ItemTransform): 
+    def encodes(self, xy): x,y=xy; return (x+y,y)
+    def decodes(self, xy): x,y=xy; return (x-y,y)
+    
+f = AIT()
+test_eq(f((1,2)), (3,2))
+test_eq(f.decode((3,2)), (1,2))
+
+

If you pass a special tuple subclass, the usual retain type behavior of Transform will keep it:

+
+
class _T(tuple): pass
+x = _T((1,2))
+test_eq_type(f(x), _T((3,2)))
+
+
+

source

+
+
+

get_func

+
+
 get_func (t, name, *args, **kwargs)
+
+

Get the t.name (potentially partial-ized with args and kwargs) or noop if not defined

+

This works for any kind of t supporting getattr, so a class or a module.

+
+
test_eq(get_func(operator, 'neg', 2)(), -2)
+test_eq(get_func(operator.neg, '__call__')(2), -2)
+test_eq(get_func(list, 'foobar')([2]), [2])
+a = [2,1]
+get_func(list, 'sort')(a)
+test_eq(a, [1,2])
+
+

Transforms are built with multiple-dispatch: a given function can have several methods depending on the type of the object received. This is done directly with the TypeDispatch module and type-annotation in Transform, but you can also use the following class.

+
+

source

+
+
+

Func

+
+
 Func (name, *args, **kwargs)
+
+

Basic wrapper around a name with args and kwargs to call on a given type

+

You can call the Func object on any module name or type, even a list of types. It will return the corresponding function (with a default to noop if nothing is found) or list of functions.

+
+
test_eq(Func('sqrt')(math), math.sqrt)
+
+
+
+
+

Sig

+
+
 Sig (*args, **kwargs)
+
+

Sig is just sugar-syntax to create a Func object more easily with the syntax Sig.name(*args, **kwargs).

+
+
f = Sig.sqrt()
+test_eq(f(math), math.sqrt)
+
+
+

source

+
+
+

compose_tfms

+
+
 compose_tfms (x, tfms, is_enc=True, reverse=False, **kwargs)
+
+

Apply all func_nm attribute of tfms on x, maybe in reverse order

+
+
def to_int  (x):   return Int(x)
+def to_float(x):   return Float(x)
+def double  (x):   return x*2
+def half(x)->None: return x/2
+
+
+
def test_compose(a, b, *fs): test_eq_type(compose_tfms(a, tfms=map(Transform,fs)), b)
+
+test_compose(1,   Int(1),   to_int)
+test_compose(1,   Float(1), to_int,to_float)
+test_compose(1,   Float(2), to_int,to_float,double)
+test_compose(2.0, 2.0,      to_int,double,half)
+
+
+
class A(Transform):
+    def encodes(self, x:float):  return Float(x+1)
+    def decodes(self, x): return x-1
+    
+tfms = [A(), Transform(math.sqrt)]
+t = compose_tfms(3., tfms=tfms)
+test_eq_type(t, Float(2.))
+test_eq(compose_tfms(t, tfms=tfms, is_enc=False), 1.)
+test_eq(compose_tfms(4., tfms=tfms, reverse=True), 3.)
+
+
+
tfms = [A(), Transform(math.sqrt)]
+test_eq(compose_tfms((9,3.), tfms=tfms), (3,2.))
+
+
+

source

+
+
+

mk_transform

+
+
 mk_transform (f)
+
+

Convert function f to Transform if it isn’t already one

+
+

source

+
+
+

gather_attrs

+
+
 gather_attrs (o, k, nm)
+
+

Used in getattr to collect all attrs k from self.{nm}

+
+

source

+
+
+

gather_attr_names

+
+
 gather_attr_names (o, nm)
+
+

Used in dir to collect all attrs k from self.{nm}

+
+

source

+
+
+

Pipeline

+
+
 Pipeline (funcs=None, split_idx=None)
+
+

A pipeline of composed (for encode/decode) transforms, setup with types

+
+
add_docs(Pipeline,
+         __call__="Compose `__call__` of all `fs` on `o`",
+         decode="Compose `decode` of all `fs` on `o`",
+         show="Show `o`, a single item from a tuple, decoding as needed",
+         add="Add transforms `ts`",
+         setup="Call each tfm's `setup` in order")
+
+

Pipeline is a wrapper for compose_tfms. You can pass instances of Transform or regular functions in funcs, the Pipeline will wrap them all in Transform (and instantiate them if needed) during the initialization. It handles the transform setup by adding them one at a time and calling setup on each, goes through them in order in __call__ or decode and can show an object by applying decoding the transforms up until the point it gets an object that knows how to show itself.

+
+
# Empty pipeline is noop
+pipe = Pipeline()
+test_eq(pipe(1), 1)
+test_eq(pipe((1,)), (1,))
+# Check pickle works
+assert pickle.loads(pickle.dumps(pipe))
+
+
+
class IntFloatTfm(Transform):
+    def encodes(self, x):  return Int(x)
+    def decodes(self, x):  return Float(x)
+    foo=1
+
+int_tfm=IntFloatTfm()
+
+def neg(x): return -x
+neg_tfm = Transform(neg, neg)
+
+
+
pipe = Pipeline([neg_tfm, int_tfm])
+
+start = 2.0
+t = pipe(start)
+test_eq_type(t, Int(-2))
+test_eq_type(pipe.decode(t), Float(start))
+test_stdout(lambda:pipe.show(t), '-2')
+
+
+
pipe = Pipeline([neg_tfm, int_tfm])
+t = pipe(start)
+test_stdout(lambda:pipe.show(pipe((1.,2.))), '-1\n-2')
+test_eq(pipe.foo, 1)
+assert 'foo' in dir(pipe)
+assert 'int_float_tfm' in dir(pipe)
+
+

You can add a single transform or multiple transforms ts using Pipeline.add. Transforms will be ordered by Transform.order.

+
+
pipe = Pipeline([neg_tfm, int_tfm])
+class SqrtTfm(Transform):
+    order=-1
+    def encodes(self, x): 
+        return x**(.5)
+    def decodes(self, x): return x**2
+pipe.add(SqrtTfm())
+test_eq(pipe(4),-2)
+test_eq(pipe.decode(-2),4)
+pipe.add([SqrtTfm(),SqrtTfm()])
+test_eq(pipe(256),-2)
+test_eq(pipe.decode(-2),256)
+
+

Transforms are available as attributes named with the snake_case version of the names of their types. Attributes in transforms can be directly accessed as attributes of the pipeline.

+
+
test_eq(pipe.int_float_tfm, int_tfm)
+test_eq(pipe.foo, 1)
+
+pipe = Pipeline([int_tfm, int_tfm])
+pipe.int_float_tfm
+test_eq(pipe.int_float_tfm[0], int_tfm)
+test_eq(pipe.foo, [1,1])
+
+
+
# Check opposite order
+pipe = Pipeline([int_tfm,neg_tfm])
+t = pipe(start)
+test_eq(t, -2)
+test_stdout(lambda:pipe.show(t), '-2')
+
+
+
class A(Transform):
+    def encodes(self, x):  return int(x)
+    def decodes(self, x):  return Float(x)
+
+pipe = Pipeline([neg_tfm, A])
+t = pipe(start)
+test_eq_type(t, -2)
+test_eq_type(pipe.decode(t), Float(start))
+test_stdout(lambda:pipe.show(t), '-2.0')
+
+
+
s2 = (1,2)
+pipe = Pipeline([neg_tfm, A])
+t = pipe(s2)
+test_eq_type(t, (-1,-2))
+test_eq_type(pipe.decode(t), (Float(1.),Float(2.)))
+test_stdout(lambda:pipe.show(t), '-1.0\n-2.0')
+
+
+
from PIL import Image
+
+
+
class ArrayImage(ndarray):
+    _show_args = {'cmap':'viridis'}
+    def __new__(cls, x, *args, **kwargs):
+        if isinstance(x,tuple): super().__new__(cls, x, *args, **kwargs)
+        if args or kwargs: raise RuntimeError('Unknown array init args')
+        if not isinstance(x,ndarray): x = array(x)
+        return x.view(cls)
+    
+    def show(self, ctx=None, figsize=None, **kwargs):
+        if ctx is None: _,ctx = plt.subplots(figsize=figsize)
+        ctx.imshow(im, **{**self._show_args, **kwargs})
+        ctx.axis('off')
+        return ctx
+    
+im = Image.open(TEST_IMAGE)
+im_t = ArrayImage(im)
+
+
+
def f1(x:ArrayImage): return -x
+def f2(x): return Image.open(x).resize((128,128))
+def f3(x:Image.Image): return(ArrayImage(array(x)))
+
+
+
pipe = Pipeline([f2,f3,f1])
+t = pipe(TEST_IMAGE)
+test_eq(type(t), ArrayImage)
+test_eq(t, -array(f3(f2(TEST_IMAGE))))
+
+
+
pipe = Pipeline([f2,f3])
+t = pipe(TEST_IMAGE)
+ax = pipe.show(t)
+
+
+
+

+
+
+
+
+
+
#test_fig_exists(ax)
+
+
+
#Check filtering is properly applied
+add1 = B()
+add1.split_idx = 1
+pipe = Pipeline([neg_tfm, A(), add1])
+test_eq(pipe(start), -2)
+pipe.split_idx=1
+test_eq(pipe(start), -1)
+pipe.split_idx=0
+test_eq(pipe(start), -2)
+for t in [None, 0, 1]:
+    pipe.split_idx=t
+    test_eq(pipe.decode(pipe(start)), start)
+    test_stdout(lambda: pipe.show(pipe(start)), "-2.0")
+
+
+
def neg(x): return -x
+test_eq(type(mk_transform(neg)), Transform)
+test_eq(type(mk_transform(math.sqrt)), Transform)
+test_eq(type(mk_transform(lambda a:a*2)), Transform)
+test_eq(type(mk_transform(Pipeline([neg]))), Pipeline)
+
+
+
+

Methods

+
+
#TODO: method examples
+
+
+

source

+
+
+

Pipeline.__call__

+
+
 Pipeline.__call__ (o)
+
+

Call self as a function.

+
+

source

+
+
+

Pipeline.decode

+
+
 Pipeline.decode (o, full=True)
+
+
+

source

+
+
+

Pipeline.setup

+
+
 Pipeline.setup (items=None, train_setup=False)
+
+

During the setup, the Pipeline starts with no transform and adds them one at a time, so that during its setup, each transform gets the items processed up to its point and not after.

+ + +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/xdg.html b/xdg.html new file mode 100644 index 00000000..46f1ee4e --- /dev/null +++ b/xdg.html @@ -0,0 +1,850 @@ + + + + + + + + + + +XDG – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

XDG

+
+ +
+
+ XDG Base Directory Specification helpers. +
+
+ + +
+ + + + +
+ + + +
+ + + +

See the XDG Base Directory Specification for more information.

+
+

Overview

+

xdg_cache_home, xdg_config_home, xdg_data_home, and xdg_state_home return pathlib.Path objects containing the value of the environment variable named XDG_CACHE_HOME, XDG_CONFIG_HOME, XDG_DATA_HOME, and XDG_STATE_HOME respectively, or the default defined in the specification if the environment variable is unset, empty, or contains a relative path rather than absolute path.

+

xdg_config_dirs and xdg_data_dirs return a list of pathlib.Path objects containing the value, split on colons, of the environment variable named XDG_CONFIG_DIRS and XDG_DATA_DIRS respectively, or the default defined in the specification if the environment variable is unset or empty. Relative paths are ignored, as per the specification.

+

xdg_runtime_dir returns a pathlib.Path object containing the value of the XDG_RUNTIME_DIR environment variable, or None if the environment variable is not set, or contains a relative path rather than absolute path.

+
+
+

Helpers

+

We’ll start by defining a context manager that temporarily sets an environment variable to demonstrate the behaviour of each helper function:

+
+
from contextlib import contextmanager
+
+
+
@contextmanager
+def env(variable, value):
+    old = os.environ.get(variable, None)
+    try:
+        os.environ[variable] = value
+        yield
+    finally:
+        if old is None: del os.environ[variable]
+        else: os.environ[variable] = old
+
+
+

source

+
+

xdg_cache_home

+
+
 xdg_cache_home ()
+
+

Path corresponding to XDG_CACHE_HOME

+
+
from fastcore.test import *
+
+
+
test_eq(xdg_cache_home(), Path.home()/'.cache')
+with env('XDG_CACHE_HOME', '/home/fastai/.cache'):
+    test_eq(xdg_cache_home(), Path('/home/fastai/.cache'))
+
+
+

source

+
+
+

xdg_config_dirs

+
+
 xdg_config_dirs ()
+
+

Paths corresponding to XDG_CONFIG_DIRS

+
+
test_eq(xdg_config_dirs(), [Path('/etc/xdg')])
+with env('XDG_CONFIG_DIRS', '/home/fastai/.xdg:/home/fastai/.config'):
+    test_eq(xdg_config_dirs(), [Path('/home/fastai/.xdg'), Path('/home/fastai/.config')])
+
+
+

source

+
+
+

xdg_config_home

+
+
 xdg_config_home ()
+
+

Path corresponding to XDG_CONFIG_HOME

+
+
test_eq(xdg_config_home(), Path.home()/'.config')
+with env('XDG_CONFIG_HOME', '/home/fastai/.config'):
+    test_eq(xdg_config_home(), Path('/home/fastai/.config'))
+
+
+

source

+
+
+

xdg_data_dirs

+
+
 xdg_data_dirs ()
+
+

Paths corresponding to XDG_DATA_DIRS`

+
+

source

+
+
+

xdg_data_home

+
+
 xdg_data_home ()
+
+

Path corresponding to XDG_DATA_HOME

+
+
test_eq(xdg_data_home(), Path.home()/'.local/share')
+with env('XDG_DATA_HOME', '/home/fastai/.data'):
+    test_eq(xdg_data_home(), Path('/home/fastai/.data'))
+
+
+

source

+
+
+

xdg_runtime_dir

+
+
 xdg_runtime_dir ()
+
+

Path corresponding to XDG_RUNTIME_DIR

+
+

source

+
+
+

xdg_state_home

+
+
 xdg_state_home ()
+
+

Path corresponding to XDG_STATE_HOME

+
+
test_eq(xdg_state_home(), Path.home()/'.local/state')
+with env('XDG_STATE_HOME', '/home/fastai/.state'):
+    test_eq(xdg_state_home(), Path('/home/fastai/.state'))
+
+
+

Copyright © 2016-2021 Scott Stevenson

+

Modifications copyright © 2022 onwards Jeremy Howard

+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/xml.html b/xml.html new file mode 100644 index 00000000..27bf374e --- /dev/null +++ b/xml.html @@ -0,0 +1,944 @@ + + + + + + + + + + +XML – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

XML

+
+ +
+
+ Concise generation of XML. +
+
+ + +
+ + + + +
+ + + +
+ + + +
+
from IPython.display import Markdown
+from pprint import pprint
+
+
+

source

+
+

FT

+
+
 FT (tag, cs, attrs=None, void_=False, **kwargs)
+
+

A ‘Fast Tag’ structure, which is a list of [tag,children,attrs]

+
+

source

+
+
+

attrmap

+
+
 attrmap (o)
+
+
+

source

+
+
+

valmap

+
+
 valmap (o)
+
+
+

source

+
+
+

ft

+
+
 ft (tag:str, *c, void_=False, attrmap=<function attrmap>,
+     valmap=<function valmap>, **kw)
+
+

Create an FT structure for to_xml()

+

The main HTML tags are exported as ft partials.

+

Attributes are passed as keywords. Use ‘klass’ and ‘fr’ instead of ‘class’ and ‘for’, to avoid Python reserved word clashes.

+
+

source

+
+
+

Html

+
+
 Html (*c, doctype=True, **kwargs)
+
+

An HTML tag, optionally preceeded by !DOCTYPE HTML

+
+
samp = Html(
+    Head(Title('Some page')),
+    Body(Div('Some text\nanother line', Input(name='me'), Img(src="filename", data=1),
+             cls=['myclass', 'another'],
+             style={'padding':1, 'margin':2}))
+)
+pprint(samp)
+
+
(['!doctype', (), {'html': True}],
+ ['html',
+  (['head', (['title', ('Some page',), {}],), {}],
+   ['body',
+    (['div',
+      ('Some text\nanother line',
+       ['input', (), {'name': 'me'}],
+       ['img', (), {'data': 1, 'src': 'filename'}]),
+      {'class': 'myclass another', 'style': 'padding:1; margin:2'}],),
+    {}]),
+  {}])
+
+
+

The three elements of the list can also be accessed with property names, so you don’t have to remember their order.

+
+
elem = P('Some text', id="myid")
+print(elem.tag)
+print(elem.children)
+print(elem.attrs)
+
+
p
+('Some text',)
+{'id': 'myid'}
+
+
+

You can also get and set attrs directly:

+
+
elem.id = 'newid'
+print(elem.id, elem.get('id'), elem.get('foo', 'missing'))
+elem
+
+
newid newid missing
+
+
+
['p', ('Some text',), {'id': 'newid'}]
+
+
+
+

source

+
+
+

Safe

+

*str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

+

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.*

+
+

source

+
+
+

to_xml

+
+
 to_xml (elm, lvl=0, indent:bool=True)
+
+

Convert ft element tree into an XML string

+
+
h = to_xml(samp)
+print(h)
+
+
<!doctype html>
+
+<html>
+  <head>
+    <title>Some page</title>
+  </head>
+  <body>
+    <div class="myclass another" style="padding:1; margin:2">
+Some text
+another line
+      <input name="me">
+      <img src="filename" data="1">
+    </div>
+  </body>
+</html>
+
+
+
+
+
h = to_xml(samp, indent=False)
+print(h)
+
+
<!doctype html><html><head><title>Some page</title></head><body><div class="myclass another" style="padding:1; margin:2">Some text
+another line<input name="me"><img src="filename" data="1"></div></body></html>
+
+
+

Interoperability both directions with Django and Jinja using the html() protocol:

+
+
def _esc(s): return s.__html__() if hasattr(s, '__html__') else Safe(escape(s))
+
+r = Safe('<b>Hello from Django</b>')
+print(to_xml(Div(r)))
+print(_esc(Div(P('Hello from fastcore <3'))))
+
+
<div><b>Hello from Django</b></div>
+
+<div>
+  <p>Hello from fastcore &lt;3</p>
+</div>
+
+
+
+
+

source

+
+
+

highlight

+
+
 highlight (s, lang='html')
+
+

Markdown to syntax-highlight s in language lang

+
+

source

+
+
+

showtags

+
+
 showtags (s)
+
+
+

source

+
+
+

getattr

+
+
 __getattr__ (tag)
+
+
+

source

+
+
+

FT.__call__

+
+
 FT.__call__ (*c, **kw)
+
+

Call self as a function.

+

You can also reorder the children to come after the attrs, if you use this alternative syntax for FT where the children are in a second pair of () (behind the scenes this is because FT implements __call__ to add children).

+
+
Body(klass='myclass')(
+    Div(style='padding:3px')(
+        'Some text ',
+        I(spurious=True)('in italics'),
+        Input(name='me'),
+        Img(src="filename", data=1)
+    )
+)
+
+
<body class="myclass">
+  <div style="padding:3px">
+Some text 
+    <i spurious>in italics</i>
+    <input name="me">
+    <img src="filename" data="1">
+  </div>
+</body>
+
+
+ + +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/xtras.html b/xtras.html new file mode 100644 index 00000000..f148878a --- /dev/null +++ b/xtras.html @@ -0,0 +1,2176 @@ + + + + + + + + + + +Utility functions – fastcore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ + +
+ + + +
+ +
+
+

Utility functions

+
+ +
+
+ Utility functions used in the fastai library +
+
+ + +
+ + + + +
+ + + +
+ + + +
+

File Functions

+

Utilities (other than extensions to Pathlib.Path) for dealing with IO.

+
+

source

+
+

walk

+
+
 walk (path:pathlib.Path|str, symlinks:bool=True, keep_file:<built-
+       infunctioncallable>=<function ret_true>, keep_folder:<built-
+       infunctioncallable>=<function ret_true>, skip_folder:<built-
+       infunctioncallable>=<function ret_false>, func:<built-
+       infunctioncallable>=<function join>, ret_folders:bool=False)
+
+

Generator version of os.walk, using functions to filter files and folders

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
pathPath | strpath to start searching
symlinksboolTruefollow symlinks?
keep_filecallableret_truefunction that returns True for wanted files
keep_foldercallableret_truefunction that returns True for folders to enter
skip_foldercallableret_falsefunction that returns True for folders to skip
funccallablejoinfunction to apply to each matched file
ret_foldersboolFalsereturn folders, not just files
+
+

source

+
+
+

globtastic

+
+
 globtastic (path:pathlib.Path|str, recursive:bool=True,
+             symlinks:bool=True, file_glob:str=None, file_re:str=None,
+             folder_re:str=None, skip_file_glob:str=None,
+             skip_file_re:str=None, skip_folder_re:str=None, func:<built-
+             infunctioncallable>=<function join>, ret_folders:bool=False)
+
+

A more powerful glob, including regex matches, symlink handling, and skip parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
pathPath | strpath to start searching
recursiveboolTruesearch subfolders
symlinksboolTruefollow symlinks?
file_globstrNoneOnly include files matching glob
file_restrNoneOnly include files matching regex
folder_restrNoneOnly enter folders matching regex
skip_file_globstrNoneSkip files matching glob
skip_file_restrNoneSkip files matching regex
skip_folder_restrNoneSkip folders matching regex,
funccallablejoinfunction to apply to each matched file
ret_foldersboolFalsereturn folders, not just files
ReturnsLPaths to matched files
+
+
globtastic('.', skip_folder_re='^[_.]', folder_re='core', file_glob='*.*py*', file_re='c')
+
+
(#5) ['./fastcore/docments.py','./fastcore/dispatch.py','./fastcore/basics.py','./fastcore/docscrape.py','./fastcore/script.py']
+
+
+
+

source

+
+
+

maybe_open

+
+
 maybe_open (f, mode='r', **kwargs)
+
+

Context manager: open f if it is a path (and close on exit)

+

This is useful for functions where you want to accept a path or file. maybe_open will not close your file handle if you pass one in.

+
+
def _f(fn):
+    with maybe_open(fn) as f: return f.encoding
+
+fname = '00_test.ipynb'
+sys_encoding = 'cp1252' if sys.platform == 'win32' else 'UTF-8'
+test_eq(_f(fname), sys_encoding)
+with open(fname) as fh: test_eq(_f(fh), sys_encoding)
+
+

For example, we can use this to reimplement imghdr.what from the Python standard library, which is written in Python 3.9 as:

+
+
from fastcore import imghdr
+
+
+
def what(file, h=None):
+    f = None
+    try:
+        if h is None:
+            if isinstance(file, (str,os.PathLike)):
+                f = open(file, 'rb')
+                h = f.read(32)
+            else:
+                location = file.tell()
+                h = file.read(32)
+                file.seek(location)
+        for tf in imghdr.tests:
+            res = tf(h, f)
+            if res: return res
+    finally:
+        if f: f.close()
+    return None
+
+

Here’s an example of the use of this function:

+
+
fname = 'images/puppy.jpg'
+what(fname)
+
+
'jpeg'
+
+
+

With maybe_open, Self, and L.map_first, we can rewrite this in a much more concise and (in our opinion) clear way:

+
+
def what(file, h=None):
+    if h is None:
+        with maybe_open(file, 'rb') as f: h = f.peek(32)
+    return L(imghdr.tests).map_first(Self(h,file))
+
+

…and we can check that it still works:

+
+
test_eq(what(fname), 'jpeg')
+
+

…along with the version passing a file handle:

+
+
with open(fname,'rb') as f: test_eq(what(f), 'jpeg')
+
+

…along with the h parameter version:

+
+
with open(fname,'rb') as f: test_eq(what(None, h=f.read(32)), 'jpeg')
+
+
+

source

+
+
+

mkdir

+
+
 mkdir (path, exist_ok=False, parents=False, overwrite=False, **kwargs)
+
+

Creates and returns a directory defined by path, optionally removing previous existing directory if overwrite is True

+
+
with tempfile.TemporaryDirectory() as d:
+    path = Path(os.path.join(d, 'new_dir'))
+    new_dir = mkdir(path)
+    assert new_dir.exists()
+    test_eq(new_dir, path)
+        
+    # test overwrite
+    with open(new_dir/'test.txt', 'w') as f: f.writelines('test')
+    test_eq(len(list(walk(new_dir))), 1) # assert file is present
+    new_dir = mkdir(new_dir, overwrite=True)
+    test_eq(len(list(walk(new_dir))), 0) # assert file was deleted
+
+
+

source

+
+
+

image_size

+
+
 image_size (fn)
+
+

Tuple of (w,h) for png, gif, or jpg; None otherwise

+
+
test_eq(image_size(fname), (1200,803))
+
+
+

source

+
+
+

bunzip

+
+
 bunzip (fn)
+
+

bunzip fn, raising exception if output already exists

+
+
f = Path('files/test.txt')
+if f.exists(): f.unlink()
+bunzip('files/test.txt.bz2')
+t = f.open().readlines()
+test_eq(len(t),1)
+test_eq(t[0], 'test\n')
+f.unlink()
+
+
+

source

+
+
+

loads

+
+
 loads (s, **kw)
+
+

Same as json.loads, but handles None

+
+

source

+
+
+

loads_multi

+
+
 loads_multi (s:str)
+
+

Generator of >=0 decoded json dicts, possibly with non-json ignored text at start and end

+
+
tst = """
+# ignored
+{ "a":1 }
+hello
+{
+"b":2
+}
+"""
+
+test_eq(list(loads_multi(tst)), [{'a': 1}, {'b': 2}])
+
+
+

source

+
+
+

dumps

+
+
 dumps (obj, **kw)
+
+

Same as json.dumps, but uses ujson if available

+
+

source

+
+
+

untar_dir

+
+
 untar_dir (fname, dest, rename=False, overwrite=False)
+
+

untar file into dest, creating a directory if the root contains more than one item

+
+
def test_untar(foldername, rename=False, **kwargs):
+    with tempfile.TemporaryDirectory() as d:
+        nm = os.path.join(d, 'a')
+        shutil.make_archive(nm, 'gztar', **kwargs)
+        with tempfile.TemporaryDirectory() as d2:
+            d2 = Path(d2)
+            untar_dir(nm+'.tar.gz', d2, rename=rename)
+            test_eq(d2.ls(), [d2/foldername])
+
+

If the contents of fname contain just one file or directory, it is placed directly in dest:

+
+
# using `base_dir` in `make_archive` results in `images` directory included in file names
+test_untar('images', base_dir='images')
+
+

If rename then the directory created is named based on the archive, without extension:

+
+
test_untar('a', base_dir='images', rename=True)
+
+

If the contents of fname contain multiple files and directories, a new folder in dest is created with the same name as fname (but without extension):

+
+
# using `root_dir` in `make_archive` results in `images` directory *not* included in file names
+test_untar('a', root_dir='images')
+
+
+

source

+
+
+

repo_details

+
+
 repo_details (url)
+
+

Tuple of owner,name from ssh or https git repo url

+
+
test_eq(repo_details('https://github.com/fastai/fastai.git'), ['fastai', 'fastai'])
+test_eq(repo_details('git@github.com:fastai/nbdev.git\n'), ['fastai', 'nbdev'])
+
+
+

source

+
+
+

run

+
+
 run (cmd, *rest, same_in_win=False, ignore_ex=False, as_bytes=False,
+      stderr=False)
+
+

Pass cmd (splitting with shlex if string) to subprocess.run; return stdout; raise IOError if fails

+

You can pass a string (which will be split based on standard shell rules), a list, or pass args directly:

+
+
run('echo', same_in_win=True)
+run('pip', '--version', same_in_win=True)
+run(['pip', '--version'], same_in_win=True)
+
+
'pip 23.3.1 from /Users/jhoward/miniconda3/lib/python3.11/site-packages/pip (python 3.11)'
+
+
+
+
if sys.platform == 'win32':
+    assert 'ipynb' in run('cmd /c dir /p')
+    assert 'ipynb' in run(['cmd', '/c', 'dir', '/p'])
+    assert 'ipynb' in run('cmd', '/c', 'dir',  '/p')
+else:
+    assert 'ipynb' in run('ls -ls')
+    assert 'ipynb' in run(['ls', '-l'])
+    assert 'ipynb' in run('ls', '-l')
+
+

Some commands fail in non-error situations, like grep. Use ignore_ex in those cases, which will return a tuple of stdout and returncode:

+
+
if sys.platform == 'win32':
+    test_eq(run('cmd /c findstr asdfds 00_test.ipynb', ignore_ex=True)[0], 1)
+else:
+    test_eq(run('grep asdfds 00_test.ipynb', ignore_ex=True)[0], 1)
+
+

run automatically decodes returned bytes to a str. Use as_bytes to skip that:

+
+
if sys.platform == 'win32':
+    test_eq(run('cmd /c echo hi'), 'hi')
+else:
+    test_eq(run('echo hi', as_bytes=True), b'hi\n')
+
+
+

source

+
+
+

open_file

+
+
 open_file (fn, mode='r', **kwargs)
+
+

Open a file, with optional compression if gz or bz2 suffix

+
+

source

+
+
+

save_pickle

+
+
 save_pickle (fn, o)
+
+

Save a pickle file, to a file name or opened file

+
+

source

+
+
+

load_pickle

+
+
 load_pickle (fn)
+
+

Load a pickle file from a file name or opened file

+
+
for suf in '.pkl','.bz2','.gz':
+    # delete=False is added for Windows
+    # https://stackoverflow.com/questions/23212435/permission-denied-to-write-to-my-temporary-file
+    with tempfile.NamedTemporaryFile(suffix=suf, delete=False) as f:
+        fn = Path(f.name)
+        save_pickle(fn, 't')
+        t = load_pickle(fn)
+    f.close()
+    test_eq(t,'t')
+
+
+

source

+
+
+

parse_env

+
+
 parse_env (s:str=None, fn:Union[str,pathlib.Path]=None)
+
+

Parse a shell-style environment string or file

+
+
testf = """# comment
+   # another comment
+ export FOO="bar#baz"
+BAR=thing # comment "ok"
+  baz='thong'
+QUX=quux
+export ZAP = "zip" # more comments
+   FOOBAR = 42   # trailing space and comment"""
+
+exp = dict(FOO='bar#baz', BAR='thing', baz='thong', QUX='quux', ZAP='zip', FOOBAR='42')
+
+test_eq(parse_env(testf),  exp)
+
+
+

source

+
+
+

expand_wildcards

+
+
 expand_wildcards (code)
+
+

Expand all wildcard imports in the given code string.

+
+
inp = """from math import *
+from os import *
+from random import *
+def func(): return sin(pi) + path.join('a', 'b') + randint(1, 10)"""
+
+exp = """from math import pi, sin
+from os import path
+from random import randint
+def func(): return sin(pi) + path.join('a', 'b') + randint(1, 10)"""
+
+test_eq(expand_wildcards(inp), exp)
+
+inp = """from itertools import *
+def func(): pass"""
+test_eq(expand_wildcards(inp), inp)
+
+inp = """def outer():
+    from math import *
+    def inner():
+        from os import *
+        return sin(pi) + path.join('a', 'b')"""
+
+exp = """def outer():
+    from math import pi, sin
+    def inner():
+        from os import path
+        return sin(pi) + path.join('a', 'b')"""
+
+test_eq(expand_wildcards(inp), exp)
+
+
+
+
+

Collections

+
+

source

+
+

dict2obj

+
+
 dict2obj (d, list_func=<class 'fastcore.foundation.L'>, dict_func=<class
+           'fastcore.basics.AttrDict'>)
+
+

Convert (possibly nested) dicts (or lists of dicts) to AttrDict

+

This is a convenience to give you “dotted” access to (possibly nested) dictionaries, e.g:

+
+
d1 = dict(a=1, b=dict(c=2,d=3))
+d2 = dict2obj(d1)
+test_eq(d2.b.c, 2)
+test_eq(d2.b['c'], 2)
+
+

It can also be used on lists of dicts.

+
+
_list_of_dicts = [d1, d1]
+ds = dict2obj(_list_of_dicts)
+test_eq(ds[0].b.c, 2)
+
+
+

source

+
+
+

obj2dict

+
+
 obj2dict (d)
+
+

Convert (possibly nested) AttrDicts (or lists of AttrDicts) to dict

+

obj2dict can be used to reverse what is done by dict2obj:

+
+
test_eq(obj2dict(d2), d1)
+test_eq(obj2dict(ds), _list_of_dicts)
+
+
+

source

+
+
+

repr_dict

+
+
 repr_dict (d)
+
+

Print nested dicts and lists, such as returned by dict2obj

+
+
print(repr_dict(d2))
+
+
- a: 1
+- b: 
+  - c: 2
+  - d: 3
+
+
+
+

source

+
+
+

is_listy

+
+
 is_listy (x)
+
+

isinstance(x, (tuple,list,L,slice,Generator))

+
+
assert is_listy((1,))
+assert is_listy([1])
+assert is_listy(L([1]))
+assert is_listy(slice(2))
+assert not is_listy(array([1]))
+
+
+

source

+
+
+

mapped

+
+
 mapped (f, it)
+
+

map f over it, unless it’s not listy, in which case return f(it)

+
+
def _f(x,a=1): return x-a
+
+test_eq(mapped(_f,1),0)
+test_eq(mapped(_f,[1,2]),[0,1])
+test_eq(mapped(_f,(1,)),(0,))
+
+
+
+
+

Extensions to Pathlib.Path

+

The following methods are added to the standard python libary Pathlib.Path.

+
+

source

+
+

Path.readlines

+
+
 Path.readlines (hint=-1, encoding='utf8')
+
+

Read the content of self

+
+

source

+
+
+

Path.read_json

+
+
 Path.read_json (encoding=None, errors=None)
+
+

Same as read_text followed by loads

+
+

source

+
+
+

Path.mk_write

+
+
 Path.mk_write (data, encoding=None, errors=None, mode=511)
+
+

Make all parent dirs of self, and write data

+
+

source

+
+
+

Path.relpath

+
+
 Path.relpath (start=None)
+
+

Same as os.path.relpath, but returns a Path, and resolves symlinks

+
+
p = Path('../fastcore/').resolve()
+p
+
+
Path('/Users/jhoward/Documents/GitHub/fastcore/fastcore')
+
+
+
+
p.relpath(Path.cwd())
+
+
Path('../fastcore')
+
+
+
+

source

+
+
+

Path.ls

+
+
 Path.ls (n_max=None, file_type=None, file_exts=None)
+
+

Contents of path as a list

+

We add an ls() method to pathlib.Path which is simply defined as list(Path.iterdir()), mainly for convenience in REPL environments such as notebooks.

+
+
path = Path()
+t = path.ls()
+assert len(t)>0
+t1 = path.ls(10)
+test_eq(len(t1), 10)
+t2 = path.ls(file_exts='.ipynb')
+assert len(t)>len(t2)
+t[0]
+
+
Path('000_tour.ipynb')
+
+
+

You can also pass an optional file_type MIME prefix and/or a list of file extensions.

+
+
lib_path = (path/'../fastcore')
+txt_files=lib_path.ls(file_type='text')
+assert len(txt_files) > 0 and txt_files[0].suffix=='.py'
+ipy_files=path.ls(file_exts=['.ipynb'])
+assert len(ipy_files) > 0 and ipy_files[0].suffix=='.ipynb'
+txt_files[0],ipy_files[0]
+
+
(Path('../fastcore/shutil.py'), Path('000_tour.ipynb'))
+
+
+
+

source

+
+
+

Path.__repr__

+
+
 Path.__repr__ ()
+
+

Return repr(self).

+

fastai also updates the repr of Path such that, if Path.BASE_PATH is defined, all paths are printed relative to that path (as long as they are contained in Path.BASE_PATH:

+
+
t = ipy_files[0].absolute()
+try:
+    Path.BASE_PATH = t.parent.parent
+    test_eq(repr(t), f"Path('nbs/{t.name}')")
+finally: Path.BASE_PATH = None
+
+
+

source

+
+
+

Path.delete

+
+
 Path.delete ()
+
+

Delete a file, symlink, or directory tree

+
+
+
+

Reindexing Collections

+
+

source

+
+

ReindexCollection

+
+
 ReindexCollection (coll, idxs=None, cache=None, tfm=<function noop>)
+
+

Reindexes collection coll with indices idxs and optional LRU cache of size cache

+

This is useful when constructing batches or organizing data in a particular manner (i.e. for deep learning). This class is primarly used in organizing data for language models in fastai.

+

You can supply a custom index upon instantiation with the idxs argument, or you can call the reindex method to supply a new index for your collection.

+

Here is how you can reindex a list such that the elements are reversed:

+
+
rc=ReindexCollection(['a', 'b', 'c', 'd', 'e'], idxs=[4,3,2,1,0])
+list(rc)
+
+
['e', 'd', 'c', 'b', 'a']
+
+
+

Alternatively, you can use the reindex method:

+
+

source

+
+
ReindexCollection.reindex
+
+
 ReindexCollection.reindex (idxs)
+
+

Replace self.idxs with idxs

+
+
rc=ReindexCollection(['a', 'b', 'c', 'd', 'e'])
+rc.reindex([4,3,2,1,0])
+list(rc)
+
+
['e', 'd', 'c', 'b', 'a']
+
+
+

You can optionally specify a LRU cache, which uses functools.lru_cache upon instantiation:

+
+
sz = 50
+t = ReindexCollection(L.range(sz), cache=2)
+
+#trigger a cache hit by indexing into the same element multiple times
+t[0], t[0]
+t._get.cache_info()
+
+
CacheInfo(hits=1, misses=1, maxsize=2, currsize=1)
+
+
+

You can optionally clear the LRU cache by calling the cache_clear method:

+
+

source

+
+
+
ReindexCollection.cache_clear
+
+
 ReindexCollection.cache_clear ()
+
+

Clear LRU cache

+
+
sz = 50
+t = ReindexCollection(L.range(sz), cache=2)
+
+#trigger a cache hit by indexing into the same element multiple times
+t[0], t[0]
+t.cache_clear()
+t._get.cache_info()
+
+
CacheInfo(hits=0, misses=0, maxsize=2, currsize=0)
+
+
+
+

source

+
+
+
ReindexCollection.shuffle
+
+
 ReindexCollection.shuffle ()
+
+

Randomly shuffle indices

+

Note that an ordered index is automatically constructed for the data structure even if one is not supplied.

+
+
rc=ReindexCollection(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
+rc.shuffle()
+list(rc)
+
+
['a', 'h', 'f', 'b', 'c', 'g', 'e', 'd']
+
+
+
+
sz = 50
+t = ReindexCollection(L.range(sz), cache=2)
+test_eq(list(t), range(sz))
+test_eq(t[sz-1], sz-1)
+test_eq(t._get.cache_info().hits, 1)
+t.shuffle()
+test_eq(t._get.cache_info().hits, 1)
+test_ne(list(t), range(sz))
+test_eq(set(t), set(range(sz)))
+t.cache_clear()
+test_eq(t._get.cache_info().hits, 0)
+test_eq(t.count(0), 1)
+
+
+
+
+
+

Other Helpers

+
+

source

+ +
+

truncstr

+
+
 truncstr (s:str, maxlen:int, suf:str='…', space='')
+
+

Truncate s to length maxlen, adding suffix suf if truncated

+
+
w = 'abacadabra'
+test_eq(truncstr(w, 10), w)
+test_eq(truncstr(w, 5), 'abac…')
+test_eq(truncstr(w, 5, suf=''), 'abaca')
+test_eq(truncstr(w, 11, space='_'), w+"_")
+test_eq(truncstr(w, 10, space='_'), w[:-1]+'…')
+test_eq(truncstr(w, 5, suf='!!'), 'aba!!')
+
+
+

source

+
+
+

sparkline

+
+
 sparkline (data, mn=None, mx=None, empty_zero=False)
+
+

Sparkline for data, with Nones (and zero, if empty_zero) shown as empty column

+
+
data = [9,6,None,1,4,0,8,15,10]
+print(f'without "empty_zero": {sparkline(data, empty_zero=False)}')
+print(f'   with "empty_zero": {sparkline(data, empty_zero=True )}')
+
+
without "empty_zero": ▅▂ ▁▂▁▃▇▅
+   with "empty_zero": ▅▂ ▁▂ ▃▇▅
+
+
+

You can set a maximum and minimum for the y-axis of the sparkline with the arguments mn and mx respectively:

+
+
sparkline([1,2,3,400], mn=0, mx=3)
+
+
'▂▅▇▇'
+
+
+
+

source

+
+
+

modify_exception

+
+
 modify_exception (e:Exception, msg:str=None, replace:bool=False)
+
+

Modifies e with a custom message attached

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDefaultDetails
eExceptionAn exception
msgstrNoneA custom message
replaceboolFalseWhether to replace e.args with [msg]
ReturnsException
+
+
msg = "This is my custom message!"
+
+test_fail(lambda: (_ for _ in ()).throw(modify_exception(Exception(), None)), contains='')
+test_fail(lambda: (_ for _ in ()).throw(modify_exception(Exception(), msg)), contains=msg)
+test_fail(lambda: (_ for _ in ()).throw(modify_exception(Exception("The first message"), msg)), contains="The first message This is my custom message!")
+test_fail(lambda: (_ for _ in ()).throw(modify_exception(Exception("The first message"), msg, True)), contains="This is my custom message!")
+
+
+

source

+
+
+

round_multiple

+
+
 round_multiple (x, mult, round_down=False)
+
+

Round x to nearest multiple of mult

+
+
test_eq(round_multiple(63,32), 64)
+test_eq(round_multiple(50,32), 64)
+test_eq(round_multiple(40,32), 32)
+test_eq(round_multiple( 0,32),  0)
+test_eq(round_multiple(63,32, round_down=True), 32)
+test_eq(round_multiple((63,40),32), (64,32))
+
+
+

source

+
+
+

set_num_threads

+
+
 set_num_threads (nt)
+
+

Get numpy (and others) to use nt threads

+

This sets the number of threads consistently for many tools, by:

+
    +
  1. Set the following environment variables equal to nt: OPENBLAS_NUM_THREADS,NUMEXPR_NUM_THREADS,OMP_NUM_THREADS,MKL_NUM_THREADS
  2. +
  3. Sets nt threads for numpy and pytorch.
  4. +
+
+

source

+
+
+

join_path_file

+
+
 join_path_file (file, path, ext='')
+
+

Return path/file if file is a string or a Path, file otherwise

+
+
path = Path.cwd()/'_tmp'/'tst'
+f = join_path_file('tst.txt', path)
+assert path.exists()
+test_eq(f, path/'tst.txt')
+with open(f, 'w') as f_: assert join_path_file(f_, path) == f_
+shutil.rmtree(Path.cwd()/'_tmp')
+
+
+

source

+
+
+

autostart

+
+
 autostart (g)
+
+

Decorator that automatically starts a generator

+
+

source

+
+

EventTimer

+
+
 EventTimer (store=5, span=60)
+
+

An event timer with history of store items of time span

+

Add events with add, and get number of events and their frequency (freq).

+
+
# Random wait function for testing
+def _randwait(): yield from (sleep(random.random()/200) for _ in range(100))
+
+c = EventTimer(store=5, span=0.03)
+for o in _randwait(): c.add(1)
+print(f'Num Events: {c.events}, Freq/sec: {c.freq:.01f}')
+print('Most recent: ', sparkline(c.hist), *L(c.hist).map('{:.01f}'))
+
+
Num Events: 3, Freq/sec: 316.2
+Most recent:  ▇▁▂▃▁ 288.7 227.7 246.5 256.5 217.9
+
+
+
+

source

+
+
+
+

stringfmt_names

+
+
 stringfmt_names (s:str)
+
+

Unique brace-delimited names in s

+
+
s = '/pulls/{pull_number}/reviews/{review_id}'
+test_eq(stringfmt_names(s), ['pull_number','review_id'])
+
+
+

source

+
+

PartialFormatter

+
+
 PartialFormatter ()
+
+

A string.Formatter that doesn’t error on missing fields, and tracks missing fields and unused args

+
+

source

+
+
+
+

partial_format

+
+
 partial_format (s:str, **kwargs)
+
+

string format s, ignoring missing field errors, returning missing and extra fields

+

The result is a tuple of (formatted_string,missing_fields,extra_fields), e.g:

+
+
res,missing,xtra = partial_format(s, pull_number=1, foo=2)
+test_eq(res, '/pulls/1/reviews/{review_id}')
+test_eq(missing, ['review_id'])
+test_eq(xtra, {'foo':2})
+
+
+

source

+
+
+

utc2local

+
+
 utc2local (dt:datetime.datetime)
+
+

Convert dt from UTC to local time

+
+
dt = datetime(2000,1,1,12)
+print(f'{dt} UTC is {utc2local(dt)} local time')
+
+
2000-01-01 12:00:00 UTC is 2000-01-01 22:00:00+10:00 local time
+
+
+
+

source

+
+
+

local2utc

+
+
 local2utc (dt:datetime.datetime)
+
+

Convert dt from local to UTC time

+
+
print(f'{dt} local is {local2utc(dt)} UTC time')
+
+
2000-01-01 12:00:00 local is 2000-01-01 02:00:00+00:00 UTC time
+
+
+
+

source

+
+
+

trace

+
+
 trace (f)
+
+

Add set_trace to an existing function f

+

You can add a breakpoint to an existing function, e.g:

+
Path.cwd = trace(Path.cwd)
+Path.cwd()
+

Now, when the function is called it will drop you into the debugger. Note, you must issue the s command when you begin to step into the function that is being traced.

+
+

source

+
+
+

modified_env

+
+
 modified_env (*delete, **replace)
+
+

Context manager temporarily modifying os.environ by deleting delete and replacing replace

+
+
# USER isn't in Cloud Linux Environments
+env_test = 'USERNAME' if sys.platform == "win32" else 'SHELL'
+oldusr = os.environ[env_test]
+
+replace_param = {env_test: 'a'}
+with modified_env('PATH', **replace_param):
+    test_eq(os.environ[env_test], 'a')
+    assert 'PATH' not in os.environ
+
+assert 'PATH' in os.environ
+test_eq(os.environ[env_test], oldusr)
+
+
+

source

+
+

ContextManagers

+
+
 ContextManagers (mgrs)
+
+

Wrapper for contextlib.ExitStack which enters a collection of context managers

+
+

source

+
+
+
+

shufflish

+
+
 shufflish (x, pct=0.04)
+
+

Randomly relocate items of x up to pct of len(x) from their starting location

+
+

source

+
+
+

console_help

+
+
 console_help (libname:str)
+
+

Show help for all console scripts from libname

+ + + + + + + + + + + + + + + +
TypeDetails
libnamestrname of library for console script listing
+
+

source

+
+
+

hl_md

+
+
 hl_md (s, lang='xml', show=True)
+
+

Syntax highlight s using lang.

+

When we display code in a notebook, it’s nice to highlight it, so we create a function to simplify that:

+
+
hl_md('<test><xml foo="bar">a child</xml></test>')
+
+
<test><xml foo="bar">a child</xml></test>
+
+
+
+

source

+
+
+

type2str

+
+
 type2str (typ:type)
+
+

Stringify typ

+
+
test_eq(type2str(Optional[float]), 'Union[float, None]')
+
+
+

source

+
+
+

dataclass_src

+
+
 dataclass_src (cls)
+
+
+
from dataclasses import make_dataclass, dataclass
+
+
+
DC = make_dataclass('DC', [('x', int), ('y', Optional[float], None), ('z', float, None)])
+print(dataclass_src(DC))
+
+
@dataclass
+class DC:
+    x: int
+    y: Union[float, None] = None
+    z: float = None
+
+
+
+
+

source

+
+
+

nullable_dc

+
+
 nullable_dc (cls)
+
+

Like dataclass, but default of None added to fields without defaults

+
+
@nullable_dc
+class Person: name: str; age: int; city: str = "Unknown"
+Person(name="Bob")
+
+
Person(name='Bob', age=None, city='Unknown')
+
+
+
+

source

+
+
+

make_nullable

+
+
 make_nullable (clas)
+
+
+
@dataclass
+class Person: name: str; age: int; city: str = "Unknown"
+
+make_nullable(Person)
+Person("Bob", city='NY')
+
+
Person(name='Bob', age=None, city='NY')
+
+
+
+
Person(name="Bob")
+
+
Person(name='Bob', age=None, city='Unknown')
+
+
+
+
Person("Bob", 34)
+
+
Person(name='Bob', age=34, city='Unknown')
+
+
+
+

source

+
+
+

mk_dataclass

+
+
 mk_dataclass (cls)
+
+
+
class Person: name: str; age: int; city: str = "Unknown"
+
+mk_dataclass(Person)
+Person(name="Bob")
+
+
Person(name='Bob', age=None, city='Unknown')
+
+
+
+

source

+
+
+

flexicache

+
+
 flexicache (*funcs, maxsize=128)
+
+

Like lru_cache, but customisable with policy funcs

+

This is a flexible lru cache function that you can pass a list of functions to. Those functions define the cache eviction policy. For instance, time_policy is provided for time-based cache eviction, and mtime_policy evicts based on a file’s modified-time changing. The policy functions are passed the last value that function returned was (initially None), and return a new value to indicate the cache has expired. When the cache expires, all functions are called with None to force getting new values.

+
+

source

+
+
+

time_policy

+
+
 time_policy (seconds)
+
+

A flexicache policy that expires cached items after seconds have passed

+
+

source

+
+
+

mtime_policy

+
+
 mtime_policy (filepath)
+
+

A flexicache policy that expires cached items after filepath modified-time changes

+
+
@flexicache(time_policy(10), mtime_policy('000_tour.ipynb'))
+def cached_func(x, y): return x+y
+
+cached_func(1,2)
+
+
3
+
+
+
+
@flexicache(time_policy(10), mtime_policy('000_tour.ipynb'))
+async def cached_func(x, y): return x+y
+
+await cached_func(1,2)
+await cached_func(1,2)
+
+
3
+
+
+
+

source

+
+
+

timed_cache

+
+
 timed_cache (seconds=60, maxsize=128)
+
+

Like lru_cache, but also with time-based eviction

+

This function is a small convenience wrapper for using flexicache with time_policy.

+
+
@timed_cache(seconds=0.05, maxsize=2)
+def cached_func(x): return x * 2, time()
+
+# basic caching
+result1, time1 = cached_func(2)
+test_eq(result1, 4)
+sleep(0.001)
+result2, time2 = cached_func(2)
+test_eq(result2, 4)
+test_eq(time1, time2)
+
+# caching different values
+result3, _ = cached_func(3)
+test_eq(result3, 6)
+
+# maxsize
+_, time4 = cached_func(4)
+_, time2_new = cached_func(2)
+test_close(time2, time2_new, eps=0.1)
+_, time3_new = cached_func(3)
+test_ne(time3_new, time())
+
+# time expiration
+sleep(0.05)
+_, time4_new = cached_func(4)
+test_ne(time4_new, time())
+
+ + +
+
+ +
+ +
+ + + + + \ No newline at end of file