diff --git a/0.7.5/.buildinfo b/0.7.5/.buildinfo new file mode 100644 index 00000000..29a7dbfc --- /dev/null +++ b/0.7.5/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file records the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 6a98a1844afd97517a90e0191ea0c5a4 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/0.7.5/.doctrees/_api.doctree b/0.7.5/.doctrees/_api.doctree new file mode 100644 index 00000000..c0283d08 Binary files /dev/null and b/0.7.5/.doctrees/_api.doctree differ diff --git a/0.7.5/.doctrees/_api/scanspec.core.doctree b/0.7.5/.doctrees/_api/scanspec.core.doctree new file mode 100644 index 00000000..016a62ed Binary files /dev/null and b/0.7.5/.doctrees/_api/scanspec.core.doctree differ diff --git a/0.7.5/.doctrees/_api/scanspec.doctree b/0.7.5/.doctrees/_api/scanspec.doctree new file mode 100644 index 00000000..79a89a76 Binary files /dev/null and b/0.7.5/.doctrees/_api/scanspec.doctree differ diff --git a/0.7.5/.doctrees/_api/scanspec.plot.doctree b/0.7.5/.doctrees/_api/scanspec.plot.doctree new file mode 100644 index 00000000..f630d7a6 Binary files /dev/null and b/0.7.5/.doctrees/_api/scanspec.plot.doctree differ diff --git a/0.7.5/.doctrees/_api/scanspec.regions.doctree b/0.7.5/.doctrees/_api/scanspec.regions.doctree new file mode 100644 index 00000000..3b34577b Binary files /dev/null and b/0.7.5/.doctrees/_api/scanspec.regions.doctree differ diff --git a/0.7.5/.doctrees/_api/scanspec.specs.doctree b/0.7.5/.doctrees/_api/scanspec.specs.doctree new file mode 100644 index 00000000..0a1e3027 Binary files /dev/null and b/0.7.5/.doctrees/_api/scanspec.specs.doctree differ diff --git a/0.7.5/.doctrees/explanations.doctree b/0.7.5/.doctrees/explanations.doctree new file mode 100644 index 00000000..18293956 Binary files /dev/null and b/0.7.5/.doctrees/explanations.doctree differ diff --git a/0.7.5/.doctrees/explanations/decisions.doctree b/0.7.5/.doctrees/explanations/decisions.doctree new file mode 100644 index 00000000..f1656e72 Binary files /dev/null and b/0.7.5/.doctrees/explanations/decisions.doctree differ diff --git a/0.7.5/.doctrees/explanations/decisions/0001-record-architecture-decisions.doctree b/0.7.5/.doctrees/explanations/decisions/0001-record-architecture-decisions.doctree new file mode 100644 index 00000000..edd68666 Binary files /dev/null and b/0.7.5/.doctrees/explanations/decisions/0001-record-architecture-decisions.doctree differ diff --git a/0.7.5/.doctrees/explanations/decisions/0002-switched-to-python-copier-template.doctree b/0.7.5/.doctrees/explanations/decisions/0002-switched-to-python-copier-template.doctree new file mode 100644 index 00000000..45bc27f6 Binary files /dev/null and b/0.7.5/.doctrees/explanations/decisions/0002-switched-to-python-copier-template.doctree differ diff --git a/0.7.5/.doctrees/explanations/technical-terms.doctree b/0.7.5/.doctrees/explanations/technical-terms.doctree new file mode 100644 index 00000000..ee9ddaa2 Binary files /dev/null and b/0.7.5/.doctrees/explanations/technical-terms.doctree differ diff --git a/0.7.5/.doctrees/explanations/why-squash-can-change-path.doctree b/0.7.5/.doctrees/explanations/why-squash-can-change-path.doctree new file mode 100644 index 00000000..de62a98d Binary files /dev/null and b/0.7.5/.doctrees/explanations/why-squash-can-change-path.doctree differ diff --git a/0.7.5/.doctrees/explanations/why-stack-frames.doctree b/0.7.5/.doctrees/explanations/why-stack-frames.doctree new file mode 100644 index 00000000..9f2f1986 Binary files /dev/null and b/0.7.5/.doctrees/explanations/why-stack-frames.doctree differ diff --git a/0.7.5/.doctrees/genindex.doctree b/0.7.5/.doctrees/genindex.doctree new file mode 100644 index 00000000..148feca7 Binary files /dev/null and b/0.7.5/.doctrees/genindex.doctree differ diff --git a/0.7.5/.doctrees/how-to.doctree b/0.7.5/.doctrees/how-to.doctree new file mode 100644 index 00000000..da1cdc52 Binary files /dev/null and b/0.7.5/.doctrees/how-to.doctree differ diff --git a/0.7.5/.doctrees/how-to/contribute.doctree b/0.7.5/.doctrees/how-to/contribute.doctree new file mode 100644 index 00000000..92a08d4c Binary files /dev/null and b/0.7.5/.doctrees/how-to/contribute.doctree differ diff --git a/0.7.5/.doctrees/how-to/iterate-a-spec.doctree b/0.7.5/.doctrees/how-to/iterate-a-spec.doctree new file mode 100644 index 00000000..e43cf3f7 Binary files /dev/null and b/0.7.5/.doctrees/how-to/iterate-a-spec.doctree differ diff --git a/0.7.5/.doctrees/how-to/run-container.doctree b/0.7.5/.doctrees/how-to/run-container.doctree new file mode 100644 index 00000000..9b6974c6 Binary files /dev/null and b/0.7.5/.doctrees/how-to/run-container.doctree differ diff --git a/0.7.5/.doctrees/how-to/serialize-a-spec.doctree b/0.7.5/.doctrees/how-to/serialize-a-spec.doctree new file mode 100644 index 00000000..fed2ac42 Binary files /dev/null and b/0.7.5/.doctrees/how-to/serialize-a-spec.doctree differ diff --git a/0.7.5/.doctrees/index.doctree b/0.7.5/.doctrees/index.doctree new file mode 100644 index 00000000..561bf7f3 Binary files /dev/null and b/0.7.5/.doctrees/index.doctree differ diff --git a/0.7.5/.doctrees/reference.doctree b/0.7.5/.doctrees/reference.doctree new file mode 100644 index 00000000..7dfeadbd Binary files /dev/null and b/0.7.5/.doctrees/reference.doctree differ diff --git a/0.7.5/.doctrees/reference/rest_api.doctree b/0.7.5/.doctrees/reference/rest_api.doctree new file mode 100644 index 00000000..311c7932 Binary files /dev/null and b/0.7.5/.doctrees/reference/rest_api.doctree differ diff --git a/0.7.5/.doctrees/tutorials.doctree b/0.7.5/.doctrees/tutorials.doctree new file mode 100644 index 00000000..7288d4d6 Binary files /dev/null and b/0.7.5/.doctrees/tutorials.doctree differ diff --git a/0.7.5/.doctrees/tutorials/creating-a-spec.doctree b/0.7.5/.doctrees/tutorials/creating-a-spec.doctree new file mode 100644 index 00000000..2f6b6ae5 Binary files /dev/null and b/0.7.5/.doctrees/tutorials/creating-a-spec.doctree differ diff --git a/0.7.5/.doctrees/tutorials/installation.doctree b/0.7.5/.doctrees/tutorials/installation.doctree new file mode 100644 index 00000000..aa523e68 Binary files /dev/null and b/0.7.5/.doctrees/tutorials/installation.doctree differ diff --git a/0.7.5/.doctrees/tutorials/rest-service.doctree b/0.7.5/.doctrees/tutorials/rest-service.doctree new file mode 100644 index 00000000..c76ec141 Binary files /dev/null and b/0.7.5/.doctrees/tutorials/rest-service.doctree differ diff --git a/0.7.5/_api.html b/0.7.5/_api.html new file mode 100644 index 00000000..5ea61722 --- /dev/null +++ b/0.7.5/_api.html @@ -0,0 +1,566 @@ + + + + + + + + + + + API — scanspec 0.7.5 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
+
+
+
+ +
+ +
+ + + + + +
+
+ + + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

API#

+
+ + + + + +

scanspec

Top level API.

+
+
+ + +
+ + + + + +
+ +
+
+
+ +
+ + + +
+ + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/0.7.5/_api/scanspec.core.html b/0.7.5/_api/scanspec.core.html new file mode 100644 index 00000000..45990535 --- /dev/null +++ b/0.7.5/_api/scanspec.core.html @@ -0,0 +1,1095 @@ + + + + + + + + + + + scanspec.core — scanspec 0.7.5 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
+
+
+
+ +
+ +
+ + + + + +
+
+ + + +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

scanspec.core#

+

Core classes like Frames and Path.

+

Members

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

Axis

A type variable for an Axis that can be specified for a scan

OtherAxis

Alternative axis variable to be used when two are required in the same type binding

if_instance_do

If x is of type cls then return func(x), otherwise return NotImplemented.

AxesPoints

Map of axes to float ndarray of points E.g.

Frames

Represents a series of scan frames along a number of axes.

SnakedFrames

Like a Frames object, but each alternate repetition will run in reverse.

gap_between_frames

Is there a gap between end of frames1 and start of frames2.

squash_frames

Squash a stack of nested Frames into a single one.

Path

A consumable route through a stack of Frames, representing a scan path.

Midpoints

Convenience iterable that produces the scan midpoints for each axis.

discriminated_union_of_subclasses

Add all subclasses of super_cls to a discriminated union.

StrictConfig

Used to ensure pydantic dataclasses error if given extra arguments

+
+
+
+class scanspec.core.Axis#
+

A type variable for an Axis that can be specified for a scan

+

alias of TypeVar(‘Axis’, covariant=True)

+
+ +
+
+class scanspec.core.OtherAxis#
+

Alternative axis variable to be used when two are required in the same type binding

+

alias of TypeVar(‘OtherAxis’)

+
+ +
+
+scanspec.core.if_instance_do(x: C, cls: type[C], func: Callable[[C], T]) T[source]#
+

If x is of type cls then return func(x), otherwise return NotImplemented.

+

Used as a helper when implementing operator overloading.

+
+ +
+
+scanspec.core.AxesPoints#
+

Map of axes to float ndarray of points +E.g. {xmotor: array([0, 1, 2]), ymotor: array([2, 2, 2])}

+

alias of dict[Axis, ndarray[Any, dtype[floating[Any]]]]

+
+ +
+
+class scanspec.core.Frames(midpoints: dict[Axis, ndarray[Any, dtype[floating[Any]]]], lower: dict[Axis, ndarray[Any, dtype[floating[Any]]]] | None = None, upper: dict[Axis, ndarray[Any, dtype[floating[Any]]]] | None = None, gap: ndarray[Any, dtype[bool]] | None = None)[source]#
+

Represents a series of scan frames along a number of axes.

+

During a scan each axis will traverse lower-midpoint-upper for each frame.

+
+
Parameters:
+
    +
  • midpoints – The midpoints of scan frames for each axis

  • +
  • lower – Lower bounds of scan frames if different from midpoints

  • +
  • upper – Upper bounds of scan frames if different from midpoints

  • +
  • gap – If supplied, define if there is a gap between frame and previous +otherwise it is calculated by looking at lower and upper bounds

  • +
+
+
+

Typically used in two ways:

+
    +
  • A list of Frames objects returned from Spec.calculate represents a scan +as a linear stack of frames. Interpreted as nested from slowest moving to +fastest moving, so each faster Frames object will iterate once per +position of the slower Frames object. It is passed to a Path for +calculation of the actual scan path.

  • +
  • A single Frames object returned from Path.consume represents a chunk of +frames forming part of a scan path, for interpretation by the code +that will actually perform the scan.

  • +
+
+

See also

+

Technical Terms

+
+
+
+midpoints#
+

The midpoints of scan frames for each axis

+
+ +
+
+lower#
+

The lower bounds of each scan frame in each axis for fly-scanning

+
+ +
+
+upper#
+

The upper bounds of each scan frame in each axis for fly-scanning

+
+ +
+
+gap#
+

Whether there is a gap between this frame and the previous. First +element is whether there is a gap between the last frame and the first

+
+ +
+
+axes() list[Axis][source]#
+

The axes which will move during the scan.

+

These will be present in midpoints, lower and upper.

+
+ +
+
+extract(indices: ndarray[Any, dtype[signedinteger[Any]]], calculate_gap: bool = True) Frames[Axis][source]#
+

Return a new Frames object restricted to the indices provided.

+
+
Parameters:
+
    +
  • indices – The indices of the frames to extract, modulo scan length

  • +
  • calculate_gap – If True then recalculate the gap from upper and lower

  • +
+
+
+
>>> frames = Frames({"x": np.array([1, 2, 3])})
+>>> frames.extract(np.array([1, 0, 1])).midpoints
+{'x': array([2, 1, 2])}
+
+
+
+ +
+
+concat(other: Frames[Axis], gap: bool = False) Frames[Axis][source]#
+

Return a new Frames object concatenating self and other.

+

Requires both Frames objects to have the same axes, but not necessarily in +the same order. The order is inherited from self, so other may be reordered.

+
+
Parameters:
+
    +
  • other – The Frames to concatenate to self

  • +
  • gap – Whether to force a gap between the two Frames objects

  • +
+
+
+
>>> frames = Frames({"x": np.array([1, 2, 3]), "y": np.array([6, 5, 4])})
+>>> frames2 = Frames({"y": np.array([3, 2, 1]), "x": np.array([4, 5, 6])})
+>>> frames.concat(frames2).midpoints
+{'x': array([1, 2, 3, 4, 5, 6]), 'y': array([6, 5, 4, 3, 2, 1])}
+
+
+
+ +
+
+zip(other: Frames[Axis]) Frames[Axis][source]#
+

Return a new Frames object merging self and other.

+

Require both Frames objects to not share axes.

+
>>> fx = Frames({"x": np.array([1, 2, 3])})
+>>> fy = Frames({"y": np.array([5, 6, 7])})
+>>> fx.zip(fy).midpoints
+{'x': array([1, 2, 3]), 'y': array([5, 6, 7])}
+
+
+
+ +
+ +
+
+class scanspec.core.SnakedFrames(midpoints: dict[Axis, ndarray[Any, dtype[floating[Any]]]], lower: dict[Axis, ndarray[Any, dtype[floating[Any]]]] | None = None, upper: dict[Axis, ndarray[Any, dtype[floating[Any]]]] | None = None, gap: ndarray[Any, dtype[bool]] | None = None)[source]#
+

Like a Frames object, but each alternate repetition will run in reverse.

+
+
+classmethod from_frames(frames: Frames[OtherAxis]) SnakedFrames[OtherAxis][source]#
+

Create a snaked version of a Frames object.

+
+ +
+
+extract(indices: ndarray[Any, dtype[signedinteger[Any]]], calculate_gap: bool = True) Frames[Axis][source]#
+

Return a new Frames object restricted to the indices provided.

+
+
Parameters:
+
    +
  • indices – The indices of the frames to extract, can extend past len(self)

  • +
  • calculate_gap – If True then recalculate the gap from upper and lower

  • +
+
+
+
>>> frames = SnakedFrames({"x": np.array([1, 2, 3])})
+>>> frames.extract(np.array([0, 1, 2, 3, 4, 5])).midpoints
+{'x': array([1, 2, 3, 3, 2, 1])}
+
+
+
+ +
+ +
+
+scanspec.core.gap_between_frames(frames1: Frames[Axis], frames2: Frames[Axis]) bool[source]#
+

Is there a gap between end of frames1 and start of frames2.

+
+ +
+
+scanspec.core.squash_frames(stack: list[Frames[Axis]], check_path_changes: bool = True) Frames[Axis][source]#
+

Squash a stack of nested Frames into a single one.

+
+
Parameters:
+
    +
  • stack – The Frames stack to squash, from slowest to fastest moving

  • +
  • check_path_changes – If True then check that nesting the output +Frames object within others will provide the same path +as nesting the input Frames stack within others

  • +
+
+
+ +
>>> fx = SnakedFrames({"x": np.array([1, 2])})
+>>> fy = Frames({"y": np.array([3, 4])})
+>>> squash_frames([fy, fx]).midpoints
+{'y': array([3, 3, 4, 4]), 'x': array([1, 2, 2, 1])}
+
+
+
+ +
+
+class scanspec.core.Path(stack: list[Frames[Axis]], start: int = 0, num: int | None = None)[source]#
+

A consumable route through a stack of Frames, representing a scan path.

+
+
Parameters:
+
    +
  • stack – The Frames stack describing the scan, from slowest to fastest +moving

  • +
  • start – The index of where in the Path to start

  • +
  • num – The number of scan frames to produce after start. None means up to +the end

  • +
+
+
+
+

See also

+

How to Iterate a Spec

+
+
+
+stack#
+

The Frames stack describing the scan, from slowest to fastest moving

+
+ +
+
+index#
+

Index that is next to be consumed

+
+ +
+
+lengths#
+

The lengths of all the stack

+
+ +
+
+end_index#
+

Index of the end frame, one more than the last index that will be +produced

+
+ +
+
+consume(num: int | None = None) Frames[Axis][source]#
+

Consume at most num frames from the Path and return as a Frames object.

+
>>> fx = SnakedFrames({"x": np.array([1, 2])})
+>>> fy = Frames({"y": np.array([3, 4])})
+>>> path = Path([fy, fx])
+>>> path.consume(3).midpoints
+{'y': array([3, 3, 4]), 'x': array([1, 2, 2])}
+>>> path.consume(3).midpoints
+{'y': array([4]), 'x': array([1])}
+>>> path.consume(3).midpoints
+{'y': array([], dtype=int64), 'x': array([], dtype=int64)}
+
+
+
+ +
+ +
+
+class scanspec.core.Midpoints(stack: list[Frames[Axis]])[source]#
+

Convenience iterable that produces the scan midpoints for each axis.

+

For better performance, consume from a Path instead.

+
+
Parameters:
+

stack – The stack of Frames describing the scan, from slowest to fastest +moving

+
+
+
+

See also

+

How to Iterate a Spec

+
+
>>> fx = SnakedFrames({"x": np.array([1, 2])})
+>>> fy = Frames({"y": np.array([3, 4])})
+>>> mp = Midpoints([fy, fx])
+>>> for p in mp: print(p)
+{'y': np.int64(3), 'x': np.int64(1)}
+{'y': np.int64(3), 'x': np.int64(2)}
+{'y': np.int64(4), 'x': np.int64(2)}
+{'y': np.int64(4), 'x': np.int64(1)}
+
+
+
+
+stack#
+

The stack of Frames describing the scan, from slowest to fastest moving

+
+ +
+
+property axes: list[Axis]#
+

The axes that will be present in each points dictionary.

+
+ +
+ +
+
+scanspec.core.discriminated_union_of_subclasses(super_cls: type[C], discriminator: str = 'type') type[C][source]#
+

Add all subclasses of super_cls to a discriminated union.

+

For all subclasses of super_cls, add a discriminator field to identify +the type. Raw JSON should look like {<discriminator>: <type name>, params for +<type name>…}.

+

Subclasses that extend this class must be Pydantic dataclasses, and types that +need their schema to be updated when a new type that extends super_cls is +created must be either Pydantic dataclasses or BaseModels.

+

Example:

+
@discriminated_union_of_subclasses
+class Expression(ABC):
+    @abstractmethod
+    def calculate(self) -> int:
+        ...
+
+
+@dataclass
+class Add(Expression):
+    left: Expression
+    right: Expression
+
+    def calculate(self) -> int:
+        return self.left.calculate() + self.right.calculate()
+
+
+@dataclass
+class Subtract(Expression):
+    left: Expression
+    right: Expression
+
+    def calculate(self) -> int:
+        return self.left.calculate() - self.right.calculate()
+
+
+@dataclass
+class IntLiteral(Expression):
+    value: int
+
+    def calculate(self) -> int:
+        return self.value
+
+
+my_sum = Add(IntLiteral(5), Subtract(IntLiteral(10), IntLiteral(2)))
+assert my_sum.calculate() == 13
+
+assert my_sum == parse_obj_as(
+    Expression,
+    {
+        "type": "Add",
+        "left": {"type": "IntLiteral", "value": 5},
+        "right": {
+            "type": "Subtract",
+            "left": {"type": "IntLiteral", "value": 10},
+            "right": {"type": "IntLiteral", "value": 2},
+        },
+    },
+)
+
+
+
+
Parameters:
+
    +
  • super_cls – The superclass of the union, Expression in the above example

  • +
  • discriminator – The discriminator that will be inserted into the +serialized documents for type determination. Defaults to “type”.

  • +
+
+
Returns:
+

+
decorated superclass with handling for subclasses to be added

to its discriminated union for deserialization

+
+
+

+
+
Return type:
+

Type

+
+
+
+ +
+
+scanspec.core.StrictConfig: ConfigDict = {'extra': 'forbid'}#
+

Used to ensure pydantic dataclasses error if given extra arguments

+
+ +
+ + +
+ + + + + + + +
+ + + + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/0.7.5/_api/scanspec.html b/0.7.5/_api/scanspec.html new file mode 100644 index 00000000..8a37260f --- /dev/null +++ b/0.7.5/_api/scanspec.html @@ -0,0 +1,637 @@ + + + + + + + + + + + scanspec — scanspec 0.7.5 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
+
+
+
+ +
+ +
+ + + + + +
+
+ + + +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + + + + + + + + + +
+ + + +
+ + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/0.7.5/_api/scanspec.plot.html b/0.7.5/_api/scanspec.plot.html new file mode 100644 index 00000000..3f23d58b --- /dev/null +++ b/0.7.5/_api/scanspec.plot.html @@ -0,0 +1,649 @@ + + + + + + + + + + + scanspec.plot — scanspec 0.7.5 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
+
+
+
+ +
+ +
+ + + + + +
+
+ + + +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

scanspec.plot#

+

plot_spec to visualize a scan.

+

Members

+
+ + + + + +

plot_spec

Plot a spec, drawing the path taken through the scan.

+
+
+
+scanspec.plot.plot_spec(spec: Spec[Any], title: str | None = None)[source]#
+

Plot a spec, drawing the path taken through the scan.

+

Uses a different colour for each frame, grey for the turnarounds, and +marks the midpoints with a filled circle if there are less than 200 of +them. If the scan is 2D then 2D regions are shown in black.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Line
+from scanspec.regions import Circle
+
+cube = Line("z", 1, 3, 3) * Line("y", 1, 3, 10) * ~Line("x", 0, 2, 10)
+spec = cube & Circle("x", "y", 1, 2, 0.9)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-plot-1.png +
+
+ +
+ + +
+ + + + + + + +
+ + + +
+ + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/0.7.5/_api/scanspec.regions.html b/0.7.5/_api/scanspec.regions.html new file mode 100644 index 00000000..3b97c5a5 --- /dev/null +++ b/0.7.5/_api/scanspec.regions.html @@ -0,0 +1,3972 @@ + + + + + + + + + + + scanspec.regions — scanspec 0.7.5 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
+
+
+
+ +
+ +
+ + + + + +
+
+ + + +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

scanspec.regions#

+

Region and its subclasses.

+
+

Inheritance diagram of scanspec.regions

+

Members

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

Region

Abstract baseclass for a Region that can Mask a Spec.

get_mask

Return a mask of the points inside the region.

find_regions

Recursively yield Regions from obj and its children.

+
+
+
+class scanspec.regions.Region[source]#
+

Abstract baseclass for a Region that can Mask a Spec.

+

Supports operators:

+ +
+
+axis_sets() list[set[Axis]][source]#
+

Produce the non-overlapping sets of axes this region spans.

+
+ +
+
+mask(points: dict[Axis, ndarray[Any, dtype[floating[Any]]]]) ndarray[Any, dtype[bool]][source]#
+

Produce a mask of which points are in the region.

+
+ +
+
+serialize() Mapping[str, Any][source]#
+

Serialize the Region to a dictionary.

+
+ +
+
+static deserialize(obj: Any) Region[Any][source]#
+

Deserialize a Region from a dictionary.

+
+ +
+ +
+
+scanspec.regions.get_mask(region: Region[Axis], points: dict[Axis, ndarray[Any, dtype[floating[Any]]]]) ndarray[Any, dtype[bool]][source]#
+

Return a mask of the points inside the region.

+

If there is an overlap of axes of region and points return a +mask of the points in the region, otherwise return all ones

+
+ +
+
+pydantic model scanspec.regions.CombinationOf[source]#
+

Abstract baseclass for a combination of two regions, left and right.

+

+Show JSON schema
{
+   "$defs": {
+      "Circle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the circle",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the circle",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "radius": {
+               "description": "Radius of the circle",
+               "exclusiveMinimum": 0.0,
+               "title": "Radius",
+               "type": "number"
+            },
+            "type": {
+               "const": "Circle",
+               "default": "Circle",
+               "enum": [
+                  "Circle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "radius"
+         ],
+         "title": "Circle",
+         "type": "object"
+      },
+      "CombinationOf": {
+         "additionalProperties": false,
+         "description": "Abstract baseclass for a combination of two regions, left and right.",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "CombinationOf",
+               "default": "CombinationOf",
+               "enum": [
+                  "CombinationOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "CombinationOf",
+         "type": "object"
+      },
+      "DifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "DifferenceOf",
+               "default": "DifferenceOf",
+               "enum": [
+                  "DifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "DifferenceOf",
+         "type": "object"
+      },
+      "Ellipse": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the ellipse",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the ellipse",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "x_radius": {
+               "description": "The radius along the x axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "X Radius",
+               "type": "number"
+            },
+            "y_radius": {
+               "description": "The radius along the y axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "Y Radius",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "The angle of the ellipse (degrees)",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Ellipse",
+               "default": "Ellipse",
+               "enum": [
+                  "Ellipse"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "x_radius",
+            "y_radius"
+         ],
+         "title": "Ellipse",
+         "type": "object"
+      },
+      "IntersectionOf": {
+         "additionalProperties": false,
+         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "IntersectionOf",
+               "default": "IntersectionOf",
+               "enum": [
+                  "IntersectionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "IntersectionOf",
+         "type": "object"
+      },
+      "Polygon": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_verts": {
+               "description": "The Nx1 x coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "X Verts",
+               "type": "array"
+            },
+            "y_verts": {
+               "description": "The Nx1 y coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "Y Verts",
+               "type": "array"
+            },
+            "type": {
+               "const": "Polygon",
+               "default": "Polygon",
+               "enum": [
+                  "Polygon"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_verts",
+            "y_verts"
+         ],
+         "title": "Polygon",
+         "type": "object"
+      },
+      "Range": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
+         "properties": {
+            "axis": {
+               "description": "The name matching the axis to mask in spec",
+               "title": "Axis"
+            },
+            "min": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Min",
+               "type": "number"
+            },
+            "max": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Max",
+               "type": "number"
+            },
+            "type": {
+               "const": "Range",
+               "default": "Range",
+               "enum": [
+                  "Range"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "min",
+            "max"
+         ],
+         "title": "Range",
+         "type": "object"
+      },
+      "Rectangle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_min": {
+               "description": "Minimum inclusive x value in the region",
+               "title": "X Min",
+               "type": "number"
+            },
+            "y_min": {
+               "description": "Minimum inclusive y value in the region",
+               "title": "Y Min",
+               "type": "number"
+            },
+            "x_max": {
+               "description": "Maximum inclusive x value in the region",
+               "title": "X Max",
+               "type": "number"
+            },
+            "y_max": {
+               "description": "Maximum inclusive y value in the region",
+               "title": "Y Max",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "Clockwise rotation angle of the rectangle",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Rectangle",
+               "default": "Rectangle",
+               "enum": [
+                  "Rectangle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_min",
+            "y_min",
+            "x_max",
+            "y_max"
+         ],
+         "title": "Rectangle",
+         "type": "object"
+      },
+      "Region": {
+         "discriminator": {
+            "mapping": {
+               "Circle": "#/$defs/Circle",
+               "CombinationOf": "#/$defs/CombinationOf",
+               "DifferenceOf": "#/$defs/DifferenceOf",
+               "Ellipse": "#/$defs/Ellipse",
+               "IntersectionOf": "#/$defs/IntersectionOf",
+               "Polygon": "#/$defs/Polygon",
+               "Range": "#/$defs/Range",
+               "Rectangle": "#/$defs/Rectangle",
+               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
+               "UnionOf": "#/$defs/UnionOf"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/CombinationOf"
+            },
+            {
+               "$ref": "#/$defs/UnionOf"
+            },
+            {
+               "$ref": "#/$defs/IntersectionOf"
+            },
+            {
+               "$ref": "#/$defs/DifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/SymmetricDifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/Range"
+            },
+            {
+               "$ref": "#/$defs/Rectangle"
+            },
+            {
+               "$ref": "#/$defs/Polygon"
+            },
+            {
+               "$ref": "#/$defs/Circle"
+            },
+            {
+               "$ref": "#/$defs/Ellipse"
+            }
+         ]
+      },
+      "SymmetricDifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "SymmetricDifferenceOf",
+               "default": "SymmetricDifferenceOf",
+               "enum": [
+                  "SymmetricDifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "SymmetricDifferenceOf",
+         "type": "object"
+      },
+      "UnionOf": {
+         "additionalProperties": false,
+         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "UnionOf",
+               "default": "UnionOf",
+               "enum": [
+                  "UnionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "UnionOf",
+         "type": "object"
+      }
+   },
+   "$ref": "#/$defs/CombinationOf"
+}
+
+
+

+
Fields:
+
+
+
+
+
+field left: Region[Axis] [Required]#
+

The left-hand Region to combine

+
+ +
+
+field right: Region[Axis] [Required]#
+

The right-hand Region to combine

+
+ +
+
+field type: Literal['CombinationOf'] = 'CombinationOf'#
+
+ +
+
+axis_sets() list[set[Axis]][source]#
+

Produce the non-overlapping sets of axes this region spans.

+
+ +
+ +
+
+pydantic model scanspec.regions.UnionOf[source]#
+

A point is in UnionOf(a, b) if in either a or b.

+

Typically created with the | operator

+
>>> r = Range("x", 0.5, 2.5) | Range("x", 1.5, 3.5)
+>>> r.mask({"x": np.array([0, 1, 2, 3, 4])})
+array([False,  True,  True,  True, False])
+
+
+

+Show JSON schema
{
+   "$defs": {
+      "Circle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the circle",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the circle",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "radius": {
+               "description": "Radius of the circle",
+               "exclusiveMinimum": 0.0,
+               "title": "Radius",
+               "type": "number"
+            },
+            "type": {
+               "const": "Circle",
+               "default": "Circle",
+               "enum": [
+                  "Circle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "radius"
+         ],
+         "title": "Circle",
+         "type": "object"
+      },
+      "CombinationOf": {
+         "additionalProperties": false,
+         "description": "Abstract baseclass for a combination of two regions, left and right.",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "CombinationOf",
+               "default": "CombinationOf",
+               "enum": [
+                  "CombinationOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "CombinationOf",
+         "type": "object"
+      },
+      "DifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "DifferenceOf",
+               "default": "DifferenceOf",
+               "enum": [
+                  "DifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "DifferenceOf",
+         "type": "object"
+      },
+      "Ellipse": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the ellipse",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the ellipse",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "x_radius": {
+               "description": "The radius along the x axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "X Radius",
+               "type": "number"
+            },
+            "y_radius": {
+               "description": "The radius along the y axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "Y Radius",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "The angle of the ellipse (degrees)",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Ellipse",
+               "default": "Ellipse",
+               "enum": [
+                  "Ellipse"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "x_radius",
+            "y_radius"
+         ],
+         "title": "Ellipse",
+         "type": "object"
+      },
+      "IntersectionOf": {
+         "additionalProperties": false,
+         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "IntersectionOf",
+               "default": "IntersectionOf",
+               "enum": [
+                  "IntersectionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "IntersectionOf",
+         "type": "object"
+      },
+      "Polygon": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_verts": {
+               "description": "The Nx1 x coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "X Verts",
+               "type": "array"
+            },
+            "y_verts": {
+               "description": "The Nx1 y coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "Y Verts",
+               "type": "array"
+            },
+            "type": {
+               "const": "Polygon",
+               "default": "Polygon",
+               "enum": [
+                  "Polygon"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_verts",
+            "y_verts"
+         ],
+         "title": "Polygon",
+         "type": "object"
+      },
+      "Range": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
+         "properties": {
+            "axis": {
+               "description": "The name matching the axis to mask in spec",
+               "title": "Axis"
+            },
+            "min": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Min",
+               "type": "number"
+            },
+            "max": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Max",
+               "type": "number"
+            },
+            "type": {
+               "const": "Range",
+               "default": "Range",
+               "enum": [
+                  "Range"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "min",
+            "max"
+         ],
+         "title": "Range",
+         "type": "object"
+      },
+      "Rectangle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_min": {
+               "description": "Minimum inclusive x value in the region",
+               "title": "X Min",
+               "type": "number"
+            },
+            "y_min": {
+               "description": "Minimum inclusive y value in the region",
+               "title": "Y Min",
+               "type": "number"
+            },
+            "x_max": {
+               "description": "Maximum inclusive x value in the region",
+               "title": "X Max",
+               "type": "number"
+            },
+            "y_max": {
+               "description": "Maximum inclusive y value in the region",
+               "title": "Y Max",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "Clockwise rotation angle of the rectangle",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Rectangle",
+               "default": "Rectangle",
+               "enum": [
+                  "Rectangle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_min",
+            "y_min",
+            "x_max",
+            "y_max"
+         ],
+         "title": "Rectangle",
+         "type": "object"
+      },
+      "Region": {
+         "discriminator": {
+            "mapping": {
+               "Circle": "#/$defs/Circle",
+               "CombinationOf": "#/$defs/CombinationOf",
+               "DifferenceOf": "#/$defs/DifferenceOf",
+               "Ellipse": "#/$defs/Ellipse",
+               "IntersectionOf": "#/$defs/IntersectionOf",
+               "Polygon": "#/$defs/Polygon",
+               "Range": "#/$defs/Range",
+               "Rectangle": "#/$defs/Rectangle",
+               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
+               "UnionOf": "#/$defs/UnionOf"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/CombinationOf"
+            },
+            {
+               "$ref": "#/$defs/UnionOf"
+            },
+            {
+               "$ref": "#/$defs/IntersectionOf"
+            },
+            {
+               "$ref": "#/$defs/DifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/SymmetricDifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/Range"
+            },
+            {
+               "$ref": "#/$defs/Rectangle"
+            },
+            {
+               "$ref": "#/$defs/Polygon"
+            },
+            {
+               "$ref": "#/$defs/Circle"
+            },
+            {
+               "$ref": "#/$defs/Ellipse"
+            }
+         ]
+      },
+      "SymmetricDifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "SymmetricDifferenceOf",
+               "default": "SymmetricDifferenceOf",
+               "enum": [
+                  "SymmetricDifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "SymmetricDifferenceOf",
+         "type": "object"
+      },
+      "UnionOf": {
+         "additionalProperties": false,
+         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "UnionOf",
+               "default": "UnionOf",
+               "enum": [
+                  "UnionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "UnionOf",
+         "type": "object"
+      }
+   },
+   "$ref": "#/$defs/UnionOf"
+}
+
+
+

+
Fields:
+
+
+
+
+
+field left: Region[Axis] [Required]#
+

The left-hand Region to combine

+
+ +
+
+field right: Region[Axis] [Required]#
+

The right-hand Region to combine

+
+ +
+
+field type: Literal['UnionOf'] = 'UnionOf'#
+
+ +
+
+mask(points: dict[Axis, ndarray[Any, dtype[floating[Any]]]]) ndarray[Any, dtype[bool]][source]#
+

Produce a mask of which points are in the region.

+
+ +
+ +
+
+pydantic model scanspec.regions.IntersectionOf[source]#
+

A point is in IntersectionOf(a, b) if in both a and b.

+

Typically created with the & operator.

+
>>> r = Range("x", 0.5, 2.5) & Range("x", 1.5, 3.5)
+>>> r.mask({"x": np.array([0, 1, 2, 3, 4])})
+array([False, False,  True, False, False])
+
+
+

+Show JSON schema
{
+   "$defs": {
+      "Circle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the circle",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the circle",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "radius": {
+               "description": "Radius of the circle",
+               "exclusiveMinimum": 0.0,
+               "title": "Radius",
+               "type": "number"
+            },
+            "type": {
+               "const": "Circle",
+               "default": "Circle",
+               "enum": [
+                  "Circle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "radius"
+         ],
+         "title": "Circle",
+         "type": "object"
+      },
+      "CombinationOf": {
+         "additionalProperties": false,
+         "description": "Abstract baseclass for a combination of two regions, left and right.",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "CombinationOf",
+               "default": "CombinationOf",
+               "enum": [
+                  "CombinationOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "CombinationOf",
+         "type": "object"
+      },
+      "DifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "DifferenceOf",
+               "default": "DifferenceOf",
+               "enum": [
+                  "DifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "DifferenceOf",
+         "type": "object"
+      },
+      "Ellipse": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the ellipse",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the ellipse",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "x_radius": {
+               "description": "The radius along the x axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "X Radius",
+               "type": "number"
+            },
+            "y_radius": {
+               "description": "The radius along the y axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "Y Radius",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "The angle of the ellipse (degrees)",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Ellipse",
+               "default": "Ellipse",
+               "enum": [
+                  "Ellipse"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "x_radius",
+            "y_radius"
+         ],
+         "title": "Ellipse",
+         "type": "object"
+      },
+      "IntersectionOf": {
+         "additionalProperties": false,
+         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "IntersectionOf",
+               "default": "IntersectionOf",
+               "enum": [
+                  "IntersectionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "IntersectionOf",
+         "type": "object"
+      },
+      "Polygon": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_verts": {
+               "description": "The Nx1 x coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "X Verts",
+               "type": "array"
+            },
+            "y_verts": {
+               "description": "The Nx1 y coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "Y Verts",
+               "type": "array"
+            },
+            "type": {
+               "const": "Polygon",
+               "default": "Polygon",
+               "enum": [
+                  "Polygon"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_verts",
+            "y_verts"
+         ],
+         "title": "Polygon",
+         "type": "object"
+      },
+      "Range": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
+         "properties": {
+            "axis": {
+               "description": "The name matching the axis to mask in spec",
+               "title": "Axis"
+            },
+            "min": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Min",
+               "type": "number"
+            },
+            "max": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Max",
+               "type": "number"
+            },
+            "type": {
+               "const": "Range",
+               "default": "Range",
+               "enum": [
+                  "Range"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "min",
+            "max"
+         ],
+         "title": "Range",
+         "type": "object"
+      },
+      "Rectangle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_min": {
+               "description": "Minimum inclusive x value in the region",
+               "title": "X Min",
+               "type": "number"
+            },
+            "y_min": {
+               "description": "Minimum inclusive y value in the region",
+               "title": "Y Min",
+               "type": "number"
+            },
+            "x_max": {
+               "description": "Maximum inclusive x value in the region",
+               "title": "X Max",
+               "type": "number"
+            },
+            "y_max": {
+               "description": "Maximum inclusive y value in the region",
+               "title": "Y Max",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "Clockwise rotation angle of the rectangle",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Rectangle",
+               "default": "Rectangle",
+               "enum": [
+                  "Rectangle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_min",
+            "y_min",
+            "x_max",
+            "y_max"
+         ],
+         "title": "Rectangle",
+         "type": "object"
+      },
+      "Region": {
+         "discriminator": {
+            "mapping": {
+               "Circle": "#/$defs/Circle",
+               "CombinationOf": "#/$defs/CombinationOf",
+               "DifferenceOf": "#/$defs/DifferenceOf",
+               "Ellipse": "#/$defs/Ellipse",
+               "IntersectionOf": "#/$defs/IntersectionOf",
+               "Polygon": "#/$defs/Polygon",
+               "Range": "#/$defs/Range",
+               "Rectangle": "#/$defs/Rectangle",
+               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
+               "UnionOf": "#/$defs/UnionOf"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/CombinationOf"
+            },
+            {
+               "$ref": "#/$defs/UnionOf"
+            },
+            {
+               "$ref": "#/$defs/IntersectionOf"
+            },
+            {
+               "$ref": "#/$defs/DifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/SymmetricDifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/Range"
+            },
+            {
+               "$ref": "#/$defs/Rectangle"
+            },
+            {
+               "$ref": "#/$defs/Polygon"
+            },
+            {
+               "$ref": "#/$defs/Circle"
+            },
+            {
+               "$ref": "#/$defs/Ellipse"
+            }
+         ]
+      },
+      "SymmetricDifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "SymmetricDifferenceOf",
+               "default": "SymmetricDifferenceOf",
+               "enum": [
+                  "SymmetricDifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "SymmetricDifferenceOf",
+         "type": "object"
+      },
+      "UnionOf": {
+         "additionalProperties": false,
+         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "UnionOf",
+               "default": "UnionOf",
+               "enum": [
+                  "UnionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "UnionOf",
+         "type": "object"
+      }
+   },
+   "$ref": "#/$defs/IntersectionOf"
+}
+
+
+

+
Fields:
+
+
+
+
+
+field left: Region[Axis] [Required]#
+

The left-hand Region to combine

+
+ +
+
+field right: Region[Axis] [Required]#
+

The right-hand Region to combine

+
+ +
+
+field type: Literal['IntersectionOf'] = 'IntersectionOf'#
+
+ +
+
+mask(points: dict[Axis, ndarray[Any, dtype[floating[Any]]]]) ndarray[Any, dtype[bool]][source]#
+

Produce a mask of which points are in the region.

+
+ +
+ +
+
+pydantic model scanspec.regions.DifferenceOf[source]#
+

A point is in DifferenceOf(a, b) if in a and not in b.

+

Typically created with the - operator.

+
>>> r = Range("x", 0.5, 2.5) - Range("x", 1.5, 3.5)
+>>> r.mask({"x": np.array([0, 1, 2, 3, 4])})
+array([False,  True, False, False, False])
+
+
+

+Show JSON schema
{
+   "$defs": {
+      "Circle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the circle",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the circle",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "radius": {
+               "description": "Radius of the circle",
+               "exclusiveMinimum": 0.0,
+               "title": "Radius",
+               "type": "number"
+            },
+            "type": {
+               "const": "Circle",
+               "default": "Circle",
+               "enum": [
+                  "Circle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "radius"
+         ],
+         "title": "Circle",
+         "type": "object"
+      },
+      "CombinationOf": {
+         "additionalProperties": false,
+         "description": "Abstract baseclass for a combination of two regions, left and right.",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "CombinationOf",
+               "default": "CombinationOf",
+               "enum": [
+                  "CombinationOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "CombinationOf",
+         "type": "object"
+      },
+      "DifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "DifferenceOf",
+               "default": "DifferenceOf",
+               "enum": [
+                  "DifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "DifferenceOf",
+         "type": "object"
+      },
+      "Ellipse": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the ellipse",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the ellipse",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "x_radius": {
+               "description": "The radius along the x axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "X Radius",
+               "type": "number"
+            },
+            "y_radius": {
+               "description": "The radius along the y axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "Y Radius",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "The angle of the ellipse (degrees)",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Ellipse",
+               "default": "Ellipse",
+               "enum": [
+                  "Ellipse"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "x_radius",
+            "y_radius"
+         ],
+         "title": "Ellipse",
+         "type": "object"
+      },
+      "IntersectionOf": {
+         "additionalProperties": false,
+         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "IntersectionOf",
+               "default": "IntersectionOf",
+               "enum": [
+                  "IntersectionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "IntersectionOf",
+         "type": "object"
+      },
+      "Polygon": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_verts": {
+               "description": "The Nx1 x coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "X Verts",
+               "type": "array"
+            },
+            "y_verts": {
+               "description": "The Nx1 y coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "Y Verts",
+               "type": "array"
+            },
+            "type": {
+               "const": "Polygon",
+               "default": "Polygon",
+               "enum": [
+                  "Polygon"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_verts",
+            "y_verts"
+         ],
+         "title": "Polygon",
+         "type": "object"
+      },
+      "Range": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
+         "properties": {
+            "axis": {
+               "description": "The name matching the axis to mask in spec",
+               "title": "Axis"
+            },
+            "min": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Min",
+               "type": "number"
+            },
+            "max": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Max",
+               "type": "number"
+            },
+            "type": {
+               "const": "Range",
+               "default": "Range",
+               "enum": [
+                  "Range"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "min",
+            "max"
+         ],
+         "title": "Range",
+         "type": "object"
+      },
+      "Rectangle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_min": {
+               "description": "Minimum inclusive x value in the region",
+               "title": "X Min",
+               "type": "number"
+            },
+            "y_min": {
+               "description": "Minimum inclusive y value in the region",
+               "title": "Y Min",
+               "type": "number"
+            },
+            "x_max": {
+               "description": "Maximum inclusive x value in the region",
+               "title": "X Max",
+               "type": "number"
+            },
+            "y_max": {
+               "description": "Maximum inclusive y value in the region",
+               "title": "Y Max",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "Clockwise rotation angle of the rectangle",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Rectangle",
+               "default": "Rectangle",
+               "enum": [
+                  "Rectangle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_min",
+            "y_min",
+            "x_max",
+            "y_max"
+         ],
+         "title": "Rectangle",
+         "type": "object"
+      },
+      "Region": {
+         "discriminator": {
+            "mapping": {
+               "Circle": "#/$defs/Circle",
+               "CombinationOf": "#/$defs/CombinationOf",
+               "DifferenceOf": "#/$defs/DifferenceOf",
+               "Ellipse": "#/$defs/Ellipse",
+               "IntersectionOf": "#/$defs/IntersectionOf",
+               "Polygon": "#/$defs/Polygon",
+               "Range": "#/$defs/Range",
+               "Rectangle": "#/$defs/Rectangle",
+               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
+               "UnionOf": "#/$defs/UnionOf"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/CombinationOf"
+            },
+            {
+               "$ref": "#/$defs/UnionOf"
+            },
+            {
+               "$ref": "#/$defs/IntersectionOf"
+            },
+            {
+               "$ref": "#/$defs/DifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/SymmetricDifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/Range"
+            },
+            {
+               "$ref": "#/$defs/Rectangle"
+            },
+            {
+               "$ref": "#/$defs/Polygon"
+            },
+            {
+               "$ref": "#/$defs/Circle"
+            },
+            {
+               "$ref": "#/$defs/Ellipse"
+            }
+         ]
+      },
+      "SymmetricDifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "SymmetricDifferenceOf",
+               "default": "SymmetricDifferenceOf",
+               "enum": [
+                  "SymmetricDifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "SymmetricDifferenceOf",
+         "type": "object"
+      },
+      "UnionOf": {
+         "additionalProperties": false,
+         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "UnionOf",
+               "default": "UnionOf",
+               "enum": [
+                  "UnionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "UnionOf",
+         "type": "object"
+      }
+   },
+   "$ref": "#/$defs/DifferenceOf"
+}
+
+
+

+
Fields:
+
+
+
+
+
+field left: Region[Axis] [Required]#
+

The left-hand Region to combine

+
+ +
+
+field right: Region[Axis] [Required]#
+

The right-hand Region to combine

+
+ +
+
+field type: Literal['DifferenceOf'] = 'DifferenceOf'#
+
+ +
+
+mask(points: dict[Axis, ndarray[Any, dtype[floating[Any]]]]) ndarray[Any, dtype[bool]][source]#
+

Produce a mask of which points are in the region.

+
+ +
+ +
+
+pydantic model scanspec.regions.SymmetricDifferenceOf[source]#
+

A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.

+

Typically created with the ^ operator.

+
>>> r = Range("x", 0.5, 2.5) ^ Range("x", 1.5, 3.5)
+>>> r.mask({"x": np.array([0, 1, 2, 3, 4])})
+array([False,  True, False,  True, False])
+
+
+

+Show JSON schema
{
+   "$defs": {
+      "Circle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the circle",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the circle",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "radius": {
+               "description": "Radius of the circle",
+               "exclusiveMinimum": 0.0,
+               "title": "Radius",
+               "type": "number"
+            },
+            "type": {
+               "const": "Circle",
+               "default": "Circle",
+               "enum": [
+                  "Circle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "radius"
+         ],
+         "title": "Circle",
+         "type": "object"
+      },
+      "CombinationOf": {
+         "additionalProperties": false,
+         "description": "Abstract baseclass for a combination of two regions, left and right.",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "CombinationOf",
+               "default": "CombinationOf",
+               "enum": [
+                  "CombinationOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "CombinationOf",
+         "type": "object"
+      },
+      "DifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "DifferenceOf",
+               "default": "DifferenceOf",
+               "enum": [
+                  "DifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "DifferenceOf",
+         "type": "object"
+      },
+      "Ellipse": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the ellipse",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the ellipse",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "x_radius": {
+               "description": "The radius along the x axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "X Radius",
+               "type": "number"
+            },
+            "y_radius": {
+               "description": "The radius along the y axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "Y Radius",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "The angle of the ellipse (degrees)",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Ellipse",
+               "default": "Ellipse",
+               "enum": [
+                  "Ellipse"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "x_radius",
+            "y_radius"
+         ],
+         "title": "Ellipse",
+         "type": "object"
+      },
+      "IntersectionOf": {
+         "additionalProperties": false,
+         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "IntersectionOf",
+               "default": "IntersectionOf",
+               "enum": [
+                  "IntersectionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "IntersectionOf",
+         "type": "object"
+      },
+      "Polygon": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_verts": {
+               "description": "The Nx1 x coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "X Verts",
+               "type": "array"
+            },
+            "y_verts": {
+               "description": "The Nx1 y coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "Y Verts",
+               "type": "array"
+            },
+            "type": {
+               "const": "Polygon",
+               "default": "Polygon",
+               "enum": [
+                  "Polygon"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_verts",
+            "y_verts"
+         ],
+         "title": "Polygon",
+         "type": "object"
+      },
+      "Range": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
+         "properties": {
+            "axis": {
+               "description": "The name matching the axis to mask in spec",
+               "title": "Axis"
+            },
+            "min": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Min",
+               "type": "number"
+            },
+            "max": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Max",
+               "type": "number"
+            },
+            "type": {
+               "const": "Range",
+               "default": "Range",
+               "enum": [
+                  "Range"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "min",
+            "max"
+         ],
+         "title": "Range",
+         "type": "object"
+      },
+      "Rectangle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_min": {
+               "description": "Minimum inclusive x value in the region",
+               "title": "X Min",
+               "type": "number"
+            },
+            "y_min": {
+               "description": "Minimum inclusive y value in the region",
+               "title": "Y Min",
+               "type": "number"
+            },
+            "x_max": {
+               "description": "Maximum inclusive x value in the region",
+               "title": "X Max",
+               "type": "number"
+            },
+            "y_max": {
+               "description": "Maximum inclusive y value in the region",
+               "title": "Y Max",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "Clockwise rotation angle of the rectangle",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Rectangle",
+               "default": "Rectangle",
+               "enum": [
+                  "Rectangle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_min",
+            "y_min",
+            "x_max",
+            "y_max"
+         ],
+         "title": "Rectangle",
+         "type": "object"
+      },
+      "Region": {
+         "discriminator": {
+            "mapping": {
+               "Circle": "#/$defs/Circle",
+               "CombinationOf": "#/$defs/CombinationOf",
+               "DifferenceOf": "#/$defs/DifferenceOf",
+               "Ellipse": "#/$defs/Ellipse",
+               "IntersectionOf": "#/$defs/IntersectionOf",
+               "Polygon": "#/$defs/Polygon",
+               "Range": "#/$defs/Range",
+               "Rectangle": "#/$defs/Rectangle",
+               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
+               "UnionOf": "#/$defs/UnionOf"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/CombinationOf"
+            },
+            {
+               "$ref": "#/$defs/UnionOf"
+            },
+            {
+               "$ref": "#/$defs/IntersectionOf"
+            },
+            {
+               "$ref": "#/$defs/DifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/SymmetricDifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/Range"
+            },
+            {
+               "$ref": "#/$defs/Rectangle"
+            },
+            {
+               "$ref": "#/$defs/Polygon"
+            },
+            {
+               "$ref": "#/$defs/Circle"
+            },
+            {
+               "$ref": "#/$defs/Ellipse"
+            }
+         ]
+      },
+      "SymmetricDifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "SymmetricDifferenceOf",
+               "default": "SymmetricDifferenceOf",
+               "enum": [
+                  "SymmetricDifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "SymmetricDifferenceOf",
+         "type": "object"
+      },
+      "UnionOf": {
+         "additionalProperties": false,
+         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "UnionOf",
+               "default": "UnionOf",
+               "enum": [
+                  "UnionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "UnionOf",
+         "type": "object"
+      }
+   },
+   "$ref": "#/$defs/SymmetricDifferenceOf"
+}
+
+
+

+
Fields:
+
+
+
+
+
+field left: Region[Axis] [Required]#
+

The left-hand Region to combine

+
+ +
+
+field right: Region[Axis] [Required]#
+

The right-hand Region to combine

+
+ +
+
+field type: Literal['SymmetricDifferenceOf'] = 'SymmetricDifferenceOf'#
+
+ +
+
+mask(points: dict[Axis, ndarray[Any, dtype[floating[Any]]]]) ndarray[Any, dtype[bool]][source]#
+

Produce a mask of which points are in the region.

+
+ +
+ +
+
+pydantic model scanspec.regions.Range[source]#
+

Mask contains points of axis >= min and <= max.

+
>>> r = Range("x", 1, 2)
+>>> r.mask({"x": np.array([0, 1, 2, 3, 4])})
+array([False,  True,  True, False, False])
+
+
+

+Show JSON schema
{
+   "title": "Range",
+   "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
+   "type": "object",
+   "properties": {
+      "axis": {
+         "description": "The name matching the axis to mask in spec",
+         "title": "Axis"
+      },
+      "min": {
+         "description": "The minimum inclusive value in the region",
+         "title": "Min",
+         "type": "number"
+      },
+      "max": {
+         "description": "The minimum inclusive value in the region",
+         "title": "Max",
+         "type": "number"
+      },
+      "type": {
+         "const": "Range",
+         "default": "Range",
+         "enum": [
+            "Range"
+         ],
+         "title": "Type",
+         "type": "string"
+      }
+   },
+   "additionalProperties": false,
+   "required": [
+      "axis",
+      "min",
+      "max"
+   ]
+}
+
+
+

+
Fields:
+
+
+
+
+
+field axis: Axis [Required]#
+

The name matching the axis to mask in spec

+
+ +
+
+field max: float [Required]#
+

The minimum inclusive value in the region

+
+ +
+
+field min: float [Required]#
+

The minimum inclusive value in the region

+
+ +
+
+field type: Literal['Range'] = 'Range'#
+
+ +
+
+axis_sets() list[set[Axis]][source]#
+

Produce the non-overlapping sets of axes this region spans.

+
+ +
+
+mask(points: dict[Axis, ndarray[Any, dtype[floating[Any]]]]) ndarray[Any, dtype[bool]][source]#
+

Produce a mask of which points are in the region.

+
+ +
+ +
+
+pydantic model scanspec.regions.Rectangle[source]#
+

Mask contains points of axis within a rotated xy rectangle.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.regions import Rectangle
+from scanspec.specs import Line
+
+grid = Line("y", 1, 3, 10) * ~Line("x", 0, 2, 10)
+spec = grid & Rectangle("x", "y", 0, 1.1, 1.5, 2.1, 30)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-regions-1.png +
+

+Show JSON schema
{
+   "title": "Rectangle",
+   "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
+   "type": "object",
+   "properties": {
+      "x_axis": {
+         "description": "The name matching the x axis of the spec",
+         "title": "X Axis"
+      },
+      "y_axis": {
+         "description": "The name matching the y axis of the spec",
+         "title": "Y Axis"
+      },
+      "x_min": {
+         "description": "Minimum inclusive x value in the region",
+         "title": "X Min",
+         "type": "number"
+      },
+      "y_min": {
+         "description": "Minimum inclusive y value in the region",
+         "title": "Y Min",
+         "type": "number"
+      },
+      "x_max": {
+         "description": "Maximum inclusive x value in the region",
+         "title": "X Max",
+         "type": "number"
+      },
+      "y_max": {
+         "description": "Maximum inclusive y value in the region",
+         "title": "Y Max",
+         "type": "number"
+      },
+      "angle": {
+         "default": 0.0,
+         "description": "Clockwise rotation angle of the rectangle",
+         "title": "Angle",
+         "type": "number"
+      },
+      "type": {
+         "const": "Rectangle",
+         "default": "Rectangle",
+         "enum": [
+            "Rectangle"
+         ],
+         "title": "Type",
+         "type": "string"
+      }
+   },
+   "additionalProperties": false,
+   "required": [
+      "x_axis",
+      "y_axis",
+      "x_min",
+      "y_min",
+      "x_max",
+      "y_max"
+   ]
+}
+
+
+

+
Fields:
+
+
+
+
+
+field angle: float = 0.0#
+

Clockwise rotation angle of the rectangle

+
+ +
+
+field type: Literal['Rectangle'] = 'Rectangle'#
+
+ +
+
+field x_axis: Axis [Required]#
+

The name matching the x axis of the spec

+
+ +
+
+field x_max: float [Required]#
+

Maximum inclusive x value in the region

+
+ +
+
+field x_min: float [Required]#
+

Minimum inclusive x value in the region

+
+ +
+
+field y_axis: Axis [Required]#
+

The name matching the y axis of the spec

+
+ +
+
+field y_max: float [Required]#
+

Maximum inclusive y value in the region

+
+ +
+
+field y_min: float [Required]#
+

Minimum inclusive y value in the region

+
+ +
+
+axis_sets() list[set[Axis]][source]#
+

Produce the non-overlapping sets of axes this region spans.

+
+ +
+
+mask(points: dict[Axis, ndarray[Any, dtype[floating[Any]]]]) ndarray[Any, dtype[bool]][source]#
+

Produce a mask of which points are in the region.

+
+ +
+ +
+
+pydantic model scanspec.regions.Polygon[source]#
+

Mask contains points of axis within a rotated xy polygon.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.regions import Polygon
+from scanspec.specs import Line
+
+grid = Line("y", 3, 8, 10) * ~Line("x", 1 ,8, 10)
+spec = grid & Polygon("x", "y", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-regions-2.png +
+

+Show JSON schema
{
+   "title": "Polygon",
+   "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
+   "type": "object",
+   "properties": {
+      "x_axis": {
+         "description": "The name matching the x axis of the spec",
+         "title": "X Axis"
+      },
+      "y_axis": {
+         "description": "The name matching the y axis of the spec",
+         "title": "Y Axis"
+      },
+      "x_verts": {
+         "description": "The Nx1 x coordinates of the polygons vertices",
+         "items": {
+            "type": "number"
+         },
+         "minItems": 3,
+         "title": "X Verts",
+         "type": "array"
+      },
+      "y_verts": {
+         "description": "The Nx1 y coordinates of the polygons vertices",
+         "items": {
+            "type": "number"
+         },
+         "minItems": 3,
+         "title": "Y Verts",
+         "type": "array"
+      },
+      "type": {
+         "const": "Polygon",
+         "default": "Polygon",
+         "enum": [
+            "Polygon"
+         ],
+         "title": "Type",
+         "type": "string"
+      }
+   },
+   "additionalProperties": false,
+   "required": [
+      "x_axis",
+      "y_axis",
+      "x_verts",
+      "y_verts"
+   ]
+}
+
+
+

+
Fields:
+
+
+
+
+
+field type: Literal['Polygon'] = 'Polygon'#
+
+ +
+
+field x_axis: Axis [Required]#
+

The name matching the x axis of the spec

+
+ +
+
+field x_verts: list[float] [Required]#
+

The Nx1 x coordinates of the polygons vertices

+
+
Constraints:
+
    +
  • min_length = 3

  • +
+
+
+
+ +
+
+field y_axis: Axis [Required]#
+

The name matching the y axis of the spec

+
+ +
+
+field y_verts: list[float] [Required]#
+

The Nx1 y coordinates of the polygons vertices

+
+
Constraints:
+
    +
  • min_length = 3

  • +
+
+
+
+ +
+
+axis_sets() list[set[Axis]][source]#
+

Produce the non-overlapping sets of axes this region spans.

+
+ +
+
+mask(points: dict[Axis, ndarray[Any, dtype[floating[Any]]]]) ndarray[Any, dtype[bool]][source]#
+

Produce a mask of which points are in the region.

+
+ +
+ +
+
+pydantic model scanspec.regions.Circle[source]#
+

Mask contains points of axis within an xy circle of given radius.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.regions import Circle
+from scanspec.specs import Line
+
+grid = Line("y", 1, 3, 10) * ~Line("x", 0, 2, 10)
+spec = grid & Circle("x", "y", 1, 2, 0.9)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-regions-3.png +
+

+Show JSON schema
{
+   "title": "Circle",
+   "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
+   "type": "object",
+   "properties": {
+      "x_axis": {
+         "description": "The name matching the x axis of the spec",
+         "title": "X Axis"
+      },
+      "y_axis": {
+         "description": "The name matching the y axis of the spec",
+         "title": "Y Axis"
+      },
+      "x_middle": {
+         "description": "The central x point of the circle",
+         "title": "X Middle",
+         "type": "number"
+      },
+      "y_middle": {
+         "description": "The central y point of the circle",
+         "title": "Y Middle",
+         "type": "number"
+      },
+      "radius": {
+         "description": "Radius of the circle",
+         "exclusiveMinimum": 0.0,
+         "title": "Radius",
+         "type": "number"
+      },
+      "type": {
+         "const": "Circle",
+         "default": "Circle",
+         "enum": [
+            "Circle"
+         ],
+         "title": "Type",
+         "type": "string"
+      }
+   },
+   "additionalProperties": false,
+   "required": [
+      "x_axis",
+      "y_axis",
+      "x_middle",
+      "y_middle",
+      "radius"
+   ]
+}
+
+
+

+
Fields:
+
+
+
+
+
+field radius: float [Required]#
+

Radius of the circle

+
+
Constraints:
+
    +
  • gt = 0.0

  • +
+
+
+
+ +
+
+field type: Literal['Circle'] = 'Circle'#
+
+ +
+
+field x_axis: Axis [Required]#
+

The name matching the x axis of the spec

+
+ +
+
+field x_middle: float [Required]#
+

The central x point of the circle

+
+ +
+
+field y_axis: Axis [Required]#
+

The name matching the y axis of the spec

+
+ +
+
+field y_middle: float [Required]#
+

The central y point of the circle

+
+ +
+
+axis_sets() list[set[Axis]][source]#
+

Produce the non-overlapping sets of axes this region spans.

+
+ +
+
+mask(points: dict[Axis, ndarray[Any, dtype[floating[Any]]]]) ndarray[Any, dtype[bool]][source]#
+

Produce a mask of which points are in the region.

+
+ +
+ +
+
+pydantic model scanspec.regions.Ellipse[source]#
+

Mask contains points of axis within an xy ellipse of given radius.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.regions import Ellipse
+from scanspec.specs import Line
+
+grid = Line("y", 3, 8, 10) * ~Line("x", 1 ,8, 10)
+spec = grid & Ellipse("x", "y", 5, 5, 2, 3, 75)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-regions-4.png +
+

+Show JSON schema
{
+   "title": "Ellipse",
+   "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
+   "type": "object",
+   "properties": {
+      "x_axis": {
+         "description": "The name matching the x axis of the spec",
+         "title": "X Axis"
+      },
+      "y_axis": {
+         "description": "The name matching the y axis of the spec",
+         "title": "Y Axis"
+      },
+      "x_middle": {
+         "description": "The central x point of the ellipse",
+         "title": "X Middle",
+         "type": "number"
+      },
+      "y_middle": {
+         "description": "The central y point of the ellipse",
+         "title": "Y Middle",
+         "type": "number"
+      },
+      "x_radius": {
+         "description": "The radius along the x axis of the ellipse",
+         "exclusiveMinimum": 0.0,
+         "title": "X Radius",
+         "type": "number"
+      },
+      "y_radius": {
+         "description": "The radius along the y axis of the ellipse",
+         "exclusiveMinimum": 0.0,
+         "title": "Y Radius",
+         "type": "number"
+      },
+      "angle": {
+         "default": 0.0,
+         "description": "The angle of the ellipse (degrees)",
+         "title": "Angle",
+         "type": "number"
+      },
+      "type": {
+         "const": "Ellipse",
+         "default": "Ellipse",
+         "enum": [
+            "Ellipse"
+         ],
+         "title": "Type",
+         "type": "string"
+      }
+   },
+   "additionalProperties": false,
+   "required": [
+      "x_axis",
+      "y_axis",
+      "x_middle",
+      "y_middle",
+      "x_radius",
+      "y_radius"
+   ]
+}
+
+
+

+
Fields:
+
+
+
+
+
+field angle: float = 0.0#
+

The angle of the ellipse (degrees)

+
+ +
+
+field type: Literal['Ellipse'] = 'Ellipse'#
+
+ +
+
+field x_axis: Axis [Required]#
+

The name matching the x axis of the spec

+
+ +
+
+field x_middle: float [Required]#
+

The central x point of the ellipse

+
+ +
+
+field x_radius: float [Required]#
+

The radius along the x axis of the ellipse

+
+
Constraints:
+
    +
  • gt = 0.0

  • +
+
+
+
+ +
+
+field y_axis: Axis [Required]#
+

The name matching the y axis of the spec

+
+ +
+
+field y_middle: float [Required]#
+

The central y point of the ellipse

+
+ +
+
+field y_radius: float [Required]#
+

The radius along the y axis of the ellipse

+
+
Constraints:
+
    +
  • gt = 0.0

  • +
+
+
+
+ +
+
+axis_sets() list[set[Axis]][source]#
+

Produce the non-overlapping sets of axes this region spans.

+
+ +
+
+mask(points: dict[Axis, ndarray[Any, dtype[floating[Any]]]]) ndarray[Any, dtype[bool]][source]#
+

Produce a mask of which points are in the region.

+
+ +
+ +
+
+scanspec.regions.find_regions(obj: Any) Iterator[Region[Any]][source]#
+

Recursively yield Regions from obj and its children.

+
+ +
+ + +
+ + + + + + + +
+ + + + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/0.7.5/_api/scanspec.specs.html b/0.7.5/_api/scanspec.specs.html new file mode 100644 index 00000000..407e6a12 --- /dev/null +++ b/0.7.5/_api/scanspec.specs.html @@ -0,0 +1,7083 @@ + + + + + + + + + + + scanspec.specs — scanspec 0.7.5 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
+
+
+
+ +
+ +
+ + + + + +
+
+ + + +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

scanspec.specs#

+

Spec and its subclasses.

+
+

Inheritance diagram of scanspec.specs

+

Members

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

DURATION

Can be used as a special key to indicate how long each point should be

Spec

A serializable representation of the type and parameters of a scan.

fly

Flyscan, zipping with fixed duration for every frame.

step

Step scan, with num frames of given duration at each frame in the spec.

+
+
+
+scanspec.specs.DURATION = 'DURATION'#
+

Can be used as a special key to indicate how long each point should be

+
+ +
+
+class scanspec.specs.Spec[source]#
+

A serializable representation of the type and parameters of a scan.

+

Abstract baseclass for the specification of a scan. Supports operators:

+
    +
  • *: Outer Product of two Specs, nesting the second within the first. +If the first operand is an integer, wrap it in a Repeat

  • +
  • &: Mask the Spec with a Region, excluding midpoints outside of it

  • +
  • ~: Snake the Spec, reversing every other iteration of it

  • +
+
+
+axes() list[Axis][source]#
+

Return the list of axes that are present in the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+
+calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#
+

Produce a stack of nested Frames that form the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+
+frames() Frames[Axis][source]#
+

Expand all the scan Frames and return them.

+
+ +
+
+midpoints() Midpoints[Axis][source]#
+

Return Midpoints that can be iterated point by point.

+
+ +
+
+shape() tuple[int, ...][source]#
+

Return the final, simplified shape of the scan.

+
+ +
+
+zip(other: Spec[OtherAxis]) Zip[Axis | OtherAxis][source]#
+

Zip the Spec with another, iterating in tandem.

+
+ +
+
+concat(other: Spec[Axis]) Concat[Axis][source]#
+

Concat the Spec with another, iterating one after the other.

+
+ +
+
+serialize() Mapping[str, Any][source]#
+

Serialize the Spec to a dictionary.

+
+ +
+
+static deserialize(obj: Any) Spec[Any][source]#
+

Deserialize a Spec from a dictionary.

+
+ +
+ +
+
+pydantic model scanspec.specs.Product[source]#
+

Outer product of two Specs, nesting inner within outer.

+

This means that inner will run in its entirety at each point in outer.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Line
+
+spec = Line("y", 1, 2, 3) * Line("x", 3, 4, 12)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-1.png +
+

+Show JSON schema
{
+   "$defs": {
+      "Circle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the circle",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the circle",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "radius": {
+               "description": "Radius of the circle",
+               "exclusiveMinimum": 0.0,
+               "title": "Radius",
+               "type": "number"
+            },
+            "type": {
+               "const": "Circle",
+               "default": "Circle",
+               "enum": [
+                  "Circle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "radius"
+         ],
+         "title": "Circle",
+         "type": "object"
+      },
+      "CombinationOf": {
+         "additionalProperties": false,
+         "description": "Abstract baseclass for a combination of two regions, left and right.",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "CombinationOf",
+               "default": "CombinationOf",
+               "enum": [
+                  "CombinationOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "CombinationOf",
+         "type": "object"
+      },
+      "Concat": {
+         "additionalProperties": false,
+         "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Spec",
+               "description": "The left-hand Spec to Concat, midpoints will appear earlier"
+            },
+            "right": {
+               "$ref": "#/$defs/Spec",
+               "description": "The right-hand Spec to Concat, midpoints will appear later"
+            },
+            "gap": {
+               "default": false,
+               "description": "If True, force a gap in the output at the join",
+               "title": "Gap",
+               "type": "boolean"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Concat",
+               "default": "Concat",
+               "enum": [
+                  "Concat"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "Concat",
+         "type": "object"
+      },
+      "DifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "DifferenceOf",
+               "default": "DifferenceOf",
+               "enum": [
+                  "DifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "DifferenceOf",
+         "type": "object"
+      },
+      "Ellipse": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the ellipse",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the ellipse",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "x_radius": {
+               "description": "The radius along the x axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "X Radius",
+               "type": "number"
+            },
+            "y_radius": {
+               "description": "The radius along the y axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "Y Radius",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "The angle of the ellipse (degrees)",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Ellipse",
+               "default": "Ellipse",
+               "enum": [
+                  "Ellipse"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "x_radius",
+            "y_radius"
+         ],
+         "title": "Ellipse",
+         "type": "object"
+      },
+      "IntersectionOf": {
+         "additionalProperties": false,
+         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "IntersectionOf",
+               "default": "IntersectionOf",
+               "enum": [
+                  "IntersectionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "IntersectionOf",
+         "type": "object"
+      },
+      "Line": {
+         "additionalProperties": false,
+         "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 2, 5)",
+         "properties": {
+            "axis": {
+               "description": "An identifier for what to move",
+               "title": "Axis"
+            },
+            "start": {
+               "description": "Midpoint of the first point of the line",
+               "title": "Start",
+               "type": "number"
+            },
+            "stop": {
+               "description": "Midpoint of the last point of the line",
+               "title": "Stop",
+               "type": "number"
+            },
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "type": {
+               "const": "Line",
+               "default": "Line",
+               "enum": [
+                  "Line"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "start",
+            "stop",
+            "num"
+         ],
+         "title": "Line",
+         "type": "object"
+      },
+      "Mask": {
+         "additionalProperties": false,
+         "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec containing the source midpoints"
+            },
+            "region": {
+               "$ref": "#/$defs/Region",
+               "description": "The Region that midpoints will be inside"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Mask",
+               "default": "Mask",
+               "enum": [
+                  "Mask"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec",
+            "region"
+         ],
+         "title": "Mask",
+         "type": "object"
+      },
+      "Polygon": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_verts": {
+               "description": "The Nx1 x coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "X Verts",
+               "type": "array"
+            },
+            "y_verts": {
+               "description": "The Nx1 y coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "Y Verts",
+               "type": "array"
+            },
+            "type": {
+               "const": "Polygon",
+               "default": "Polygon",
+               "enum": [
+                  "Polygon"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_verts",
+            "y_verts"
+         ],
+         "title": "Polygon",
+         "type": "object"
+      },
+      "Product": {
+         "additionalProperties": false,
+         "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)",
+         "properties": {
+            "outer": {
+               "$ref": "#/$defs/Spec",
+               "description": "Will be executed once"
+            },
+            "inner": {
+               "$ref": "#/$defs/Spec",
+               "description": "Will be executed len(outer) times"
+            },
+            "type": {
+               "const": "Product",
+               "default": "Product",
+               "enum": [
+                  "Product"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "outer",
+            "inner"
+         ],
+         "title": "Product",
+         "type": "object"
+      },
+      "Range": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
+         "properties": {
+            "axis": {
+               "description": "The name matching the axis to mask in spec",
+               "title": "Axis"
+            },
+            "min": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Min",
+               "type": "number"
+            },
+            "max": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Max",
+               "type": "number"
+            },
+            "type": {
+               "const": "Range",
+               "default": "Range",
+               "enum": [
+                  "Range"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "min",
+            "max"
+         ],
+         "title": "Range",
+         "type": "object"
+      },
+      "Rectangle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_min": {
+               "description": "Minimum inclusive x value in the region",
+               "title": "X Min",
+               "type": "number"
+            },
+            "y_min": {
+               "description": "Minimum inclusive y value in the region",
+               "title": "Y Min",
+               "type": "number"
+            },
+            "x_max": {
+               "description": "Maximum inclusive x value in the region",
+               "title": "X Max",
+               "type": "number"
+            },
+            "y_max": {
+               "description": "Maximum inclusive y value in the region",
+               "title": "Y Max",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "Clockwise rotation angle of the rectangle",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Rectangle",
+               "default": "Rectangle",
+               "enum": [
+                  "Rectangle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_min",
+            "y_min",
+            "x_max",
+            "y_max"
+         ],
+         "title": "Rectangle",
+         "type": "object"
+      },
+      "Region": {
+         "discriminator": {
+            "mapping": {
+               "Circle": "#/$defs/Circle",
+               "CombinationOf": "#/$defs/CombinationOf",
+               "DifferenceOf": "#/$defs/DifferenceOf",
+               "Ellipse": "#/$defs/Ellipse",
+               "IntersectionOf": "#/$defs/IntersectionOf",
+               "Polygon": "#/$defs/Polygon",
+               "Range": "#/$defs/Range",
+               "Rectangle": "#/$defs/Rectangle",
+               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
+               "UnionOf": "#/$defs/UnionOf"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/CombinationOf"
+            },
+            {
+               "$ref": "#/$defs/UnionOf"
+            },
+            {
+               "$ref": "#/$defs/IntersectionOf"
+            },
+            {
+               "$ref": "#/$defs/DifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/SymmetricDifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/Range"
+            },
+            {
+               "$ref": "#/$defs/Rectangle"
+            },
+            {
+               "$ref": "#/$defs/Polygon"
+            },
+            {
+               "$ref": "#/$defs/Circle"
+            },
+            {
+               "$ref": "#/$defs/Ellipse"
+            }
+         ]
+      },
+      "Repeat": {
+         "additionalProperties": false,
+         "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n    from scanspec.specs import Line, Repeat\n\n    spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4",
+         "properties": {
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "gap": {
+               "default": true,
+               "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap",
+               "title": "Gap",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Repeat",
+               "default": "Repeat",
+               "enum": [
+                  "Repeat"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "num"
+         ],
+         "title": "Repeat",
+         "type": "object"
+      },
+      "Snake": {
+         "additionalProperties": false,
+         "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec to run in reverse every other iteration"
+            },
+            "type": {
+               "const": "Snake",
+               "default": "Snake",
+               "enum": [
+                  "Snake"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec"
+         ],
+         "title": "Snake",
+         "type": "object"
+      },
+      "Spec": {
+         "discriminator": {
+            "mapping": {
+               "Concat": "#/$defs/Concat",
+               "Line": "#/$defs/Line",
+               "Mask": "#/$defs/Mask",
+               "Product": "#/$defs/Product",
+               "Repeat": "#/$defs/Repeat",
+               "Snake": "#/$defs/Snake",
+               "Spiral": "#/$defs/Spiral",
+               "Squash": "#/$defs/Squash",
+               "Static": "#/$defs/Static",
+               "Zip": "#/$defs/Zip"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/Product"
+            },
+            {
+               "$ref": "#/$defs/Repeat"
+            },
+            {
+               "$ref": "#/$defs/Zip"
+            },
+            {
+               "$ref": "#/$defs/Mask"
+            },
+            {
+               "$ref": "#/$defs/Snake"
+            },
+            {
+               "$ref": "#/$defs/Concat"
+            },
+            {
+               "$ref": "#/$defs/Squash"
+            },
+            {
+               "$ref": "#/$defs/Line"
+            },
+            {
+               "$ref": "#/$defs/Static"
+            },
+            {
+               "$ref": "#/$defs/Spiral"
+            }
+         ]
+      },
+      "Spiral": {
+         "additionalProperties": false,
+         "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n    from scanspec.specs import Spiral\n\n    spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "An identifier for what to move for x",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "An identifier for what to move for y",
+               "title": "Y Axis"
+            },
+            "x_start": {
+               "description": "x centre of the spiral",
+               "title": "X Start",
+               "type": "number"
+            },
+            "y_start": {
+               "description": "y centre of the spiral",
+               "title": "Y Start",
+               "type": "number"
+            },
+            "x_range": {
+               "description": "x width of the spiral",
+               "title": "X Range",
+               "type": "number"
+            },
+            "y_range": {
+               "description": "y width of the spiral",
+               "title": "Y Range",
+               "type": "number"
+            },
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "rotate": {
+               "default": 0.0,
+               "description": "How much to rotate the angle of the spiral",
+               "title": "Rotate",
+               "type": "number"
+            },
+            "type": {
+               "const": "Spiral",
+               "default": "Spiral",
+               "enum": [
+                  "Spiral"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_start",
+            "y_start",
+            "x_range",
+            "y_range",
+            "num"
+         ],
+         "title": "Spiral",
+         "type": "object"
+      },
+      "Squash": {
+         "additionalProperties": false,
+         "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n    `why-squash-can-change-path`\n\n.. example_spec::\n\n    from scanspec.specs import Line, Squash\n\n    spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec to squash the dimensions of"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Squash",
+               "default": "Squash",
+               "enum": [
+                  "Squash"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec"
+         ],
+         "title": "Squash",
+         "type": "object"
+      },
+      "Static": {
+         "additionalProperties": false,
+         "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n    from scanspec.specs import Line, Static\n\n    spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))",
+         "properties": {
+            "axis": {
+               "description": "An identifier for what to move",
+               "title": "Axis"
+            },
+            "value": {
+               "description": "The value at each point",
+               "title": "Value",
+               "type": "number"
+            },
+            "num": {
+               "default": 1,
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "type": {
+               "const": "Static",
+               "default": "Static",
+               "enum": [
+                  "Static"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "value"
+         ],
+         "title": "Static",
+         "type": "object"
+      },
+      "SymmetricDifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "SymmetricDifferenceOf",
+               "default": "SymmetricDifferenceOf",
+               "enum": [
+                  "SymmetricDifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "SymmetricDifferenceOf",
+         "type": "object"
+      },
+      "UnionOf": {
+         "additionalProperties": false,
+         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "UnionOf",
+               "default": "UnionOf",
+               "enum": [
+                  "UnionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "UnionOf",
+         "type": "object"
+      },
+      "Zip": {
+         "additionalProperties": false,
+         "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n  the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Spec",
+               "description": "The left-hand Spec to Zip, will appear earlier in axes"
+            },
+            "right": {
+               "$ref": "#/$defs/Spec",
+               "description": "The right-hand Spec to Zip, will appear later in axes"
+            },
+            "type": {
+               "const": "Zip",
+               "default": "Zip",
+               "enum": [
+                  "Zip"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "Zip",
+         "type": "object"
+      }
+   },
+   "$ref": "#/$defs/Product"
+}
+
+
+

+
Fields:
+
+
+
+
+
+field inner: Spec[Axis] [Required]#
+

Will be executed len(outer) times

+
+ +
+
+field outer: Spec[Axis] [Required]#
+

Will be executed once

+
+ +
+
+field type: Literal['Product'] = 'Product'#
+
+ +
+
+axes() list[Axis][source]#
+

Return the list of axes that are present in the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+
+calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#
+

Produce a stack of nested Frames that form the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+ +
+
+pydantic model scanspec.specs.Repeat[source]#
+

Repeat an empty frame num times.

+

Can be used on the outside of a scan to repeat the same scan many times.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Line
+
+spec = 2 * ~Line.bounded("x", 3, 4, 1)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-2.png +
+

If you want snaked axes to have no gap between iterations you can do:

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Line, Repeat
+
+spec = Repeat(2, gap=False) * ~Line.bounded("x", 3, 4, 1)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-3.png +
+
+

Note

+

There is no turnaround arrow at x=4

+
+

+Show JSON schema
{
+   "title": "Repeat",
+   "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n    from scanspec.specs import Line, Repeat\n\n    spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4",
+   "type": "object",
+   "properties": {
+      "num": {
+         "description": "Number of frames to produce",
+         "minimum": 1,
+         "title": "Num",
+         "type": "integer"
+      },
+      "gap": {
+         "default": true,
+         "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap",
+         "title": "Gap",
+         "type": "boolean"
+      },
+      "type": {
+         "const": "Repeat",
+         "default": "Repeat",
+         "enum": [
+            "Repeat"
+         ],
+         "title": "Type",
+         "type": "string"
+      }
+   },
+   "additionalProperties": false,
+   "required": [
+      "num"
+   ]
+}
+
+
+

+
Fields:
+
+
+
+
+
+field gap: bool = True#
+

If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap

+
+ +
+
+field num: int [Required]#
+

Number of frames to produce

+
+
Constraints:
+
    +
  • ge = 1

  • +
+
+
+
+ +
+
+field type: Literal['Repeat'] = 'Repeat'#
+
+ +
+
+axes() list[Axis][source]#
+

Return the list of axes that are present in the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+
+calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#
+

Produce a stack of nested Frames that form the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+ +
+
+pydantic model scanspec.specs.Zip[source]#
+

Run two Specs in parallel, merging their midpoints together.

+

Typically formed using Spec.zip.

+

Stacks of Frames are merged by:

+
    +
  • If right creates a stack of a single Frames object of size 1, expand it to +the size of the fastest Frames object created by left

  • +
  • Merge individual Frames objects together from fastest to slowest

  • +
+

This means that Zipping a Spec producing stack [l2, l1] with a Spec +producing stack [r1] will assert len(l1)==len(r1), and produce +stack [l2, l1.zip(r1)].

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Line
+
+spec = Line("z", 1, 2, 3) * Line("y", 3, 4, 5).zip(Line("x", 4, 5, 5))
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-4.png +
+

+Show JSON schema
{
+   "$defs": {
+      "Circle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the circle",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the circle",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "radius": {
+               "description": "Radius of the circle",
+               "exclusiveMinimum": 0.0,
+               "title": "Radius",
+               "type": "number"
+            },
+            "type": {
+               "const": "Circle",
+               "default": "Circle",
+               "enum": [
+                  "Circle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "radius"
+         ],
+         "title": "Circle",
+         "type": "object"
+      },
+      "CombinationOf": {
+         "additionalProperties": false,
+         "description": "Abstract baseclass for a combination of two regions, left and right.",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "CombinationOf",
+               "default": "CombinationOf",
+               "enum": [
+                  "CombinationOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "CombinationOf",
+         "type": "object"
+      },
+      "Concat": {
+         "additionalProperties": false,
+         "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Spec",
+               "description": "The left-hand Spec to Concat, midpoints will appear earlier"
+            },
+            "right": {
+               "$ref": "#/$defs/Spec",
+               "description": "The right-hand Spec to Concat, midpoints will appear later"
+            },
+            "gap": {
+               "default": false,
+               "description": "If True, force a gap in the output at the join",
+               "title": "Gap",
+               "type": "boolean"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Concat",
+               "default": "Concat",
+               "enum": [
+                  "Concat"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "Concat",
+         "type": "object"
+      },
+      "DifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "DifferenceOf",
+               "default": "DifferenceOf",
+               "enum": [
+                  "DifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "DifferenceOf",
+         "type": "object"
+      },
+      "Ellipse": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the ellipse",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the ellipse",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "x_radius": {
+               "description": "The radius along the x axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "X Radius",
+               "type": "number"
+            },
+            "y_radius": {
+               "description": "The radius along the y axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "Y Radius",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "The angle of the ellipse (degrees)",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Ellipse",
+               "default": "Ellipse",
+               "enum": [
+                  "Ellipse"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "x_radius",
+            "y_radius"
+         ],
+         "title": "Ellipse",
+         "type": "object"
+      },
+      "IntersectionOf": {
+         "additionalProperties": false,
+         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "IntersectionOf",
+               "default": "IntersectionOf",
+               "enum": [
+                  "IntersectionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "IntersectionOf",
+         "type": "object"
+      },
+      "Line": {
+         "additionalProperties": false,
+         "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 2, 5)",
+         "properties": {
+            "axis": {
+               "description": "An identifier for what to move",
+               "title": "Axis"
+            },
+            "start": {
+               "description": "Midpoint of the first point of the line",
+               "title": "Start",
+               "type": "number"
+            },
+            "stop": {
+               "description": "Midpoint of the last point of the line",
+               "title": "Stop",
+               "type": "number"
+            },
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "type": {
+               "const": "Line",
+               "default": "Line",
+               "enum": [
+                  "Line"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "start",
+            "stop",
+            "num"
+         ],
+         "title": "Line",
+         "type": "object"
+      },
+      "Mask": {
+         "additionalProperties": false,
+         "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec containing the source midpoints"
+            },
+            "region": {
+               "$ref": "#/$defs/Region",
+               "description": "The Region that midpoints will be inside"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Mask",
+               "default": "Mask",
+               "enum": [
+                  "Mask"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec",
+            "region"
+         ],
+         "title": "Mask",
+         "type": "object"
+      },
+      "Polygon": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_verts": {
+               "description": "The Nx1 x coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "X Verts",
+               "type": "array"
+            },
+            "y_verts": {
+               "description": "The Nx1 y coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "Y Verts",
+               "type": "array"
+            },
+            "type": {
+               "const": "Polygon",
+               "default": "Polygon",
+               "enum": [
+                  "Polygon"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_verts",
+            "y_verts"
+         ],
+         "title": "Polygon",
+         "type": "object"
+      },
+      "Product": {
+         "additionalProperties": false,
+         "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)",
+         "properties": {
+            "outer": {
+               "$ref": "#/$defs/Spec",
+               "description": "Will be executed once"
+            },
+            "inner": {
+               "$ref": "#/$defs/Spec",
+               "description": "Will be executed len(outer) times"
+            },
+            "type": {
+               "const": "Product",
+               "default": "Product",
+               "enum": [
+                  "Product"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "outer",
+            "inner"
+         ],
+         "title": "Product",
+         "type": "object"
+      },
+      "Range": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
+         "properties": {
+            "axis": {
+               "description": "The name matching the axis to mask in spec",
+               "title": "Axis"
+            },
+            "min": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Min",
+               "type": "number"
+            },
+            "max": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Max",
+               "type": "number"
+            },
+            "type": {
+               "const": "Range",
+               "default": "Range",
+               "enum": [
+                  "Range"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "min",
+            "max"
+         ],
+         "title": "Range",
+         "type": "object"
+      },
+      "Rectangle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_min": {
+               "description": "Minimum inclusive x value in the region",
+               "title": "X Min",
+               "type": "number"
+            },
+            "y_min": {
+               "description": "Minimum inclusive y value in the region",
+               "title": "Y Min",
+               "type": "number"
+            },
+            "x_max": {
+               "description": "Maximum inclusive x value in the region",
+               "title": "X Max",
+               "type": "number"
+            },
+            "y_max": {
+               "description": "Maximum inclusive y value in the region",
+               "title": "Y Max",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "Clockwise rotation angle of the rectangle",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Rectangle",
+               "default": "Rectangle",
+               "enum": [
+                  "Rectangle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_min",
+            "y_min",
+            "x_max",
+            "y_max"
+         ],
+         "title": "Rectangle",
+         "type": "object"
+      },
+      "Region": {
+         "discriminator": {
+            "mapping": {
+               "Circle": "#/$defs/Circle",
+               "CombinationOf": "#/$defs/CombinationOf",
+               "DifferenceOf": "#/$defs/DifferenceOf",
+               "Ellipse": "#/$defs/Ellipse",
+               "IntersectionOf": "#/$defs/IntersectionOf",
+               "Polygon": "#/$defs/Polygon",
+               "Range": "#/$defs/Range",
+               "Rectangle": "#/$defs/Rectangle",
+               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
+               "UnionOf": "#/$defs/UnionOf"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/CombinationOf"
+            },
+            {
+               "$ref": "#/$defs/UnionOf"
+            },
+            {
+               "$ref": "#/$defs/IntersectionOf"
+            },
+            {
+               "$ref": "#/$defs/DifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/SymmetricDifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/Range"
+            },
+            {
+               "$ref": "#/$defs/Rectangle"
+            },
+            {
+               "$ref": "#/$defs/Polygon"
+            },
+            {
+               "$ref": "#/$defs/Circle"
+            },
+            {
+               "$ref": "#/$defs/Ellipse"
+            }
+         ]
+      },
+      "Repeat": {
+         "additionalProperties": false,
+         "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n    from scanspec.specs import Line, Repeat\n\n    spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4",
+         "properties": {
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "gap": {
+               "default": true,
+               "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap",
+               "title": "Gap",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Repeat",
+               "default": "Repeat",
+               "enum": [
+                  "Repeat"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "num"
+         ],
+         "title": "Repeat",
+         "type": "object"
+      },
+      "Snake": {
+         "additionalProperties": false,
+         "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec to run in reverse every other iteration"
+            },
+            "type": {
+               "const": "Snake",
+               "default": "Snake",
+               "enum": [
+                  "Snake"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec"
+         ],
+         "title": "Snake",
+         "type": "object"
+      },
+      "Spec": {
+         "discriminator": {
+            "mapping": {
+               "Concat": "#/$defs/Concat",
+               "Line": "#/$defs/Line",
+               "Mask": "#/$defs/Mask",
+               "Product": "#/$defs/Product",
+               "Repeat": "#/$defs/Repeat",
+               "Snake": "#/$defs/Snake",
+               "Spiral": "#/$defs/Spiral",
+               "Squash": "#/$defs/Squash",
+               "Static": "#/$defs/Static",
+               "Zip": "#/$defs/Zip"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/Product"
+            },
+            {
+               "$ref": "#/$defs/Repeat"
+            },
+            {
+               "$ref": "#/$defs/Zip"
+            },
+            {
+               "$ref": "#/$defs/Mask"
+            },
+            {
+               "$ref": "#/$defs/Snake"
+            },
+            {
+               "$ref": "#/$defs/Concat"
+            },
+            {
+               "$ref": "#/$defs/Squash"
+            },
+            {
+               "$ref": "#/$defs/Line"
+            },
+            {
+               "$ref": "#/$defs/Static"
+            },
+            {
+               "$ref": "#/$defs/Spiral"
+            }
+         ]
+      },
+      "Spiral": {
+         "additionalProperties": false,
+         "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n    from scanspec.specs import Spiral\n\n    spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "An identifier for what to move for x",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "An identifier for what to move for y",
+               "title": "Y Axis"
+            },
+            "x_start": {
+               "description": "x centre of the spiral",
+               "title": "X Start",
+               "type": "number"
+            },
+            "y_start": {
+               "description": "y centre of the spiral",
+               "title": "Y Start",
+               "type": "number"
+            },
+            "x_range": {
+               "description": "x width of the spiral",
+               "title": "X Range",
+               "type": "number"
+            },
+            "y_range": {
+               "description": "y width of the spiral",
+               "title": "Y Range",
+               "type": "number"
+            },
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "rotate": {
+               "default": 0.0,
+               "description": "How much to rotate the angle of the spiral",
+               "title": "Rotate",
+               "type": "number"
+            },
+            "type": {
+               "const": "Spiral",
+               "default": "Spiral",
+               "enum": [
+                  "Spiral"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_start",
+            "y_start",
+            "x_range",
+            "y_range",
+            "num"
+         ],
+         "title": "Spiral",
+         "type": "object"
+      },
+      "Squash": {
+         "additionalProperties": false,
+         "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n    `why-squash-can-change-path`\n\n.. example_spec::\n\n    from scanspec.specs import Line, Squash\n\n    spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec to squash the dimensions of"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Squash",
+               "default": "Squash",
+               "enum": [
+                  "Squash"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec"
+         ],
+         "title": "Squash",
+         "type": "object"
+      },
+      "Static": {
+         "additionalProperties": false,
+         "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n    from scanspec.specs import Line, Static\n\n    spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))",
+         "properties": {
+            "axis": {
+               "description": "An identifier for what to move",
+               "title": "Axis"
+            },
+            "value": {
+               "description": "The value at each point",
+               "title": "Value",
+               "type": "number"
+            },
+            "num": {
+               "default": 1,
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "type": {
+               "const": "Static",
+               "default": "Static",
+               "enum": [
+                  "Static"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "value"
+         ],
+         "title": "Static",
+         "type": "object"
+      },
+      "SymmetricDifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "SymmetricDifferenceOf",
+               "default": "SymmetricDifferenceOf",
+               "enum": [
+                  "SymmetricDifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "SymmetricDifferenceOf",
+         "type": "object"
+      },
+      "UnionOf": {
+         "additionalProperties": false,
+         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "UnionOf",
+               "default": "UnionOf",
+               "enum": [
+                  "UnionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "UnionOf",
+         "type": "object"
+      },
+      "Zip": {
+         "additionalProperties": false,
+         "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n  the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Spec",
+               "description": "The left-hand Spec to Zip, will appear earlier in axes"
+            },
+            "right": {
+               "$ref": "#/$defs/Spec",
+               "description": "The right-hand Spec to Zip, will appear later in axes"
+            },
+            "type": {
+               "const": "Zip",
+               "default": "Zip",
+               "enum": [
+                  "Zip"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "Zip",
+         "type": "object"
+      }
+   },
+   "$ref": "#/$defs/Zip"
+}
+
+
+

+
Fields:
+
+
+
+
+
+field left: Spec[Axis] [Required]#
+

The left-hand Spec to Zip, will appear earlier in axes

+
+ +
+
+field right: Spec[Axis] [Required]#
+

The right-hand Spec to Zip, will appear later in axes

+
+ +
+
+field type: Literal['Zip'] = 'Zip'#
+
+ +
+
+axes() list[Axis][source]#
+

Return the list of axes that are present in the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+
+calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#
+

Produce a stack of nested Frames that form the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+ +
+
+pydantic model scanspec.specs.Mask[source]#
+

Restrict Spec to only midpoints that fall inside the given Region.

+

Typically created with the & operator. It also pushes down the +& | ^ - operators to its Region to avoid the need for brackets on +combinations of Regions.

+

If a Region spans multiple Frames objects, they will be squashed together.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.regions import Circle
+from scanspec.specs import Line
+
+spec = Line("y", 1, 3, 3) * Line("x", 3, 5, 5) & Circle("x", "y", 4, 2, 1.2)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-5.png +
+

See Also: Why Squash (and Mask) can change the Path

+

+Show JSON schema
{
+   "$defs": {
+      "Circle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the circle",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the circle",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "radius": {
+               "description": "Radius of the circle",
+               "exclusiveMinimum": 0.0,
+               "title": "Radius",
+               "type": "number"
+            },
+            "type": {
+               "const": "Circle",
+               "default": "Circle",
+               "enum": [
+                  "Circle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "radius"
+         ],
+         "title": "Circle",
+         "type": "object"
+      },
+      "CombinationOf": {
+         "additionalProperties": false,
+         "description": "Abstract baseclass for a combination of two regions, left and right.",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "CombinationOf",
+               "default": "CombinationOf",
+               "enum": [
+                  "CombinationOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "CombinationOf",
+         "type": "object"
+      },
+      "Concat": {
+         "additionalProperties": false,
+         "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Spec",
+               "description": "The left-hand Spec to Concat, midpoints will appear earlier"
+            },
+            "right": {
+               "$ref": "#/$defs/Spec",
+               "description": "The right-hand Spec to Concat, midpoints will appear later"
+            },
+            "gap": {
+               "default": false,
+               "description": "If True, force a gap in the output at the join",
+               "title": "Gap",
+               "type": "boolean"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Concat",
+               "default": "Concat",
+               "enum": [
+                  "Concat"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "Concat",
+         "type": "object"
+      },
+      "DifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "DifferenceOf",
+               "default": "DifferenceOf",
+               "enum": [
+                  "DifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "DifferenceOf",
+         "type": "object"
+      },
+      "Ellipse": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the ellipse",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the ellipse",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "x_radius": {
+               "description": "The radius along the x axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "X Radius",
+               "type": "number"
+            },
+            "y_radius": {
+               "description": "The radius along the y axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "Y Radius",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "The angle of the ellipse (degrees)",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Ellipse",
+               "default": "Ellipse",
+               "enum": [
+                  "Ellipse"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "x_radius",
+            "y_radius"
+         ],
+         "title": "Ellipse",
+         "type": "object"
+      },
+      "IntersectionOf": {
+         "additionalProperties": false,
+         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "IntersectionOf",
+               "default": "IntersectionOf",
+               "enum": [
+                  "IntersectionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "IntersectionOf",
+         "type": "object"
+      },
+      "Line": {
+         "additionalProperties": false,
+         "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 2, 5)",
+         "properties": {
+            "axis": {
+               "description": "An identifier for what to move",
+               "title": "Axis"
+            },
+            "start": {
+               "description": "Midpoint of the first point of the line",
+               "title": "Start",
+               "type": "number"
+            },
+            "stop": {
+               "description": "Midpoint of the last point of the line",
+               "title": "Stop",
+               "type": "number"
+            },
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "type": {
+               "const": "Line",
+               "default": "Line",
+               "enum": [
+                  "Line"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "start",
+            "stop",
+            "num"
+         ],
+         "title": "Line",
+         "type": "object"
+      },
+      "Mask": {
+         "additionalProperties": false,
+         "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec containing the source midpoints"
+            },
+            "region": {
+               "$ref": "#/$defs/Region",
+               "description": "The Region that midpoints will be inside"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Mask",
+               "default": "Mask",
+               "enum": [
+                  "Mask"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec",
+            "region"
+         ],
+         "title": "Mask",
+         "type": "object"
+      },
+      "Polygon": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_verts": {
+               "description": "The Nx1 x coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "X Verts",
+               "type": "array"
+            },
+            "y_verts": {
+               "description": "The Nx1 y coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "Y Verts",
+               "type": "array"
+            },
+            "type": {
+               "const": "Polygon",
+               "default": "Polygon",
+               "enum": [
+                  "Polygon"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_verts",
+            "y_verts"
+         ],
+         "title": "Polygon",
+         "type": "object"
+      },
+      "Product": {
+         "additionalProperties": false,
+         "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)",
+         "properties": {
+            "outer": {
+               "$ref": "#/$defs/Spec",
+               "description": "Will be executed once"
+            },
+            "inner": {
+               "$ref": "#/$defs/Spec",
+               "description": "Will be executed len(outer) times"
+            },
+            "type": {
+               "const": "Product",
+               "default": "Product",
+               "enum": [
+                  "Product"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "outer",
+            "inner"
+         ],
+         "title": "Product",
+         "type": "object"
+      },
+      "Range": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
+         "properties": {
+            "axis": {
+               "description": "The name matching the axis to mask in spec",
+               "title": "Axis"
+            },
+            "min": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Min",
+               "type": "number"
+            },
+            "max": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Max",
+               "type": "number"
+            },
+            "type": {
+               "const": "Range",
+               "default": "Range",
+               "enum": [
+                  "Range"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "min",
+            "max"
+         ],
+         "title": "Range",
+         "type": "object"
+      },
+      "Rectangle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_min": {
+               "description": "Minimum inclusive x value in the region",
+               "title": "X Min",
+               "type": "number"
+            },
+            "y_min": {
+               "description": "Minimum inclusive y value in the region",
+               "title": "Y Min",
+               "type": "number"
+            },
+            "x_max": {
+               "description": "Maximum inclusive x value in the region",
+               "title": "X Max",
+               "type": "number"
+            },
+            "y_max": {
+               "description": "Maximum inclusive y value in the region",
+               "title": "Y Max",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "Clockwise rotation angle of the rectangle",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Rectangle",
+               "default": "Rectangle",
+               "enum": [
+                  "Rectangle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_min",
+            "y_min",
+            "x_max",
+            "y_max"
+         ],
+         "title": "Rectangle",
+         "type": "object"
+      },
+      "Region": {
+         "discriminator": {
+            "mapping": {
+               "Circle": "#/$defs/Circle",
+               "CombinationOf": "#/$defs/CombinationOf",
+               "DifferenceOf": "#/$defs/DifferenceOf",
+               "Ellipse": "#/$defs/Ellipse",
+               "IntersectionOf": "#/$defs/IntersectionOf",
+               "Polygon": "#/$defs/Polygon",
+               "Range": "#/$defs/Range",
+               "Rectangle": "#/$defs/Rectangle",
+               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
+               "UnionOf": "#/$defs/UnionOf"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/CombinationOf"
+            },
+            {
+               "$ref": "#/$defs/UnionOf"
+            },
+            {
+               "$ref": "#/$defs/IntersectionOf"
+            },
+            {
+               "$ref": "#/$defs/DifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/SymmetricDifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/Range"
+            },
+            {
+               "$ref": "#/$defs/Rectangle"
+            },
+            {
+               "$ref": "#/$defs/Polygon"
+            },
+            {
+               "$ref": "#/$defs/Circle"
+            },
+            {
+               "$ref": "#/$defs/Ellipse"
+            }
+         ]
+      },
+      "Repeat": {
+         "additionalProperties": false,
+         "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n    from scanspec.specs import Line, Repeat\n\n    spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4",
+         "properties": {
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "gap": {
+               "default": true,
+               "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap",
+               "title": "Gap",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Repeat",
+               "default": "Repeat",
+               "enum": [
+                  "Repeat"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "num"
+         ],
+         "title": "Repeat",
+         "type": "object"
+      },
+      "Snake": {
+         "additionalProperties": false,
+         "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec to run in reverse every other iteration"
+            },
+            "type": {
+               "const": "Snake",
+               "default": "Snake",
+               "enum": [
+                  "Snake"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec"
+         ],
+         "title": "Snake",
+         "type": "object"
+      },
+      "Spec": {
+         "discriminator": {
+            "mapping": {
+               "Concat": "#/$defs/Concat",
+               "Line": "#/$defs/Line",
+               "Mask": "#/$defs/Mask",
+               "Product": "#/$defs/Product",
+               "Repeat": "#/$defs/Repeat",
+               "Snake": "#/$defs/Snake",
+               "Spiral": "#/$defs/Spiral",
+               "Squash": "#/$defs/Squash",
+               "Static": "#/$defs/Static",
+               "Zip": "#/$defs/Zip"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/Product"
+            },
+            {
+               "$ref": "#/$defs/Repeat"
+            },
+            {
+               "$ref": "#/$defs/Zip"
+            },
+            {
+               "$ref": "#/$defs/Mask"
+            },
+            {
+               "$ref": "#/$defs/Snake"
+            },
+            {
+               "$ref": "#/$defs/Concat"
+            },
+            {
+               "$ref": "#/$defs/Squash"
+            },
+            {
+               "$ref": "#/$defs/Line"
+            },
+            {
+               "$ref": "#/$defs/Static"
+            },
+            {
+               "$ref": "#/$defs/Spiral"
+            }
+         ]
+      },
+      "Spiral": {
+         "additionalProperties": false,
+         "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n    from scanspec.specs import Spiral\n\n    spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "An identifier for what to move for x",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "An identifier for what to move for y",
+               "title": "Y Axis"
+            },
+            "x_start": {
+               "description": "x centre of the spiral",
+               "title": "X Start",
+               "type": "number"
+            },
+            "y_start": {
+               "description": "y centre of the spiral",
+               "title": "Y Start",
+               "type": "number"
+            },
+            "x_range": {
+               "description": "x width of the spiral",
+               "title": "X Range",
+               "type": "number"
+            },
+            "y_range": {
+               "description": "y width of the spiral",
+               "title": "Y Range",
+               "type": "number"
+            },
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "rotate": {
+               "default": 0.0,
+               "description": "How much to rotate the angle of the spiral",
+               "title": "Rotate",
+               "type": "number"
+            },
+            "type": {
+               "const": "Spiral",
+               "default": "Spiral",
+               "enum": [
+                  "Spiral"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_start",
+            "y_start",
+            "x_range",
+            "y_range",
+            "num"
+         ],
+         "title": "Spiral",
+         "type": "object"
+      },
+      "Squash": {
+         "additionalProperties": false,
+         "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n    `why-squash-can-change-path`\n\n.. example_spec::\n\n    from scanspec.specs import Line, Squash\n\n    spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec to squash the dimensions of"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Squash",
+               "default": "Squash",
+               "enum": [
+                  "Squash"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec"
+         ],
+         "title": "Squash",
+         "type": "object"
+      },
+      "Static": {
+         "additionalProperties": false,
+         "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n    from scanspec.specs import Line, Static\n\n    spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))",
+         "properties": {
+            "axis": {
+               "description": "An identifier for what to move",
+               "title": "Axis"
+            },
+            "value": {
+               "description": "The value at each point",
+               "title": "Value",
+               "type": "number"
+            },
+            "num": {
+               "default": 1,
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "type": {
+               "const": "Static",
+               "default": "Static",
+               "enum": [
+                  "Static"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "value"
+         ],
+         "title": "Static",
+         "type": "object"
+      },
+      "SymmetricDifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "SymmetricDifferenceOf",
+               "default": "SymmetricDifferenceOf",
+               "enum": [
+                  "SymmetricDifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "SymmetricDifferenceOf",
+         "type": "object"
+      },
+      "UnionOf": {
+         "additionalProperties": false,
+         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "UnionOf",
+               "default": "UnionOf",
+               "enum": [
+                  "UnionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "UnionOf",
+         "type": "object"
+      },
+      "Zip": {
+         "additionalProperties": false,
+         "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n  the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Spec",
+               "description": "The left-hand Spec to Zip, will appear earlier in axes"
+            },
+            "right": {
+               "$ref": "#/$defs/Spec",
+               "description": "The right-hand Spec to Zip, will appear later in axes"
+            },
+            "type": {
+               "const": "Zip",
+               "default": "Zip",
+               "enum": [
+                  "Zip"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "Zip",
+         "type": "object"
+      }
+   },
+   "$ref": "#/$defs/Mask"
+}
+
+
+

+
Fields:
+
+
+
+
+
+field check_path_changes: bool = True#
+

If True path through scan will not be modified by squash

+
+ +
+
+field region: Region[Axis] [Required]#
+

The Region that midpoints will be inside

+
+ +
+
+field spec: Spec[Axis] [Required]#
+

The Spec containing the source midpoints

+
+ +
+
+field type: Literal['Mask'] = 'Mask'#
+
+ +
+
+axes() list[Axis][source]#
+

Return the list of axes that are present in the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+
+calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#
+

Produce a stack of nested Frames that form the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+ +
+
+pydantic model scanspec.specs.Snake[source]#
+

Run the Spec in reverse on every other iteration when nested.

+

Typically created with the ~ operator.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Line
+
+spec = Line("y", 1, 3, 3) * ~Line("x", 3, 5, 5)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-6.png +
+

+Show JSON schema
{
+   "$defs": {
+      "Circle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the circle",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the circle",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "radius": {
+               "description": "Radius of the circle",
+               "exclusiveMinimum": 0.0,
+               "title": "Radius",
+               "type": "number"
+            },
+            "type": {
+               "const": "Circle",
+               "default": "Circle",
+               "enum": [
+                  "Circle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "radius"
+         ],
+         "title": "Circle",
+         "type": "object"
+      },
+      "CombinationOf": {
+         "additionalProperties": false,
+         "description": "Abstract baseclass for a combination of two regions, left and right.",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "CombinationOf",
+               "default": "CombinationOf",
+               "enum": [
+                  "CombinationOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "CombinationOf",
+         "type": "object"
+      },
+      "Concat": {
+         "additionalProperties": false,
+         "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Spec",
+               "description": "The left-hand Spec to Concat, midpoints will appear earlier"
+            },
+            "right": {
+               "$ref": "#/$defs/Spec",
+               "description": "The right-hand Spec to Concat, midpoints will appear later"
+            },
+            "gap": {
+               "default": false,
+               "description": "If True, force a gap in the output at the join",
+               "title": "Gap",
+               "type": "boolean"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Concat",
+               "default": "Concat",
+               "enum": [
+                  "Concat"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "Concat",
+         "type": "object"
+      },
+      "DifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "DifferenceOf",
+               "default": "DifferenceOf",
+               "enum": [
+                  "DifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "DifferenceOf",
+         "type": "object"
+      },
+      "Ellipse": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the ellipse",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the ellipse",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "x_radius": {
+               "description": "The radius along the x axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "X Radius",
+               "type": "number"
+            },
+            "y_radius": {
+               "description": "The radius along the y axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "Y Radius",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "The angle of the ellipse (degrees)",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Ellipse",
+               "default": "Ellipse",
+               "enum": [
+                  "Ellipse"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "x_radius",
+            "y_radius"
+         ],
+         "title": "Ellipse",
+         "type": "object"
+      },
+      "IntersectionOf": {
+         "additionalProperties": false,
+         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "IntersectionOf",
+               "default": "IntersectionOf",
+               "enum": [
+                  "IntersectionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "IntersectionOf",
+         "type": "object"
+      },
+      "Line": {
+         "additionalProperties": false,
+         "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 2, 5)",
+         "properties": {
+            "axis": {
+               "description": "An identifier for what to move",
+               "title": "Axis"
+            },
+            "start": {
+               "description": "Midpoint of the first point of the line",
+               "title": "Start",
+               "type": "number"
+            },
+            "stop": {
+               "description": "Midpoint of the last point of the line",
+               "title": "Stop",
+               "type": "number"
+            },
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "type": {
+               "const": "Line",
+               "default": "Line",
+               "enum": [
+                  "Line"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "start",
+            "stop",
+            "num"
+         ],
+         "title": "Line",
+         "type": "object"
+      },
+      "Mask": {
+         "additionalProperties": false,
+         "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec containing the source midpoints"
+            },
+            "region": {
+               "$ref": "#/$defs/Region",
+               "description": "The Region that midpoints will be inside"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Mask",
+               "default": "Mask",
+               "enum": [
+                  "Mask"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec",
+            "region"
+         ],
+         "title": "Mask",
+         "type": "object"
+      },
+      "Polygon": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_verts": {
+               "description": "The Nx1 x coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "X Verts",
+               "type": "array"
+            },
+            "y_verts": {
+               "description": "The Nx1 y coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "Y Verts",
+               "type": "array"
+            },
+            "type": {
+               "const": "Polygon",
+               "default": "Polygon",
+               "enum": [
+                  "Polygon"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_verts",
+            "y_verts"
+         ],
+         "title": "Polygon",
+         "type": "object"
+      },
+      "Product": {
+         "additionalProperties": false,
+         "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)",
+         "properties": {
+            "outer": {
+               "$ref": "#/$defs/Spec",
+               "description": "Will be executed once"
+            },
+            "inner": {
+               "$ref": "#/$defs/Spec",
+               "description": "Will be executed len(outer) times"
+            },
+            "type": {
+               "const": "Product",
+               "default": "Product",
+               "enum": [
+                  "Product"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "outer",
+            "inner"
+         ],
+         "title": "Product",
+         "type": "object"
+      },
+      "Range": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
+         "properties": {
+            "axis": {
+               "description": "The name matching the axis to mask in spec",
+               "title": "Axis"
+            },
+            "min": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Min",
+               "type": "number"
+            },
+            "max": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Max",
+               "type": "number"
+            },
+            "type": {
+               "const": "Range",
+               "default": "Range",
+               "enum": [
+                  "Range"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "min",
+            "max"
+         ],
+         "title": "Range",
+         "type": "object"
+      },
+      "Rectangle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_min": {
+               "description": "Minimum inclusive x value in the region",
+               "title": "X Min",
+               "type": "number"
+            },
+            "y_min": {
+               "description": "Minimum inclusive y value in the region",
+               "title": "Y Min",
+               "type": "number"
+            },
+            "x_max": {
+               "description": "Maximum inclusive x value in the region",
+               "title": "X Max",
+               "type": "number"
+            },
+            "y_max": {
+               "description": "Maximum inclusive y value in the region",
+               "title": "Y Max",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "Clockwise rotation angle of the rectangle",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Rectangle",
+               "default": "Rectangle",
+               "enum": [
+                  "Rectangle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_min",
+            "y_min",
+            "x_max",
+            "y_max"
+         ],
+         "title": "Rectangle",
+         "type": "object"
+      },
+      "Region": {
+         "discriminator": {
+            "mapping": {
+               "Circle": "#/$defs/Circle",
+               "CombinationOf": "#/$defs/CombinationOf",
+               "DifferenceOf": "#/$defs/DifferenceOf",
+               "Ellipse": "#/$defs/Ellipse",
+               "IntersectionOf": "#/$defs/IntersectionOf",
+               "Polygon": "#/$defs/Polygon",
+               "Range": "#/$defs/Range",
+               "Rectangle": "#/$defs/Rectangle",
+               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
+               "UnionOf": "#/$defs/UnionOf"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/CombinationOf"
+            },
+            {
+               "$ref": "#/$defs/UnionOf"
+            },
+            {
+               "$ref": "#/$defs/IntersectionOf"
+            },
+            {
+               "$ref": "#/$defs/DifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/SymmetricDifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/Range"
+            },
+            {
+               "$ref": "#/$defs/Rectangle"
+            },
+            {
+               "$ref": "#/$defs/Polygon"
+            },
+            {
+               "$ref": "#/$defs/Circle"
+            },
+            {
+               "$ref": "#/$defs/Ellipse"
+            }
+         ]
+      },
+      "Repeat": {
+         "additionalProperties": false,
+         "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n    from scanspec.specs import Line, Repeat\n\n    spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4",
+         "properties": {
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "gap": {
+               "default": true,
+               "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap",
+               "title": "Gap",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Repeat",
+               "default": "Repeat",
+               "enum": [
+                  "Repeat"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "num"
+         ],
+         "title": "Repeat",
+         "type": "object"
+      },
+      "Snake": {
+         "additionalProperties": false,
+         "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec to run in reverse every other iteration"
+            },
+            "type": {
+               "const": "Snake",
+               "default": "Snake",
+               "enum": [
+                  "Snake"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec"
+         ],
+         "title": "Snake",
+         "type": "object"
+      },
+      "Spec": {
+         "discriminator": {
+            "mapping": {
+               "Concat": "#/$defs/Concat",
+               "Line": "#/$defs/Line",
+               "Mask": "#/$defs/Mask",
+               "Product": "#/$defs/Product",
+               "Repeat": "#/$defs/Repeat",
+               "Snake": "#/$defs/Snake",
+               "Spiral": "#/$defs/Spiral",
+               "Squash": "#/$defs/Squash",
+               "Static": "#/$defs/Static",
+               "Zip": "#/$defs/Zip"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/Product"
+            },
+            {
+               "$ref": "#/$defs/Repeat"
+            },
+            {
+               "$ref": "#/$defs/Zip"
+            },
+            {
+               "$ref": "#/$defs/Mask"
+            },
+            {
+               "$ref": "#/$defs/Snake"
+            },
+            {
+               "$ref": "#/$defs/Concat"
+            },
+            {
+               "$ref": "#/$defs/Squash"
+            },
+            {
+               "$ref": "#/$defs/Line"
+            },
+            {
+               "$ref": "#/$defs/Static"
+            },
+            {
+               "$ref": "#/$defs/Spiral"
+            }
+         ]
+      },
+      "Spiral": {
+         "additionalProperties": false,
+         "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n    from scanspec.specs import Spiral\n\n    spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "An identifier for what to move for x",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "An identifier for what to move for y",
+               "title": "Y Axis"
+            },
+            "x_start": {
+               "description": "x centre of the spiral",
+               "title": "X Start",
+               "type": "number"
+            },
+            "y_start": {
+               "description": "y centre of the spiral",
+               "title": "Y Start",
+               "type": "number"
+            },
+            "x_range": {
+               "description": "x width of the spiral",
+               "title": "X Range",
+               "type": "number"
+            },
+            "y_range": {
+               "description": "y width of the spiral",
+               "title": "Y Range",
+               "type": "number"
+            },
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "rotate": {
+               "default": 0.0,
+               "description": "How much to rotate the angle of the spiral",
+               "title": "Rotate",
+               "type": "number"
+            },
+            "type": {
+               "const": "Spiral",
+               "default": "Spiral",
+               "enum": [
+                  "Spiral"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_start",
+            "y_start",
+            "x_range",
+            "y_range",
+            "num"
+         ],
+         "title": "Spiral",
+         "type": "object"
+      },
+      "Squash": {
+         "additionalProperties": false,
+         "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n    `why-squash-can-change-path`\n\n.. example_spec::\n\n    from scanspec.specs import Line, Squash\n\n    spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec to squash the dimensions of"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Squash",
+               "default": "Squash",
+               "enum": [
+                  "Squash"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec"
+         ],
+         "title": "Squash",
+         "type": "object"
+      },
+      "Static": {
+         "additionalProperties": false,
+         "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n    from scanspec.specs import Line, Static\n\n    spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))",
+         "properties": {
+            "axis": {
+               "description": "An identifier for what to move",
+               "title": "Axis"
+            },
+            "value": {
+               "description": "The value at each point",
+               "title": "Value",
+               "type": "number"
+            },
+            "num": {
+               "default": 1,
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "type": {
+               "const": "Static",
+               "default": "Static",
+               "enum": [
+                  "Static"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "value"
+         ],
+         "title": "Static",
+         "type": "object"
+      },
+      "SymmetricDifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "SymmetricDifferenceOf",
+               "default": "SymmetricDifferenceOf",
+               "enum": [
+                  "SymmetricDifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "SymmetricDifferenceOf",
+         "type": "object"
+      },
+      "UnionOf": {
+         "additionalProperties": false,
+         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "UnionOf",
+               "default": "UnionOf",
+               "enum": [
+                  "UnionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "UnionOf",
+         "type": "object"
+      },
+      "Zip": {
+         "additionalProperties": false,
+         "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n  the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Spec",
+               "description": "The left-hand Spec to Zip, will appear earlier in axes"
+            },
+            "right": {
+               "$ref": "#/$defs/Spec",
+               "description": "The right-hand Spec to Zip, will appear later in axes"
+            },
+            "type": {
+               "const": "Zip",
+               "default": "Zip",
+               "enum": [
+                  "Zip"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "Zip",
+         "type": "object"
+      }
+   },
+   "$ref": "#/$defs/Snake"
+}
+
+
+

+
Fields:
+
+
+
+
+
+field spec: Spec[Axis] [Required]#
+

The Spec to run in reverse every other iteration

+
+ +
+
+field type: Literal['Snake'] = 'Snake'#
+
+ +
+
+axes() list[Axis][source]#
+

Return the list of axes that are present in the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+
+calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#
+

Produce a stack of nested Frames that form the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+ +
+
+pydantic model scanspec.specs.Concat[source]#
+

Concatenate two Specs together, running one after the other.

+

Each Dimension of left and right must contain the same axes. Typically +formed using Spec.concat.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Line
+
+spec = Line("x", 1, 3, 3).concat(Line("x", 4, 5, 5))
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-7.png +
+

+Show JSON schema
{
+   "$defs": {
+      "Circle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the circle",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the circle",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "radius": {
+               "description": "Radius of the circle",
+               "exclusiveMinimum": 0.0,
+               "title": "Radius",
+               "type": "number"
+            },
+            "type": {
+               "const": "Circle",
+               "default": "Circle",
+               "enum": [
+                  "Circle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "radius"
+         ],
+         "title": "Circle",
+         "type": "object"
+      },
+      "CombinationOf": {
+         "additionalProperties": false,
+         "description": "Abstract baseclass for a combination of two regions, left and right.",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "CombinationOf",
+               "default": "CombinationOf",
+               "enum": [
+                  "CombinationOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "CombinationOf",
+         "type": "object"
+      },
+      "Concat": {
+         "additionalProperties": false,
+         "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Spec",
+               "description": "The left-hand Spec to Concat, midpoints will appear earlier"
+            },
+            "right": {
+               "$ref": "#/$defs/Spec",
+               "description": "The right-hand Spec to Concat, midpoints will appear later"
+            },
+            "gap": {
+               "default": false,
+               "description": "If True, force a gap in the output at the join",
+               "title": "Gap",
+               "type": "boolean"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Concat",
+               "default": "Concat",
+               "enum": [
+                  "Concat"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "Concat",
+         "type": "object"
+      },
+      "DifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "DifferenceOf",
+               "default": "DifferenceOf",
+               "enum": [
+                  "DifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "DifferenceOf",
+         "type": "object"
+      },
+      "Ellipse": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the ellipse",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the ellipse",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "x_radius": {
+               "description": "The radius along the x axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "X Radius",
+               "type": "number"
+            },
+            "y_radius": {
+               "description": "The radius along the y axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "Y Radius",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "The angle of the ellipse (degrees)",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Ellipse",
+               "default": "Ellipse",
+               "enum": [
+                  "Ellipse"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "x_radius",
+            "y_radius"
+         ],
+         "title": "Ellipse",
+         "type": "object"
+      },
+      "IntersectionOf": {
+         "additionalProperties": false,
+         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "IntersectionOf",
+               "default": "IntersectionOf",
+               "enum": [
+                  "IntersectionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "IntersectionOf",
+         "type": "object"
+      },
+      "Line": {
+         "additionalProperties": false,
+         "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 2, 5)",
+         "properties": {
+            "axis": {
+               "description": "An identifier for what to move",
+               "title": "Axis"
+            },
+            "start": {
+               "description": "Midpoint of the first point of the line",
+               "title": "Start",
+               "type": "number"
+            },
+            "stop": {
+               "description": "Midpoint of the last point of the line",
+               "title": "Stop",
+               "type": "number"
+            },
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "type": {
+               "const": "Line",
+               "default": "Line",
+               "enum": [
+                  "Line"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "start",
+            "stop",
+            "num"
+         ],
+         "title": "Line",
+         "type": "object"
+      },
+      "Mask": {
+         "additionalProperties": false,
+         "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec containing the source midpoints"
+            },
+            "region": {
+               "$ref": "#/$defs/Region",
+               "description": "The Region that midpoints will be inside"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Mask",
+               "default": "Mask",
+               "enum": [
+                  "Mask"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec",
+            "region"
+         ],
+         "title": "Mask",
+         "type": "object"
+      },
+      "Polygon": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_verts": {
+               "description": "The Nx1 x coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "X Verts",
+               "type": "array"
+            },
+            "y_verts": {
+               "description": "The Nx1 y coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "Y Verts",
+               "type": "array"
+            },
+            "type": {
+               "const": "Polygon",
+               "default": "Polygon",
+               "enum": [
+                  "Polygon"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_verts",
+            "y_verts"
+         ],
+         "title": "Polygon",
+         "type": "object"
+      },
+      "Product": {
+         "additionalProperties": false,
+         "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)",
+         "properties": {
+            "outer": {
+               "$ref": "#/$defs/Spec",
+               "description": "Will be executed once"
+            },
+            "inner": {
+               "$ref": "#/$defs/Spec",
+               "description": "Will be executed len(outer) times"
+            },
+            "type": {
+               "const": "Product",
+               "default": "Product",
+               "enum": [
+                  "Product"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "outer",
+            "inner"
+         ],
+         "title": "Product",
+         "type": "object"
+      },
+      "Range": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
+         "properties": {
+            "axis": {
+               "description": "The name matching the axis to mask in spec",
+               "title": "Axis"
+            },
+            "min": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Min",
+               "type": "number"
+            },
+            "max": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Max",
+               "type": "number"
+            },
+            "type": {
+               "const": "Range",
+               "default": "Range",
+               "enum": [
+                  "Range"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "min",
+            "max"
+         ],
+         "title": "Range",
+         "type": "object"
+      },
+      "Rectangle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_min": {
+               "description": "Minimum inclusive x value in the region",
+               "title": "X Min",
+               "type": "number"
+            },
+            "y_min": {
+               "description": "Minimum inclusive y value in the region",
+               "title": "Y Min",
+               "type": "number"
+            },
+            "x_max": {
+               "description": "Maximum inclusive x value in the region",
+               "title": "X Max",
+               "type": "number"
+            },
+            "y_max": {
+               "description": "Maximum inclusive y value in the region",
+               "title": "Y Max",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "Clockwise rotation angle of the rectangle",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Rectangle",
+               "default": "Rectangle",
+               "enum": [
+                  "Rectangle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_min",
+            "y_min",
+            "x_max",
+            "y_max"
+         ],
+         "title": "Rectangle",
+         "type": "object"
+      },
+      "Region": {
+         "discriminator": {
+            "mapping": {
+               "Circle": "#/$defs/Circle",
+               "CombinationOf": "#/$defs/CombinationOf",
+               "DifferenceOf": "#/$defs/DifferenceOf",
+               "Ellipse": "#/$defs/Ellipse",
+               "IntersectionOf": "#/$defs/IntersectionOf",
+               "Polygon": "#/$defs/Polygon",
+               "Range": "#/$defs/Range",
+               "Rectangle": "#/$defs/Rectangle",
+               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
+               "UnionOf": "#/$defs/UnionOf"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/CombinationOf"
+            },
+            {
+               "$ref": "#/$defs/UnionOf"
+            },
+            {
+               "$ref": "#/$defs/IntersectionOf"
+            },
+            {
+               "$ref": "#/$defs/DifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/SymmetricDifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/Range"
+            },
+            {
+               "$ref": "#/$defs/Rectangle"
+            },
+            {
+               "$ref": "#/$defs/Polygon"
+            },
+            {
+               "$ref": "#/$defs/Circle"
+            },
+            {
+               "$ref": "#/$defs/Ellipse"
+            }
+         ]
+      },
+      "Repeat": {
+         "additionalProperties": false,
+         "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n    from scanspec.specs import Line, Repeat\n\n    spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4",
+         "properties": {
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "gap": {
+               "default": true,
+               "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap",
+               "title": "Gap",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Repeat",
+               "default": "Repeat",
+               "enum": [
+                  "Repeat"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "num"
+         ],
+         "title": "Repeat",
+         "type": "object"
+      },
+      "Snake": {
+         "additionalProperties": false,
+         "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec to run in reverse every other iteration"
+            },
+            "type": {
+               "const": "Snake",
+               "default": "Snake",
+               "enum": [
+                  "Snake"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec"
+         ],
+         "title": "Snake",
+         "type": "object"
+      },
+      "Spec": {
+         "discriminator": {
+            "mapping": {
+               "Concat": "#/$defs/Concat",
+               "Line": "#/$defs/Line",
+               "Mask": "#/$defs/Mask",
+               "Product": "#/$defs/Product",
+               "Repeat": "#/$defs/Repeat",
+               "Snake": "#/$defs/Snake",
+               "Spiral": "#/$defs/Spiral",
+               "Squash": "#/$defs/Squash",
+               "Static": "#/$defs/Static",
+               "Zip": "#/$defs/Zip"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/Product"
+            },
+            {
+               "$ref": "#/$defs/Repeat"
+            },
+            {
+               "$ref": "#/$defs/Zip"
+            },
+            {
+               "$ref": "#/$defs/Mask"
+            },
+            {
+               "$ref": "#/$defs/Snake"
+            },
+            {
+               "$ref": "#/$defs/Concat"
+            },
+            {
+               "$ref": "#/$defs/Squash"
+            },
+            {
+               "$ref": "#/$defs/Line"
+            },
+            {
+               "$ref": "#/$defs/Static"
+            },
+            {
+               "$ref": "#/$defs/Spiral"
+            }
+         ]
+      },
+      "Spiral": {
+         "additionalProperties": false,
+         "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n    from scanspec.specs import Spiral\n\n    spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "An identifier for what to move for x",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "An identifier for what to move for y",
+               "title": "Y Axis"
+            },
+            "x_start": {
+               "description": "x centre of the spiral",
+               "title": "X Start",
+               "type": "number"
+            },
+            "y_start": {
+               "description": "y centre of the spiral",
+               "title": "Y Start",
+               "type": "number"
+            },
+            "x_range": {
+               "description": "x width of the spiral",
+               "title": "X Range",
+               "type": "number"
+            },
+            "y_range": {
+               "description": "y width of the spiral",
+               "title": "Y Range",
+               "type": "number"
+            },
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "rotate": {
+               "default": 0.0,
+               "description": "How much to rotate the angle of the spiral",
+               "title": "Rotate",
+               "type": "number"
+            },
+            "type": {
+               "const": "Spiral",
+               "default": "Spiral",
+               "enum": [
+                  "Spiral"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_start",
+            "y_start",
+            "x_range",
+            "y_range",
+            "num"
+         ],
+         "title": "Spiral",
+         "type": "object"
+      },
+      "Squash": {
+         "additionalProperties": false,
+         "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n    `why-squash-can-change-path`\n\n.. example_spec::\n\n    from scanspec.specs import Line, Squash\n\n    spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec to squash the dimensions of"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Squash",
+               "default": "Squash",
+               "enum": [
+                  "Squash"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec"
+         ],
+         "title": "Squash",
+         "type": "object"
+      },
+      "Static": {
+         "additionalProperties": false,
+         "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n    from scanspec.specs import Line, Static\n\n    spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))",
+         "properties": {
+            "axis": {
+               "description": "An identifier for what to move",
+               "title": "Axis"
+            },
+            "value": {
+               "description": "The value at each point",
+               "title": "Value",
+               "type": "number"
+            },
+            "num": {
+               "default": 1,
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "type": {
+               "const": "Static",
+               "default": "Static",
+               "enum": [
+                  "Static"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "value"
+         ],
+         "title": "Static",
+         "type": "object"
+      },
+      "SymmetricDifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "SymmetricDifferenceOf",
+               "default": "SymmetricDifferenceOf",
+               "enum": [
+                  "SymmetricDifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "SymmetricDifferenceOf",
+         "type": "object"
+      },
+      "UnionOf": {
+         "additionalProperties": false,
+         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "UnionOf",
+               "default": "UnionOf",
+               "enum": [
+                  "UnionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "UnionOf",
+         "type": "object"
+      },
+      "Zip": {
+         "additionalProperties": false,
+         "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n  the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Spec",
+               "description": "The left-hand Spec to Zip, will appear earlier in axes"
+            },
+            "right": {
+               "$ref": "#/$defs/Spec",
+               "description": "The right-hand Spec to Zip, will appear later in axes"
+            },
+            "type": {
+               "const": "Zip",
+               "default": "Zip",
+               "enum": [
+                  "Zip"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "Zip",
+         "type": "object"
+      }
+   },
+   "$ref": "#/$defs/Concat"
+}
+
+
+

+
Fields:
+
+
+
+
+
+field check_path_changes: bool = True#
+

If True path through scan will not be modified by squash

+
+ +
+
+field gap: bool = False#
+

If True, force a gap in the output at the join

+
+ +
+
+field left: Spec[Axis] [Required]#
+

The left-hand Spec to Concat, midpoints will appear earlier

+
+ +
+
+field right: Spec[Axis] [Required]#
+

The right-hand Spec to Concat, midpoints will appear later

+
+ +
+
+field type: Literal['Concat'] = 'Concat'#
+
+ +
+
+axes() list[Axis][source]#
+

Return the list of axes that are present in the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+
+calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#
+

Produce a stack of nested Frames that form the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+ +
+
+pydantic model scanspec.specs.Squash[source]#
+

Squash a stack of Frames together into a single expanded Frames object.

+ +
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Line, Squash
+
+spec = Squash(Line("y", 1, 2, 3) * Line("x", 0, 1, 4))
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-8.png +
+

+Show JSON schema
{
+   "$defs": {
+      "Circle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the circle",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the circle",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "radius": {
+               "description": "Radius of the circle",
+               "exclusiveMinimum": 0.0,
+               "title": "Radius",
+               "type": "number"
+            },
+            "type": {
+               "const": "Circle",
+               "default": "Circle",
+               "enum": [
+                  "Circle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "radius"
+         ],
+         "title": "Circle",
+         "type": "object"
+      },
+      "CombinationOf": {
+         "additionalProperties": false,
+         "description": "Abstract baseclass for a combination of two regions, left and right.",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "CombinationOf",
+               "default": "CombinationOf",
+               "enum": [
+                  "CombinationOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "CombinationOf",
+         "type": "object"
+      },
+      "Concat": {
+         "additionalProperties": false,
+         "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Spec",
+               "description": "The left-hand Spec to Concat, midpoints will appear earlier"
+            },
+            "right": {
+               "$ref": "#/$defs/Spec",
+               "description": "The right-hand Spec to Concat, midpoints will appear later"
+            },
+            "gap": {
+               "default": false,
+               "description": "If True, force a gap in the output at the join",
+               "title": "Gap",
+               "type": "boolean"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Concat",
+               "default": "Concat",
+               "enum": [
+                  "Concat"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "Concat",
+         "type": "object"
+      },
+      "DifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "DifferenceOf",
+               "default": "DifferenceOf",
+               "enum": [
+                  "DifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "DifferenceOf",
+         "type": "object"
+      },
+      "Ellipse": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_middle": {
+               "description": "The central x point of the ellipse",
+               "title": "X Middle",
+               "type": "number"
+            },
+            "y_middle": {
+               "description": "The central y point of the ellipse",
+               "title": "Y Middle",
+               "type": "number"
+            },
+            "x_radius": {
+               "description": "The radius along the x axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "X Radius",
+               "type": "number"
+            },
+            "y_radius": {
+               "description": "The radius along the y axis of the ellipse",
+               "exclusiveMinimum": 0.0,
+               "title": "Y Radius",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "The angle of the ellipse (degrees)",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Ellipse",
+               "default": "Ellipse",
+               "enum": [
+                  "Ellipse"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_middle",
+            "y_middle",
+            "x_radius",
+            "y_radius"
+         ],
+         "title": "Ellipse",
+         "type": "object"
+      },
+      "IntersectionOf": {
+         "additionalProperties": false,
+         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "IntersectionOf",
+               "default": "IntersectionOf",
+               "enum": [
+                  "IntersectionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "IntersectionOf",
+         "type": "object"
+      },
+      "Line": {
+         "additionalProperties": false,
+         "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 2, 5)",
+         "properties": {
+            "axis": {
+               "description": "An identifier for what to move",
+               "title": "Axis"
+            },
+            "start": {
+               "description": "Midpoint of the first point of the line",
+               "title": "Start",
+               "type": "number"
+            },
+            "stop": {
+               "description": "Midpoint of the last point of the line",
+               "title": "Stop",
+               "type": "number"
+            },
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "type": {
+               "const": "Line",
+               "default": "Line",
+               "enum": [
+                  "Line"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "start",
+            "stop",
+            "num"
+         ],
+         "title": "Line",
+         "type": "object"
+      },
+      "Mask": {
+         "additionalProperties": false,
+         "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec containing the source midpoints"
+            },
+            "region": {
+               "$ref": "#/$defs/Region",
+               "description": "The Region that midpoints will be inside"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Mask",
+               "default": "Mask",
+               "enum": [
+                  "Mask"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec",
+            "region"
+         ],
+         "title": "Mask",
+         "type": "object"
+      },
+      "Polygon": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_verts": {
+               "description": "The Nx1 x coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "X Verts",
+               "type": "array"
+            },
+            "y_verts": {
+               "description": "The Nx1 y coordinates of the polygons vertices",
+               "items": {
+                  "type": "number"
+               },
+               "minItems": 3,
+               "title": "Y Verts",
+               "type": "array"
+            },
+            "type": {
+               "const": "Polygon",
+               "default": "Polygon",
+               "enum": [
+                  "Polygon"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_verts",
+            "y_verts"
+         ],
+         "title": "Polygon",
+         "type": "object"
+      },
+      "Product": {
+         "additionalProperties": false,
+         "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)",
+         "properties": {
+            "outer": {
+               "$ref": "#/$defs/Spec",
+               "description": "Will be executed once"
+            },
+            "inner": {
+               "$ref": "#/$defs/Spec",
+               "description": "Will be executed len(outer) times"
+            },
+            "type": {
+               "const": "Product",
+               "default": "Product",
+               "enum": [
+                  "Product"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "outer",
+            "inner"
+         ],
+         "title": "Product",
+         "type": "object"
+      },
+      "Range": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
+         "properties": {
+            "axis": {
+               "description": "The name matching the axis to mask in spec",
+               "title": "Axis"
+            },
+            "min": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Min",
+               "type": "number"
+            },
+            "max": {
+               "description": "The minimum inclusive value in the region",
+               "title": "Max",
+               "type": "number"
+            },
+            "type": {
+               "const": "Range",
+               "default": "Range",
+               "enum": [
+                  "Range"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "min",
+            "max"
+         ],
+         "title": "Range",
+         "type": "object"
+      },
+      "Rectangle": {
+         "additionalProperties": false,
+         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "The name matching the x axis of the spec",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "The name matching the y axis of the spec",
+               "title": "Y Axis"
+            },
+            "x_min": {
+               "description": "Minimum inclusive x value in the region",
+               "title": "X Min",
+               "type": "number"
+            },
+            "y_min": {
+               "description": "Minimum inclusive y value in the region",
+               "title": "Y Min",
+               "type": "number"
+            },
+            "x_max": {
+               "description": "Maximum inclusive x value in the region",
+               "title": "X Max",
+               "type": "number"
+            },
+            "y_max": {
+               "description": "Maximum inclusive y value in the region",
+               "title": "Y Max",
+               "type": "number"
+            },
+            "angle": {
+               "default": 0.0,
+               "description": "Clockwise rotation angle of the rectangle",
+               "title": "Angle",
+               "type": "number"
+            },
+            "type": {
+               "const": "Rectangle",
+               "default": "Rectangle",
+               "enum": [
+                  "Rectangle"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_min",
+            "y_min",
+            "x_max",
+            "y_max"
+         ],
+         "title": "Rectangle",
+         "type": "object"
+      },
+      "Region": {
+         "discriminator": {
+            "mapping": {
+               "Circle": "#/$defs/Circle",
+               "CombinationOf": "#/$defs/CombinationOf",
+               "DifferenceOf": "#/$defs/DifferenceOf",
+               "Ellipse": "#/$defs/Ellipse",
+               "IntersectionOf": "#/$defs/IntersectionOf",
+               "Polygon": "#/$defs/Polygon",
+               "Range": "#/$defs/Range",
+               "Rectangle": "#/$defs/Rectangle",
+               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
+               "UnionOf": "#/$defs/UnionOf"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/CombinationOf"
+            },
+            {
+               "$ref": "#/$defs/UnionOf"
+            },
+            {
+               "$ref": "#/$defs/IntersectionOf"
+            },
+            {
+               "$ref": "#/$defs/DifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/SymmetricDifferenceOf"
+            },
+            {
+               "$ref": "#/$defs/Range"
+            },
+            {
+               "$ref": "#/$defs/Rectangle"
+            },
+            {
+               "$ref": "#/$defs/Polygon"
+            },
+            {
+               "$ref": "#/$defs/Circle"
+            },
+            {
+               "$ref": "#/$defs/Ellipse"
+            }
+         ]
+      },
+      "Repeat": {
+         "additionalProperties": false,
+         "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n    from scanspec.specs import Line, Repeat\n\n    spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4",
+         "properties": {
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "gap": {
+               "default": true,
+               "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap",
+               "title": "Gap",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Repeat",
+               "default": "Repeat",
+               "enum": [
+                  "Repeat"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "num"
+         ],
+         "title": "Repeat",
+         "type": "object"
+      },
+      "Snake": {
+         "additionalProperties": false,
+         "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec to run in reverse every other iteration"
+            },
+            "type": {
+               "const": "Snake",
+               "default": "Snake",
+               "enum": [
+                  "Snake"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec"
+         ],
+         "title": "Snake",
+         "type": "object"
+      },
+      "Spec": {
+         "discriminator": {
+            "mapping": {
+               "Concat": "#/$defs/Concat",
+               "Line": "#/$defs/Line",
+               "Mask": "#/$defs/Mask",
+               "Product": "#/$defs/Product",
+               "Repeat": "#/$defs/Repeat",
+               "Snake": "#/$defs/Snake",
+               "Spiral": "#/$defs/Spiral",
+               "Squash": "#/$defs/Squash",
+               "Static": "#/$defs/Static",
+               "Zip": "#/$defs/Zip"
+            },
+            "propertyName": "type"
+         },
+         "oneOf": [
+            {
+               "$ref": "#/$defs/Product"
+            },
+            {
+               "$ref": "#/$defs/Repeat"
+            },
+            {
+               "$ref": "#/$defs/Zip"
+            },
+            {
+               "$ref": "#/$defs/Mask"
+            },
+            {
+               "$ref": "#/$defs/Snake"
+            },
+            {
+               "$ref": "#/$defs/Concat"
+            },
+            {
+               "$ref": "#/$defs/Squash"
+            },
+            {
+               "$ref": "#/$defs/Line"
+            },
+            {
+               "$ref": "#/$defs/Static"
+            },
+            {
+               "$ref": "#/$defs/Spiral"
+            }
+         ]
+      },
+      "Spiral": {
+         "additionalProperties": false,
+         "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n    from scanspec.specs import Spiral\n\n    spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)",
+         "properties": {
+            "x_axis": {
+               "description": "An identifier for what to move for x",
+               "title": "X Axis"
+            },
+            "y_axis": {
+               "description": "An identifier for what to move for y",
+               "title": "Y Axis"
+            },
+            "x_start": {
+               "description": "x centre of the spiral",
+               "title": "X Start",
+               "type": "number"
+            },
+            "y_start": {
+               "description": "y centre of the spiral",
+               "title": "Y Start",
+               "type": "number"
+            },
+            "x_range": {
+               "description": "x width of the spiral",
+               "title": "X Range",
+               "type": "number"
+            },
+            "y_range": {
+               "description": "y width of the spiral",
+               "title": "Y Range",
+               "type": "number"
+            },
+            "num": {
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "rotate": {
+               "default": 0.0,
+               "description": "How much to rotate the angle of the spiral",
+               "title": "Rotate",
+               "type": "number"
+            },
+            "type": {
+               "const": "Spiral",
+               "default": "Spiral",
+               "enum": [
+                  "Spiral"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "x_axis",
+            "y_axis",
+            "x_start",
+            "y_start",
+            "x_range",
+            "y_range",
+            "num"
+         ],
+         "title": "Spiral",
+         "type": "object"
+      },
+      "Squash": {
+         "additionalProperties": false,
+         "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n    `why-squash-can-change-path`\n\n.. example_spec::\n\n    from scanspec.specs import Line, Squash\n\n    spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))",
+         "properties": {
+            "spec": {
+               "$ref": "#/$defs/Spec",
+               "description": "The Spec to squash the dimensions of"
+            },
+            "check_path_changes": {
+               "default": true,
+               "description": "If True path through scan will not be modified by squash",
+               "title": "Check Path Changes",
+               "type": "boolean"
+            },
+            "type": {
+               "const": "Squash",
+               "default": "Squash",
+               "enum": [
+                  "Squash"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "spec"
+         ],
+         "title": "Squash",
+         "type": "object"
+      },
+      "Static": {
+         "additionalProperties": false,
+         "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n    from scanspec.specs import Line, Static\n\n    spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))",
+         "properties": {
+            "axis": {
+               "description": "An identifier for what to move",
+               "title": "Axis"
+            },
+            "value": {
+               "description": "The value at each point",
+               "title": "Value",
+               "type": "number"
+            },
+            "num": {
+               "default": 1,
+               "description": "Number of frames to produce",
+               "minimum": 1,
+               "title": "Num",
+               "type": "integer"
+            },
+            "type": {
+               "const": "Static",
+               "default": "Static",
+               "enum": [
+                  "Static"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "axis",
+            "value"
+         ],
+         "title": "Static",
+         "type": "object"
+      },
+      "SymmetricDifferenceOf": {
+         "additionalProperties": false,
+         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "SymmetricDifferenceOf",
+               "default": "SymmetricDifferenceOf",
+               "enum": [
+                  "SymmetricDifferenceOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "SymmetricDifferenceOf",
+         "type": "object"
+      },
+      "UnionOf": {
+         "additionalProperties": false,
+         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Region",
+               "description": "The left-hand Region to combine"
+            },
+            "right": {
+               "$ref": "#/$defs/Region",
+               "description": "The right-hand Region to combine"
+            },
+            "type": {
+               "const": "UnionOf",
+               "default": "UnionOf",
+               "enum": [
+                  "UnionOf"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "UnionOf",
+         "type": "object"
+      },
+      "Zip": {
+         "additionalProperties": false,
+         "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n  the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))",
+         "properties": {
+            "left": {
+               "$ref": "#/$defs/Spec",
+               "description": "The left-hand Spec to Zip, will appear earlier in axes"
+            },
+            "right": {
+               "$ref": "#/$defs/Spec",
+               "description": "The right-hand Spec to Zip, will appear later in axes"
+            },
+            "type": {
+               "const": "Zip",
+               "default": "Zip",
+               "enum": [
+                  "Zip"
+               ],
+               "title": "Type",
+               "type": "string"
+            }
+         },
+         "required": [
+            "left",
+            "right"
+         ],
+         "title": "Zip",
+         "type": "object"
+      }
+   },
+   "$ref": "#/$defs/Squash"
+}
+
+
+

+
Fields:
+
+
+
+
+
+field check_path_changes: bool = True#
+

If True path through scan will not be modified by squash

+
+ +
+
+field spec: Spec[Axis] [Required]#
+

The Spec to squash the dimensions of

+
+ +
+
+field type: Literal['Squash'] = 'Squash'#
+
+ +
+
+axes() list[Axis][source]#
+

Return the list of axes that are present in the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+
+calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#
+

Produce a stack of nested Frames that form the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+ +
+
+pydantic model scanspec.specs.Line[source]#
+

Linearly spaced frames with start and stop as first and last midpoints.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Line
+
+spec = Line("x", 1, 2, 5)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-9.png +
+

+Show JSON schema
{
+   "title": "Line",
+   "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 2, 5)",
+   "type": "object",
+   "properties": {
+      "axis": {
+         "description": "An identifier for what to move",
+         "title": "Axis"
+      },
+      "start": {
+         "description": "Midpoint of the first point of the line",
+         "title": "Start",
+         "type": "number"
+      },
+      "stop": {
+         "description": "Midpoint of the last point of the line",
+         "title": "Stop",
+         "type": "number"
+      },
+      "num": {
+         "description": "Number of frames to produce",
+         "minimum": 1,
+         "title": "Num",
+         "type": "integer"
+      },
+      "type": {
+         "const": "Line",
+         "default": "Line",
+         "enum": [
+            "Line"
+         ],
+         "title": "Type",
+         "type": "string"
+      }
+   },
+   "additionalProperties": false,
+   "required": [
+      "axis",
+      "start",
+      "stop",
+      "num"
+   ]
+}
+
+
+

+
Fields:
+
+
+
+
+
+field axis: Axis [Required]#
+

An identifier for what to move

+
+ +
+
+field num: int [Required]#
+

Number of frames to produce

+
+
Constraints:
+
    +
  • ge = 1

  • +
+
+
+
+ +
+
+field start: float [Required]#
+

Midpoint of the first point of the line

+
+ +
+
+field stop: float [Required]#
+

Midpoint of the last point of the line

+
+ +
+
+field type: Literal['Line'] = 'Line'#
+
+ +
+
+axes() list[Axis][source]#
+

Return the list of axes that are present in the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+
+bounded(lower: float = FieldInfo(annotation=float, required=True, description='Lower bound of the first point of the line'), upper: float = FieldInfo(annotation=float, required=True, description='Upper bound of the last point of the line'), num: int = FieldInfo(annotation=int, required=True, description='Number of frames to produce', metadata=[Ge(ge=1)])) Line[OtherAxis][source]#
+

Specify a Line by extreme bounds instead of midpoints.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Line
+
+spec = Line.bounded("x", 1, 2, 5)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-10.png +
+
+ +
+
+calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#
+

Produce a stack of nested Frames that form the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+ +
+
+pydantic model scanspec.specs.Static[source]#
+

A static frame, repeated num times, with axis at value.

+

Can be used to set axis=value at every point in a scan.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Line, Static
+
+spec = Line("y", 1, 2, 3).zip(Static("x", 3))
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-11.png +
+

+Show JSON schema
{
+   "title": "Static",
+   "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n    from scanspec.specs import Line, Static\n\n    spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))",
+   "type": "object",
+   "properties": {
+      "axis": {
+         "description": "An identifier for what to move",
+         "title": "Axis"
+      },
+      "value": {
+         "description": "The value at each point",
+         "title": "Value",
+         "type": "number"
+      },
+      "num": {
+         "default": 1,
+         "description": "Number of frames to produce",
+         "minimum": 1,
+         "title": "Num",
+         "type": "integer"
+      },
+      "type": {
+         "const": "Static",
+         "default": "Static",
+         "enum": [
+            "Static"
+         ],
+         "title": "Type",
+         "type": "string"
+      }
+   },
+   "additionalProperties": false,
+   "required": [
+      "axis",
+      "value"
+   ]
+}
+
+
+

+
Fields:
+
+
+
+
+
+field axis: Axis [Required]#
+

An identifier for what to move

+
+ +
+
+field num: int = 1#
+

Number of frames to produce

+
+
Constraints:
+
    +
  • ge = 1

  • +
+
+
+
+ +
+
+field type: Literal['Static'] = 'Static'#
+
+ +
+
+field value: float [Required]#
+

The value at each point

+
+ +
+
+axes() list[Axis][source]#
+

Return the list of axes that are present in the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+
+calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#
+

Produce a stack of nested Frames that form the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+
+duration(num: int = FieldInfo(annotation=int, required=False, default=1, description='Number of frames to produce', metadata=[Ge(ge=1)])) Static[str][source]#
+

A static spec with no motion, only a duration repeated “num” times.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Line, Static
+
+spec = Line("y", 1, 2, 3).zip(Static.duration(0.1))
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-12.png +
+
+ +
+ +
+
+pydantic model scanspec.specs.Spiral[source]#
+

Archimedean spiral of “x_axis” and “y_axis”.

+

Starts at centre point (“x_start”, “y_start”) with angle “rotate”. Produces +“num” points in a spiral spanning width of “x_range” and height of “y_range”

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Spiral
+
+spec = Spiral("x", "y", 1, 5, 10, 50, 30)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-13.png +
+

+Show JSON schema
{
+   "title": "Spiral",
+   "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n    from scanspec.specs import Spiral\n\n    spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)",
+   "type": "object",
+   "properties": {
+      "x_axis": {
+         "description": "An identifier for what to move for x",
+         "title": "X Axis"
+      },
+      "y_axis": {
+         "description": "An identifier for what to move for y",
+         "title": "Y Axis"
+      },
+      "x_start": {
+         "description": "x centre of the spiral",
+         "title": "X Start",
+         "type": "number"
+      },
+      "y_start": {
+         "description": "y centre of the spiral",
+         "title": "Y Start",
+         "type": "number"
+      },
+      "x_range": {
+         "description": "x width of the spiral",
+         "title": "X Range",
+         "type": "number"
+      },
+      "y_range": {
+         "description": "y width of the spiral",
+         "title": "Y Range",
+         "type": "number"
+      },
+      "num": {
+         "description": "Number of frames to produce",
+         "minimum": 1,
+         "title": "Num",
+         "type": "integer"
+      },
+      "rotate": {
+         "default": 0.0,
+         "description": "How much to rotate the angle of the spiral",
+         "title": "Rotate",
+         "type": "number"
+      },
+      "type": {
+         "const": "Spiral",
+         "default": "Spiral",
+         "enum": [
+            "Spiral"
+         ],
+         "title": "Type",
+         "type": "string"
+      }
+   },
+   "additionalProperties": false,
+   "required": [
+      "x_axis",
+      "y_axis",
+      "x_start",
+      "y_start",
+      "x_range",
+      "y_range",
+      "num"
+   ]
+}
+
+
+

+
Fields:
+
+
+
+
+
+field num: int [Required]#
+

Number of frames to produce

+
+
Constraints:
+
    +
  • ge = 1

  • +
+
+
+
+ +
+
+field rotate: float = 0.0#
+

How much to rotate the angle of the spiral

+
+ +
+
+field type: Literal['Spiral'] = 'Spiral'#
+
+ +
+
+field x_axis: Axis [Required]#
+

An identifier for what to move for x

+
+ +
+
+field x_range: float [Required]#
+

x width of the spiral

+
+ +
+
+field x_start: float [Required]#
+

x centre of the spiral

+
+ +
+
+field y_axis: Axis [Required]#
+

An identifier for what to move for y

+
+ +
+
+field y_range: float [Required]#
+

y width of the spiral

+
+ +
+
+field y_start: float [Required]#
+

y centre of the spiral

+
+ +
+
+axes() list[Axis][source]#
+

Return the list of axes that are present in the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+
+calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#
+

Produce a stack of nested Frames that form the scan.

+

Ordered from slowest moving to fastest moving.

+
+ +
+
+spaced(y_axis: OtherAxis = FieldInfo(annotation=~OtherAxis, required=True, description='An identifier for what to move for y'), x_start: float = FieldInfo(annotation=float, required=True, description='x centre of the spiral'), y_start: float = FieldInfo(annotation=float, required=True, description='y centre of the spiral'), radius: float = FieldInfo(annotation=float, required=True, description='radius of the spiral'), dr: float = FieldInfo(annotation=float, required=True, description='difference between each ring'), rotate: float = FieldInfo(annotation=float, required=False, default=0.0, description='How much to rotate the angle of the spiral')) Spiral[OtherAxis][source]#
+

Specify a Spiral equally spaced in “x_axis” and “y_axis”.

+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Spiral
+
+spec = Spiral.spaced("x", "y", 0, 0, 10, 3)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-14.png +
+
+ +
+ +
+
+scanspec.specs.fly(spec: Spec[Axis], duration: float) Spec[Axis | str][source]#
+

Flyscan, zipping with fixed duration for every frame.

+
+
Parameters:
+
    +
  • spec – The source Spec to continuously move

  • +
  • duration – How long to spend at each frame in the spec

  • +
+
+
+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Line, fly
+
+spec = fly(Line("x", 1, 2, 3), 0.1)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-15.png +
+
+ +
+
+scanspec.specs.step(spec: Spec[Axis], duration: float, num: int = 1) Spec[Axis | str][source]#
+

Step scan, with num frames of given duration at each frame in the spec.

+
+
Parameters:
+
    +
  • spec – The source Spec with midpoints to move to and stop

  • +
  • duration – The duration of each scan frame

  • +
  • num – Number of frames to produce with given duration at each of frame +in the spec

  • +
+
+
+
# Example Spec
+
+from scanspec.plot import plot_spec
+from scanspec.specs import Line, step
+
+spec = step(Line("x", 1, 2, 3), 0.1)
+plot_spec(spec)
+
+
+

(Source code, png, hires.png, pdf)

+
+../_images/scanspec-specs-16.png +
+
+ +
+ + +
+ + + + + + + +
+ + + + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/0.7.5/_downloads/0223a88adc6d09735d8fff79b4ca64a0/scanspec-regions-3.py b/0.7.5/_downloads/0223a88adc6d09735d8fff79b4ca64a0/scanspec-regions-3.py new file mode 100644 index 00000000..aff5125b --- /dev/null +++ b/0.7.5/_downloads/0223a88adc6d09735d8fff79b4ca64a0/scanspec-regions-3.py @@ -0,0 +1,9 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.regions import Circle +from scanspec.specs import Line + +grid = Line("y", 1, 3, 10) * ~Line("x", 0, 2, 10) +spec = grid & Circle("x", "y", 1, 2, 0.9) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/029d34da503729102c31e8b9bcdcce2a/scanspec-specs-6.py b/0.7.5/_downloads/029d34da503729102c31e8b9bcdcce2a/scanspec-specs-6.py new file mode 100644 index 00000000..f10a8074 --- /dev/null +++ b/0.7.5/_downloads/029d34da503729102c31e8b9bcdcce2a/scanspec-specs-6.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line + +spec = Line("y", 1, 3, 3) * ~Line("x", 3, 5, 5) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/03d02dd7fcbfa209b8e8fc653cd48fe9/why-squash-can-change-path-3.hires.png b/0.7.5/_downloads/03d02dd7fcbfa209b8e8fc653cd48fe9/why-squash-can-change-path-3.hires.png new file mode 100644 index 00000000..eee6af18 Binary files /dev/null and b/0.7.5/_downloads/03d02dd7fcbfa209b8e8fc653cd48fe9/why-squash-can-change-path-3.hires.png differ diff --git a/0.7.5/_downloads/03df8facf6b141a80c01c64943a8d53d/why-squash-can-change-path-1.py b/0.7.5/_downloads/03df8facf6b141a80c01c64943a8d53d/why-squash-can-change-path-1.py new file mode 100644 index 00000000..3212fde7 --- /dev/null +++ b/0.7.5/_downloads/03df8facf6b141a80c01c64943a8d53d/why-squash-can-change-path-1.py @@ -0,0 +1,5 @@ +from scanspec.specs import Line +from scanspec.plot import plot_spec + +spec = Line("z", 0, 1, 3) * ~Line("y", 0, 1, 3) * Line("x", 0, 1, 3) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/090ae78c4b6455d5980148fff5aa44c2/creating-a-spec-3.hires.png b/0.7.5/_downloads/090ae78c4b6455d5980148fff5aa44c2/creating-a-spec-3.hires.png new file mode 100644 index 00000000..9f28434d Binary files /dev/null and b/0.7.5/_downloads/090ae78c4b6455d5980148fff5aa44c2/creating-a-spec-3.hires.png differ diff --git a/0.7.5/_downloads/0ae73fb7939821b1edc3d22233280318/scanspec-regions-1.pdf b/0.7.5/_downloads/0ae73fb7939821b1edc3d22233280318/scanspec-regions-1.pdf new file mode 100644 index 00000000..d52953b1 Binary files /dev/null and b/0.7.5/_downloads/0ae73fb7939821b1edc3d22233280318/scanspec-regions-1.pdf differ diff --git a/0.7.5/_downloads/0b4799657e877d5b1b4cacd9b2acb170/why-squash-can-change-path-3.pdf b/0.7.5/_downloads/0b4799657e877d5b1b4cacd9b2acb170/why-squash-can-change-path-3.pdf new file mode 100644 index 00000000..a378046a Binary files /dev/null and b/0.7.5/_downloads/0b4799657e877d5b1b4cacd9b2acb170/why-squash-can-change-path-3.pdf differ diff --git a/0.7.5/_downloads/0e091704af9d4694c1d1ec0a0954dc8f/scanspec-regions-2.png b/0.7.5/_downloads/0e091704af9d4694c1d1ec0a0954dc8f/scanspec-regions-2.png new file mode 100644 index 00000000..bb1adfdb Binary files /dev/null and b/0.7.5/_downloads/0e091704af9d4694c1d1ec0a0954dc8f/scanspec-regions-2.png differ diff --git a/0.7.5/_downloads/13b77470026a004a78b9fe0d8381851c/creating-a-spec-1.py b/0.7.5/_downloads/13b77470026a004a78b9fe0d8381851c/creating-a-spec-1.py new file mode 100644 index 00000000..d40cfb88 --- /dev/null +++ b/0.7.5/_downloads/13b77470026a004a78b9fe0d8381851c/creating-a-spec-1.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line + +spec = Line("x", 1, 2, 5) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/140a97216923402012aba5e48fea542e/why-squash-can-change-path-4.py b/0.7.5/_downloads/140a97216923402012aba5e48fea542e/why-squash-can-change-path-4.py new file mode 100644 index 00000000..e4881c6e --- /dev/null +++ b/0.7.5/_downloads/140a97216923402012aba5e48fea542e/why-squash-can-change-path-4.py @@ -0,0 +1,7 @@ +from scanspec.specs import Line, Squash +from scanspec.plot import plot_spec + +spec = Line("z", 0, 1, 3) * Squash( + Line("y", 0, 1, 3) * ~Line("x", 0, 1, 3), check_path_changes=False +) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/1473d71a9aa74675a8d9df70051456f4/scanspec-specs-8.png b/0.7.5/_downloads/1473d71a9aa74675a8d9df70051456f4/scanspec-specs-8.png new file mode 100644 index 00000000..6cf49529 Binary files /dev/null and b/0.7.5/_downloads/1473d71a9aa74675a8d9df70051456f4/scanspec-specs-8.png differ diff --git a/0.7.5/_downloads/14cd9f05ba952a1aeae7bc548b9fd177/scanspec-specs-3.pdf b/0.7.5/_downloads/14cd9f05ba952a1aeae7bc548b9fd177/scanspec-specs-3.pdf new file mode 100644 index 00000000..e6e36e77 Binary files /dev/null and b/0.7.5/_downloads/14cd9f05ba952a1aeae7bc548b9fd177/scanspec-specs-3.pdf differ diff --git a/0.7.5/_downloads/17b16611218f29da558120b1699442be/scanspec-specs-11.py b/0.7.5/_downloads/17b16611218f29da558120b1699442be/scanspec-specs-11.py new file mode 100644 index 00000000..2132f391 --- /dev/null +++ b/0.7.5/_downloads/17b16611218f29da558120b1699442be/scanspec-specs-11.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line, Static + +spec = Line("y", 1, 2, 3).zip(Static("x", 3)) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/1881c7b7398842eb252241a18e511a61/scanspec-regions-2.py b/0.7.5/_downloads/1881c7b7398842eb252241a18e511a61/scanspec-regions-2.py new file mode 100644 index 00000000..845343f9 --- /dev/null +++ b/0.7.5/_downloads/1881c7b7398842eb252241a18e511a61/scanspec-regions-2.py @@ -0,0 +1,9 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.regions import Polygon +from scanspec.specs import Line + +grid = Line("y", 3, 8, 10) * ~Line("x", 1 ,8, 10) +spec = grid & Polygon("x", "y", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0]) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/1aef3bb8ee2a641e32a2d2d96e29b7b6/scanspec-specs-4.hires.png b/0.7.5/_downloads/1aef3bb8ee2a641e32a2d2d96e29b7b6/scanspec-specs-4.hires.png new file mode 100644 index 00000000..85b2152a Binary files /dev/null and b/0.7.5/_downloads/1aef3bb8ee2a641e32a2d2d96e29b7b6/scanspec-specs-4.hires.png differ diff --git a/0.7.5/_downloads/1f2bf7a0ab5a81274b679654b2cfceaa/creating-a-spec-4.png b/0.7.5/_downloads/1f2bf7a0ab5a81274b679654b2cfceaa/creating-a-spec-4.png new file mode 100644 index 00000000..418231fb Binary files /dev/null and b/0.7.5/_downloads/1f2bf7a0ab5a81274b679654b2cfceaa/creating-a-spec-4.png differ diff --git a/0.7.5/_downloads/25365eba811f6b456fe24829840ed193/why-squash-can-change-path-4.png b/0.7.5/_downloads/25365eba811f6b456fe24829840ed193/why-squash-can-change-path-4.png new file mode 100644 index 00000000..6f9e373a Binary files /dev/null and b/0.7.5/_downloads/25365eba811f6b456fe24829840ed193/why-squash-can-change-path-4.png differ diff --git a/0.7.5/_downloads/28f92b8fad4dde904a13111227dc1427/scanspec-specs-9.png b/0.7.5/_downloads/28f92b8fad4dde904a13111227dc1427/scanspec-specs-9.png new file mode 100644 index 00000000..04509ee2 Binary files /dev/null and b/0.7.5/_downloads/28f92b8fad4dde904a13111227dc1427/scanspec-specs-9.png differ diff --git a/0.7.5/_downloads/29ca263728fd0f8d0c6cfad280625143/scanspec-specs-7.py b/0.7.5/_downloads/29ca263728fd0f8d0c6cfad280625143/scanspec-specs-7.py new file mode 100644 index 00000000..b1474a68 --- /dev/null +++ b/0.7.5/_downloads/29ca263728fd0f8d0c6cfad280625143/scanspec-specs-7.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line + +spec = Line("x", 1, 3, 3).concat(Line("x", 4, 5, 5)) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/29efac10d5b5e4957caf26c08046ad85/scanspec-specs-15.png b/0.7.5/_downloads/29efac10d5b5e4957caf26c08046ad85/scanspec-specs-15.png new file mode 100644 index 00000000..cd0b2340 Binary files /dev/null and b/0.7.5/_downloads/29efac10d5b5e4957caf26c08046ad85/scanspec-specs-15.png differ diff --git a/0.7.5/_downloads/29f8e9f676c07ef454b88a78fef753ad/scanspec-specs-10.pdf b/0.7.5/_downloads/29f8e9f676c07ef454b88a78fef753ad/scanspec-specs-10.pdf new file mode 100644 index 00000000..a16439a0 Binary files /dev/null and b/0.7.5/_downloads/29f8e9f676c07ef454b88a78fef753ad/scanspec-specs-10.pdf differ diff --git a/0.7.5/_downloads/2bdcf85251aa86ede3065d379aff5cd7/scanspec-specs-13.py b/0.7.5/_downloads/2bdcf85251aa86ede3065d379aff5cd7/scanspec-specs-13.py new file mode 100644 index 00000000..41d808fc --- /dev/null +++ b/0.7.5/_downloads/2bdcf85251aa86ede3065d379aff5cd7/scanspec-specs-13.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Spiral + +spec = Spiral("x", "y", 1, 5, 10, 50, 30) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/2c9a9fd7b530c5c706073c6c74b7e9c8/scanspec-regions-1.py b/0.7.5/_downloads/2c9a9fd7b530c5c706073c6c74b7e9c8/scanspec-regions-1.py new file mode 100644 index 00000000..9fd0362c --- /dev/null +++ b/0.7.5/_downloads/2c9a9fd7b530c5c706073c6c74b7e9c8/scanspec-regions-1.py @@ -0,0 +1,9 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.regions import Rectangle +from scanspec.specs import Line + +grid = Line("y", 1, 3, 10) * ~Line("x", 0, 2, 10) +spec = grid & Rectangle("x", "y", 0, 1.1, 1.5, 2.1, 30) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/2cfa1a7efa170f3f496b6daff9bb2c49/creating-a-spec-6.hires.png b/0.7.5/_downloads/2cfa1a7efa170f3f496b6daff9bb2c49/creating-a-spec-6.hires.png new file mode 100644 index 00000000..3c00ab6d Binary files /dev/null and b/0.7.5/_downloads/2cfa1a7efa170f3f496b6daff9bb2c49/creating-a-spec-6.hires.png differ diff --git a/0.7.5/_downloads/3114561b7e33fb4f9b1b212000aa552b/scanspec-specs-13.png b/0.7.5/_downloads/3114561b7e33fb4f9b1b212000aa552b/scanspec-specs-13.png new file mode 100644 index 00000000..64604a20 Binary files /dev/null and b/0.7.5/_downloads/3114561b7e33fb4f9b1b212000aa552b/scanspec-specs-13.png differ diff --git a/0.7.5/_downloads/32c9e69b107f5cd11ed75edfef7a521c/creating-a-spec-4.pdf b/0.7.5/_downloads/32c9e69b107f5cd11ed75edfef7a521c/creating-a-spec-4.pdf new file mode 100644 index 00000000..322f2a2d Binary files /dev/null and b/0.7.5/_downloads/32c9e69b107f5cd11ed75edfef7a521c/creating-a-spec-4.pdf differ diff --git a/0.7.5/_downloads/36360e8aeabfd64e7339de3c85a6a2ae/scanspec-specs-2.pdf b/0.7.5/_downloads/36360e8aeabfd64e7339de3c85a6a2ae/scanspec-specs-2.pdf new file mode 100644 index 00000000..664d4081 Binary files /dev/null and b/0.7.5/_downloads/36360e8aeabfd64e7339de3c85a6a2ae/scanspec-specs-2.pdf differ diff --git a/0.7.5/_downloads/36534493a6d19b6411e1895d931db289/creating-a-spec-1.hires.png b/0.7.5/_downloads/36534493a6d19b6411e1895d931db289/creating-a-spec-1.hires.png new file mode 100644 index 00000000..fbd32b10 Binary files /dev/null and b/0.7.5/_downloads/36534493a6d19b6411e1895d931db289/creating-a-spec-1.hires.png differ diff --git a/0.7.5/_downloads/391cf72d62c69bafc113af94890f714e/scanspec-specs-10.py b/0.7.5/_downloads/391cf72d62c69bafc113af94890f714e/scanspec-specs-10.py new file mode 100644 index 00000000..bff58d33 --- /dev/null +++ b/0.7.5/_downloads/391cf72d62c69bafc113af94890f714e/scanspec-specs-10.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line + +spec = Line.bounded("x", 1, 2, 5) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/3bd32d2e3c3a3b9ab90bef32dc7012ec/why-squash-can-change-path-2.png b/0.7.5/_downloads/3bd32d2e3c3a3b9ab90bef32dc7012ec/why-squash-can-change-path-2.png new file mode 100644 index 00000000..8c32b3a5 Binary files /dev/null and b/0.7.5/_downloads/3bd32d2e3c3a3b9ab90bef32dc7012ec/why-squash-can-change-path-2.png differ diff --git a/0.7.5/_downloads/4076f4b2e334f3de92b85af48122e3ab/scanspec-specs-9.py b/0.7.5/_downloads/4076f4b2e334f3de92b85af48122e3ab/scanspec-specs-9.py new file mode 100644 index 00000000..d40cfb88 --- /dev/null +++ b/0.7.5/_downloads/4076f4b2e334f3de92b85af48122e3ab/scanspec-specs-9.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line + +spec = Line("x", 1, 2, 5) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/41ee09f6b8792abbc8b43852678d87f3/scanspec-regions-3.hires.png b/0.7.5/_downloads/41ee09f6b8792abbc8b43852678d87f3/scanspec-regions-3.hires.png new file mode 100644 index 00000000..1155ca67 Binary files /dev/null and b/0.7.5/_downloads/41ee09f6b8792abbc8b43852678d87f3/scanspec-regions-3.hires.png differ diff --git a/0.7.5/_downloads/4509167960562ec708efdd0be55da36c/scanspec-regions-4.png b/0.7.5/_downloads/4509167960562ec708efdd0be55da36c/scanspec-regions-4.png new file mode 100644 index 00000000..27e11047 Binary files /dev/null and b/0.7.5/_downloads/4509167960562ec708efdd0be55da36c/scanspec-regions-4.png differ diff --git a/0.7.5/_downloads/495047b8b8a7867da4c99568301922ec/scanspec-specs-14.py b/0.7.5/_downloads/495047b8b8a7867da4c99568301922ec/scanspec-specs-14.py new file mode 100644 index 00000000..99605daf --- /dev/null +++ b/0.7.5/_downloads/495047b8b8a7867da4c99568301922ec/scanspec-specs-14.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Spiral + +spec = Spiral.spaced("x", "y", 0, 0, 10, 3) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/4ad72ca01eda81b905ebb3d9d4b4bd07/scanspec-specs-6.png b/0.7.5/_downloads/4ad72ca01eda81b905ebb3d9d4b4bd07/scanspec-specs-6.png new file mode 100644 index 00000000..bd687072 Binary files /dev/null and b/0.7.5/_downloads/4ad72ca01eda81b905ebb3d9d4b4bd07/scanspec-specs-6.png differ diff --git a/0.7.5/_downloads/4cff00b0b1d9fd7cbd80ee99b1324784/scanspec-specs-13.pdf b/0.7.5/_downloads/4cff00b0b1d9fd7cbd80ee99b1324784/scanspec-specs-13.pdf new file mode 100644 index 00000000..2e13b013 Binary files /dev/null and b/0.7.5/_downloads/4cff00b0b1d9fd7cbd80ee99b1324784/scanspec-specs-13.pdf differ diff --git a/0.7.5/_downloads/4d5401a5ef1906f42ef40eae55ca4842/scanspec-specs-16.hires.png b/0.7.5/_downloads/4d5401a5ef1906f42ef40eae55ca4842/scanspec-specs-16.hires.png new file mode 100644 index 00000000..f0ac194d Binary files /dev/null and b/0.7.5/_downloads/4d5401a5ef1906f42ef40eae55ca4842/scanspec-specs-16.hires.png differ diff --git a/0.7.5/_downloads/4e6a723d5cba2932d0dc34c140576fd6/scanspec-specs-8.pdf b/0.7.5/_downloads/4e6a723d5cba2932d0dc34c140576fd6/scanspec-specs-8.pdf new file mode 100644 index 00000000..e6c3ea5e Binary files /dev/null and b/0.7.5/_downloads/4e6a723d5cba2932d0dc34c140576fd6/scanspec-specs-8.pdf differ diff --git a/0.7.5/_downloads/4fea1518115551cb791d855e6a66eb55/scanspec-specs-3.png b/0.7.5/_downloads/4fea1518115551cb791d855e6a66eb55/scanspec-specs-3.png new file mode 100644 index 00000000..b1a79d80 Binary files /dev/null and b/0.7.5/_downloads/4fea1518115551cb791d855e6a66eb55/scanspec-specs-3.png differ diff --git a/0.7.5/_downloads/52bdbd66208e717704106cf91a12bc13/scanspec-regions-2.hires.png b/0.7.5/_downloads/52bdbd66208e717704106cf91a12bc13/scanspec-regions-2.hires.png new file mode 100644 index 00000000..e5649cc1 Binary files /dev/null and b/0.7.5/_downloads/52bdbd66208e717704106cf91a12bc13/scanspec-regions-2.hires.png differ diff --git a/0.7.5/_downloads/55477252c82aa8a8b1380f6521402e48/scanspec-specs-16.py b/0.7.5/_downloads/55477252c82aa8a8b1380f6521402e48/scanspec-specs-16.py new file mode 100644 index 00000000..e08f52ed --- /dev/null +++ b/0.7.5/_downloads/55477252c82aa8a8b1380f6521402e48/scanspec-specs-16.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line, step + +spec = step(Line("x", 1, 2, 3), 0.1) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/56bb872d1a387f9c4a1e9fd60023d0ad/scanspec-regions-4.pdf b/0.7.5/_downloads/56bb872d1a387f9c4a1e9fd60023d0ad/scanspec-regions-4.pdf new file mode 100644 index 00000000..43389a77 Binary files /dev/null and b/0.7.5/_downloads/56bb872d1a387f9c4a1e9fd60023d0ad/scanspec-regions-4.pdf differ diff --git a/0.7.5/_downloads/594f21876b9d2230f2a0af7771fd53e3/scanspec-regions-2.pdf b/0.7.5/_downloads/594f21876b9d2230f2a0af7771fd53e3/scanspec-regions-2.pdf new file mode 100644 index 00000000..f07beb6a Binary files /dev/null and b/0.7.5/_downloads/594f21876b9d2230f2a0af7771fd53e3/scanspec-regions-2.pdf differ diff --git a/0.7.5/_downloads/59ccb090bb2d3360ace4709fff9b5b3b/creating-a-spec-1.pdf b/0.7.5/_downloads/59ccb090bb2d3360ace4709fff9b5b3b/creating-a-spec-1.pdf new file mode 100644 index 00000000..96082a27 Binary files /dev/null and b/0.7.5/_downloads/59ccb090bb2d3360ace4709fff9b5b3b/creating-a-spec-1.pdf differ diff --git a/0.7.5/_downloads/5c0624426b92b4d678699185e497f06b/creating-a-spec-6.pdf b/0.7.5/_downloads/5c0624426b92b4d678699185e497f06b/creating-a-spec-6.pdf new file mode 100644 index 00000000..0ce15384 Binary files /dev/null and b/0.7.5/_downloads/5c0624426b92b4d678699185e497f06b/creating-a-spec-6.pdf differ diff --git a/0.7.5/_downloads/5f4cbd3d9eca3474f783397c1af34245/scanspec-specs-14.pdf b/0.7.5/_downloads/5f4cbd3d9eca3474f783397c1af34245/scanspec-specs-14.pdf new file mode 100644 index 00000000..f41b3ca1 Binary files /dev/null and b/0.7.5/_downloads/5f4cbd3d9eca3474f783397c1af34245/scanspec-specs-14.pdf differ diff --git a/0.7.5/_downloads/5fecf49fd9e18b0cbc137cab2570ce30/scanspec-specs-12.py b/0.7.5/_downloads/5fecf49fd9e18b0cbc137cab2570ce30/scanspec-specs-12.py new file mode 100644 index 00000000..726271d9 --- /dev/null +++ b/0.7.5/_downloads/5fecf49fd9e18b0cbc137cab2570ce30/scanspec-specs-12.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line, Static + +spec = Line("y", 1, 2, 3).zip(Static.duration(0.1)) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/603e53497bfdb6e0d5f199b9f65883a6/creating-a-spec-1.png b/0.7.5/_downloads/603e53497bfdb6e0d5f199b9f65883a6/creating-a-spec-1.png new file mode 100644 index 00000000..04509ee2 Binary files /dev/null and b/0.7.5/_downloads/603e53497bfdb6e0d5f199b9f65883a6/creating-a-spec-1.png differ diff --git a/0.7.5/_downloads/622f2957f6aa7d79df0cad5d9e9946f6/scanspec-specs-14.png b/0.7.5/_downloads/622f2957f6aa7d79df0cad5d9e9946f6/scanspec-specs-14.png new file mode 100644 index 00000000..88156f69 Binary files /dev/null and b/0.7.5/_downloads/622f2957f6aa7d79df0cad5d9e9946f6/scanspec-specs-14.png differ diff --git a/0.7.5/_downloads/6273f467b19bc56f75d71e9fa791260b/scanspec-specs-13.hires.png b/0.7.5/_downloads/6273f467b19bc56f75d71e9fa791260b/scanspec-specs-13.hires.png new file mode 100644 index 00000000..e1a9f433 Binary files /dev/null and b/0.7.5/_downloads/6273f467b19bc56f75d71e9fa791260b/scanspec-specs-13.hires.png differ diff --git a/0.7.5/_downloads/62c5e5947d127957c1809c6287b64e8a/scanspec-specs-4.py b/0.7.5/_downloads/62c5e5947d127957c1809c6287b64e8a/scanspec-specs-4.py new file mode 100644 index 00000000..79f5f57d --- /dev/null +++ b/0.7.5/_downloads/62c5e5947d127957c1809c6287b64e8a/scanspec-specs-4.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line + +spec = Line("z", 1, 2, 3) * Line("y", 3, 4, 5).zip(Line("x", 4, 5, 5)) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/6377083c2cf9e1c6c2ce2f15c65b9035/scanspec-specs-12.pdf b/0.7.5/_downloads/6377083c2cf9e1c6c2ce2f15c65b9035/scanspec-specs-12.pdf new file mode 100644 index 00000000..4247a02e Binary files /dev/null and b/0.7.5/_downloads/6377083c2cf9e1c6c2ce2f15c65b9035/scanspec-specs-12.pdf differ diff --git a/0.7.5/_downloads/64847659a317500c96e79e38caf63631/scanspec-specs-8.py b/0.7.5/_downloads/64847659a317500c96e79e38caf63631/scanspec-specs-8.py new file mode 100644 index 00000000..1cc7c4e1 --- /dev/null +++ b/0.7.5/_downloads/64847659a317500c96e79e38caf63631/scanspec-specs-8.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line, Squash + +spec = Squash(Line("y", 1, 2, 3) * Line("x", 0, 1, 4)) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/64bfb258ba45ae9ac7554b9fd23e1714/scanspec-specs-9.hires.png b/0.7.5/_downloads/64bfb258ba45ae9ac7554b9fd23e1714/scanspec-specs-9.hires.png new file mode 100644 index 00000000..fbd32b10 Binary files /dev/null and b/0.7.5/_downloads/64bfb258ba45ae9ac7554b9fd23e1714/scanspec-specs-9.hires.png differ diff --git a/0.7.5/_downloads/65c31687b904cef516424334e81d81e7/creating-a-spec-4.hires.png b/0.7.5/_downloads/65c31687b904cef516424334e81d81e7/creating-a-spec-4.hires.png new file mode 100644 index 00000000..c79c0d50 Binary files /dev/null and b/0.7.5/_downloads/65c31687b904cef516424334e81d81e7/creating-a-spec-4.hires.png differ diff --git a/0.7.5/_downloads/6765155ac6402e82e524480d6a75c968/scanspec-specs-12.png b/0.7.5/_downloads/6765155ac6402e82e524480d6a75c968/scanspec-specs-12.png new file mode 100644 index 00000000..9e71796d Binary files /dev/null and b/0.7.5/_downloads/6765155ac6402e82e524480d6a75c968/scanspec-specs-12.png differ diff --git a/0.7.5/_downloads/67664503153d45229a4637c1dc49d984/scanspec-specs-7.png b/0.7.5/_downloads/67664503153d45229a4637c1dc49d984/scanspec-specs-7.png new file mode 100644 index 00000000..62fc4e12 Binary files /dev/null and b/0.7.5/_downloads/67664503153d45229a4637c1dc49d984/scanspec-specs-7.png differ diff --git a/0.7.5/_downloads/6799e6124974d7c56748316454a1d774/why-squash-can-change-path-3.png b/0.7.5/_downloads/6799e6124974d7c56748316454a1d774/why-squash-can-change-path-3.png new file mode 100644 index 00000000..0a43371d Binary files /dev/null and b/0.7.5/_downloads/6799e6124974d7c56748316454a1d774/why-squash-can-change-path-3.png differ diff --git a/0.7.5/_downloads/67c27b53de3dac2211647804f6bdf9fd/scanspec-specs-16.png b/0.7.5/_downloads/67c27b53de3dac2211647804f6bdf9fd/scanspec-specs-16.png new file mode 100644 index 00000000..74202a1d Binary files /dev/null and b/0.7.5/_downloads/67c27b53de3dac2211647804f6bdf9fd/scanspec-specs-16.png differ diff --git a/0.7.5/_downloads/6b2bfdefec22ee159c8ced5f7866a2cb/why-squash-can-change-path-4.pdf b/0.7.5/_downloads/6b2bfdefec22ee159c8ced5f7866a2cb/why-squash-can-change-path-4.pdf new file mode 100644 index 00000000..b5d0a15f Binary files /dev/null and b/0.7.5/_downloads/6b2bfdefec22ee159c8ced5f7866a2cb/why-squash-can-change-path-4.pdf differ diff --git a/0.7.5/_downloads/6b86bc97919ff794b55d489569679bfb/scanspec-specs-10.png b/0.7.5/_downloads/6b86bc97919ff794b55d489569679bfb/scanspec-specs-10.png new file mode 100644 index 00000000..d6daa85e Binary files /dev/null and b/0.7.5/_downloads/6b86bc97919ff794b55d489569679bfb/scanspec-specs-10.png differ diff --git a/0.7.5/_downloads/6c39d5369cd428a1fc9b6f8931f5af16/scanspec-regions-3.pdf b/0.7.5/_downloads/6c39d5369cd428a1fc9b6f8931f5af16/scanspec-regions-3.pdf new file mode 100644 index 00000000..39077531 Binary files /dev/null and b/0.7.5/_downloads/6c39d5369cd428a1fc9b6f8931f5af16/scanspec-regions-3.pdf differ diff --git a/0.7.5/_downloads/6c63be80402adee14ecfafb58cf23b0b/why-squash-can-change-path-4.hires.png b/0.7.5/_downloads/6c63be80402adee14ecfafb58cf23b0b/why-squash-can-change-path-4.hires.png new file mode 100644 index 00000000..0f4cc9ec Binary files /dev/null and b/0.7.5/_downloads/6c63be80402adee14ecfafb58cf23b0b/why-squash-can-change-path-4.hires.png differ diff --git a/0.7.5/_downloads/6d4a97d0302014228a54f3420775b31e/creating-a-spec-5.png b/0.7.5/_downloads/6d4a97d0302014228a54f3420775b31e/creating-a-spec-5.png new file mode 100644 index 00000000..255141ac Binary files /dev/null and b/0.7.5/_downloads/6d4a97d0302014228a54f3420775b31e/creating-a-spec-5.png differ diff --git a/0.7.5/_downloads/722f276ee9a699027f8d55b64c4700c9/scanspec-regions-3.png b/0.7.5/_downloads/722f276ee9a699027f8d55b64c4700c9/scanspec-regions-3.png new file mode 100644 index 00000000..a8acaf00 Binary files /dev/null and b/0.7.5/_downloads/722f276ee9a699027f8d55b64c4700c9/scanspec-regions-3.png differ diff --git a/0.7.5/_downloads/738467511cf5dfa5a9f00429c35d07d2/scanspec-specs-14.hires.png b/0.7.5/_downloads/738467511cf5dfa5a9f00429c35d07d2/scanspec-specs-14.hires.png new file mode 100644 index 00000000..066a862b Binary files /dev/null and b/0.7.5/_downloads/738467511cf5dfa5a9f00429c35d07d2/scanspec-specs-14.hires.png differ diff --git a/0.7.5/_downloads/765eb3a3427fe6d21b1a1aa535319276/scanspec-specs-15.pdf b/0.7.5/_downloads/765eb3a3427fe6d21b1a1aa535319276/scanspec-specs-15.pdf new file mode 100644 index 00000000..95708692 Binary files /dev/null and b/0.7.5/_downloads/765eb3a3427fe6d21b1a1aa535319276/scanspec-specs-15.pdf differ diff --git a/0.7.5/_downloads/76d94101d031d187c5c0b8699a646d02/creating-a-spec-2.py b/0.7.5/_downloads/76d94101d031d187c5c0b8699a646d02/creating-a-spec-2.py new file mode 100644 index 00000000..8294329b --- /dev/null +++ b/0.7.5/_downloads/76d94101d031d187c5c0b8699a646d02/creating-a-spec-2.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line + +spec = Line("y", 3, 4, 5).zip(Line("x", 1, 2, 5)) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/78010eb471c3624d320b01abff0752f8/scanspec-plot-1.png b/0.7.5/_downloads/78010eb471c3624d320b01abff0752f8/scanspec-plot-1.png new file mode 100644 index 00000000..094d4d1a Binary files /dev/null and b/0.7.5/_downloads/78010eb471c3624d320b01abff0752f8/scanspec-plot-1.png differ diff --git a/0.7.5/_downloads/78f3e6b8ef9b120d4577737c6704b4c6/scanspec-regions-1.hires.png b/0.7.5/_downloads/78f3e6b8ef9b120d4577737c6704b4c6/scanspec-regions-1.hires.png new file mode 100644 index 00000000..7790c15c Binary files /dev/null and b/0.7.5/_downloads/78f3e6b8ef9b120d4577737c6704b4c6/scanspec-regions-1.hires.png differ diff --git a/0.7.5/_downloads/795a14e724a7b3c14d4291bca0c93156/scanspec-specs-5.hires.png b/0.7.5/_downloads/795a14e724a7b3c14d4291bca0c93156/scanspec-specs-5.hires.png new file mode 100644 index 00000000..1c3648d4 Binary files /dev/null and b/0.7.5/_downloads/795a14e724a7b3c14d4291bca0c93156/scanspec-specs-5.hires.png differ diff --git a/0.7.5/_downloads/7b8826e2f0542681558845e82107a45e/scanspec-specs-3.hires.png b/0.7.5/_downloads/7b8826e2f0542681558845e82107a45e/scanspec-specs-3.hires.png new file mode 100644 index 00000000..9bfd9740 Binary files /dev/null and b/0.7.5/_downloads/7b8826e2f0542681558845e82107a45e/scanspec-specs-3.hires.png differ diff --git a/0.7.5/_downloads/7cd1d1d5cbbe023e131aff0cf050eb3a/scanspec-regions-4.py b/0.7.5/_downloads/7cd1d1d5cbbe023e131aff0cf050eb3a/scanspec-regions-4.py new file mode 100644 index 00000000..a337b2ed --- /dev/null +++ b/0.7.5/_downloads/7cd1d1d5cbbe023e131aff0cf050eb3a/scanspec-regions-4.py @@ -0,0 +1,9 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.regions import Ellipse +from scanspec.specs import Line + +grid = Line("y", 3, 8, 10) * ~Line("x", 1 ,8, 10) +spec = grid & Ellipse("x", "y", 5, 5, 2, 3, 75) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/7e8f24eafd1a977a48125d3f45572c1d/scanspec-specs-5.png b/0.7.5/_downloads/7e8f24eafd1a977a48125d3f45572c1d/scanspec-specs-5.png new file mode 100644 index 00000000..5f74c50b Binary files /dev/null and b/0.7.5/_downloads/7e8f24eafd1a977a48125d3f45572c1d/scanspec-specs-5.png differ diff --git a/0.7.5/_downloads/81242f4d60e5033090690ffb37f6e8e3/scanspec-specs-7.hires.png b/0.7.5/_downloads/81242f4d60e5033090690ffb37f6e8e3/scanspec-specs-7.hires.png new file mode 100644 index 00000000..92e7e763 Binary files /dev/null and b/0.7.5/_downloads/81242f4d60e5033090690ffb37f6e8e3/scanspec-specs-7.hires.png differ diff --git a/0.7.5/_downloads/84adf8120af3f73ccaffd95e693a1656/creating-a-spec-3.py b/0.7.5/_downloads/84adf8120af3f73ccaffd95e693a1656/creating-a-spec-3.py new file mode 100644 index 00000000..1141c08b --- /dev/null +++ b/0.7.5/_downloads/84adf8120af3f73ccaffd95e693a1656/creating-a-spec-3.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line + +spec = Line("y", 3, 4, 3) * Line("x", 1, 2, 5) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/8def2e8f1cf11e2f6361b9872d5c1f96/scanspec-specs-5.pdf b/0.7.5/_downloads/8def2e8f1cf11e2f6361b9872d5c1f96/scanspec-specs-5.pdf new file mode 100644 index 00000000..23369839 Binary files /dev/null and b/0.7.5/_downloads/8def2e8f1cf11e2f6361b9872d5c1f96/scanspec-specs-5.pdf differ diff --git a/0.7.5/_downloads/90481c9e5c2b3588d1b16f603ccb3a86/creating-a-spec-3.pdf b/0.7.5/_downloads/90481c9e5c2b3588d1b16f603ccb3a86/creating-a-spec-3.pdf new file mode 100644 index 00000000..fa508b58 Binary files /dev/null and b/0.7.5/_downloads/90481c9e5c2b3588d1b16f603ccb3a86/creating-a-spec-3.pdf differ diff --git a/0.7.5/_downloads/9068d5b74602d43c895bb204f8a33a47/scanspec-specs-1.py b/0.7.5/_downloads/9068d5b74602d43c895bb204f8a33a47/scanspec-specs-1.py new file mode 100644 index 00000000..afdf3cbb --- /dev/null +++ b/0.7.5/_downloads/9068d5b74602d43c895bb204f8a33a47/scanspec-specs-1.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line + +spec = Line("y", 1, 2, 3) * Line("x", 3, 4, 12) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/968d95e03a89754709e773f72ed8f154/scanspec-specs-6.hires.png b/0.7.5/_downloads/968d95e03a89754709e773f72ed8f154/scanspec-specs-6.hires.png new file mode 100644 index 00000000..8e521ed6 Binary files /dev/null and b/0.7.5/_downloads/968d95e03a89754709e773f72ed8f154/scanspec-specs-6.hires.png differ diff --git a/0.7.5/_downloads/979e789f6fe7f6a0edf7b923298e6c35/scanspec-specs-1.hires.png b/0.7.5/_downloads/979e789f6fe7f6a0edf7b923298e6c35/scanspec-specs-1.hires.png new file mode 100644 index 00000000..a6fda002 Binary files /dev/null and b/0.7.5/_downloads/979e789f6fe7f6a0edf7b923298e6c35/scanspec-specs-1.hires.png differ diff --git a/0.7.5/_downloads/9d36571ca3788038dbc94df5de05c3b5/why-squash-can-change-path-1.hires.png b/0.7.5/_downloads/9d36571ca3788038dbc94df5de05c3b5/why-squash-can-change-path-1.hires.png new file mode 100644 index 00000000..9db42d48 Binary files /dev/null and b/0.7.5/_downloads/9d36571ca3788038dbc94df5de05c3b5/why-squash-can-change-path-1.hires.png differ diff --git a/0.7.5/_downloads/a3e641038fd95a120295f2d3ec2190b6/scanspec-specs-16.pdf b/0.7.5/_downloads/a3e641038fd95a120295f2d3ec2190b6/scanspec-specs-16.pdf new file mode 100644 index 00000000..3fe0973f Binary files /dev/null and b/0.7.5/_downloads/a3e641038fd95a120295f2d3ec2190b6/scanspec-specs-16.pdf differ diff --git a/0.7.5/_downloads/a4cf0ccadef62899dc1c214dc006c23e/scanspec-regions-4.hires.png b/0.7.5/_downloads/a4cf0ccadef62899dc1c214dc006c23e/scanspec-regions-4.hires.png new file mode 100644 index 00000000..6a7d8e23 Binary files /dev/null and b/0.7.5/_downloads/a4cf0ccadef62899dc1c214dc006c23e/scanspec-regions-4.hires.png differ diff --git a/0.7.5/_downloads/a59083bb391dc8562b94035c10b73be3/scanspec-specs-5.py b/0.7.5/_downloads/a59083bb391dc8562b94035c10b73be3/scanspec-specs-5.py new file mode 100644 index 00000000..68dd4100 --- /dev/null +++ b/0.7.5/_downloads/a59083bb391dc8562b94035c10b73be3/scanspec-specs-5.py @@ -0,0 +1,8 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.regions import Circle +from scanspec.specs import Line + +spec = Line("y", 1, 3, 3) * Line("x", 3, 5, 5) & Circle("x", "y", 4, 2, 1.2) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/aaf02e051399c63656daa735de933754/scanspec-specs-4.pdf b/0.7.5/_downloads/aaf02e051399c63656daa735de933754/scanspec-specs-4.pdf new file mode 100644 index 00000000..19458934 Binary files /dev/null and b/0.7.5/_downloads/aaf02e051399c63656daa735de933754/scanspec-specs-4.pdf differ diff --git a/0.7.5/_downloads/ab15ad6488d7de55d318e0ce16a402e4/scanspec-specs-8.hires.png b/0.7.5/_downloads/ab15ad6488d7de55d318e0ce16a402e4/scanspec-specs-8.hires.png new file mode 100644 index 00000000..18105e6f Binary files /dev/null and b/0.7.5/_downloads/ab15ad6488d7de55d318e0ce16a402e4/scanspec-specs-8.hires.png differ diff --git a/0.7.5/_downloads/ac74e6bf48373aad32d4450b8d529998/scanspec-plot-1.hires.png b/0.7.5/_downloads/ac74e6bf48373aad32d4450b8d529998/scanspec-plot-1.hires.png new file mode 100644 index 00000000..629b776f Binary files /dev/null and b/0.7.5/_downloads/ac74e6bf48373aad32d4450b8d529998/scanspec-plot-1.hires.png differ diff --git a/0.7.5/_downloads/af8890f1d73a12db82a79c5489cf8f06/scanspec-specs-2.py b/0.7.5/_downloads/af8890f1d73a12db82a79c5489cf8f06/scanspec-specs-2.py new file mode 100644 index 00000000..4a2e2b75 --- /dev/null +++ b/0.7.5/_downloads/af8890f1d73a12db82a79c5489cf8f06/scanspec-specs-2.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line + +spec = 2 * ~Line.bounded("x", 3, 4, 1) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/b0cff8737e1b445e779e40c4781f03db/scanspec-specs-11.hires.png b/0.7.5/_downloads/b0cff8737e1b445e779e40c4781f03db/scanspec-specs-11.hires.png new file mode 100644 index 00000000..f2515a21 Binary files /dev/null and b/0.7.5/_downloads/b0cff8737e1b445e779e40c4781f03db/scanspec-specs-11.hires.png differ diff --git a/0.7.5/_downloads/b3f54cd984003c3ac9f1c2960a2517f3/creating-a-spec-4.py b/0.7.5/_downloads/b3f54cd984003c3ac9f1c2960a2517f3/creating-a-spec-4.py new file mode 100644 index 00000000..1c263ea1 --- /dev/null +++ b/0.7.5/_downloads/b3f54cd984003c3ac9f1c2960a2517f3/creating-a-spec-4.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line + +spec = Line("y", 3, 4, 3) * ~Line("x", 1, 2, 5) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/b56b9e73e96faf1b75092b65a5c06b6c/scanspec-regions-1.png b/0.7.5/_downloads/b56b9e73e96faf1b75092b65a5c06b6c/scanspec-regions-1.png new file mode 100644 index 00000000..993c099c Binary files /dev/null and b/0.7.5/_downloads/b56b9e73e96faf1b75092b65a5c06b6c/scanspec-regions-1.png differ diff --git a/0.7.5/_downloads/b5b911e9e126d0860f4da9a6a4bafafb/scanspec-specs-1.png b/0.7.5/_downloads/b5b911e9e126d0860f4da9a6a4bafafb/scanspec-specs-1.png new file mode 100644 index 00000000..812fd598 Binary files /dev/null and b/0.7.5/_downloads/b5b911e9e126d0860f4da9a6a4bafafb/scanspec-specs-1.png differ diff --git a/0.7.5/_downloads/b8c099a01c4b47dc4d1cd8976793725f/creating-a-spec-2.png b/0.7.5/_downloads/b8c099a01c4b47dc4d1cd8976793725f/creating-a-spec-2.png new file mode 100644 index 00000000..23cf5e56 Binary files /dev/null and b/0.7.5/_downloads/b8c099a01c4b47dc4d1cd8976793725f/creating-a-spec-2.png differ diff --git a/0.7.5/_downloads/b93b66585638eb26b1622a0b98b703fd/scanspec-specs-6.pdf b/0.7.5/_downloads/b93b66585638eb26b1622a0b98b703fd/scanspec-specs-6.pdf new file mode 100644 index 00000000..2477aad9 Binary files /dev/null and b/0.7.5/_downloads/b93b66585638eb26b1622a0b98b703fd/scanspec-specs-6.pdf differ diff --git a/0.7.5/_downloads/ba43228fe3b2f308e04e5ea9c1c6c121/scanspec-specs-12.hires.png b/0.7.5/_downloads/ba43228fe3b2f308e04e5ea9c1c6c121/scanspec-specs-12.hires.png new file mode 100644 index 00000000..39220889 Binary files /dev/null and b/0.7.5/_downloads/ba43228fe3b2f308e04e5ea9c1c6c121/scanspec-specs-12.hires.png differ diff --git a/0.7.5/_downloads/bb03a5082403681ddefda243d79d914e/scanspec-specs-15.py b/0.7.5/_downloads/bb03a5082403681ddefda243d79d914e/scanspec-specs-15.py new file mode 100644 index 00000000..34e91b66 --- /dev/null +++ b/0.7.5/_downloads/bb03a5082403681ddefda243d79d914e/scanspec-specs-15.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line, fly + +spec = fly(Line("x", 1, 2, 3), 0.1) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/bb8f2c460ed8d9d18885fd5afb672bb7/creating-a-spec-3.png b/0.7.5/_downloads/bb8f2c460ed8d9d18885fd5afb672bb7/creating-a-spec-3.png new file mode 100644 index 00000000..51e4836b Binary files /dev/null and b/0.7.5/_downloads/bb8f2c460ed8d9d18885fd5afb672bb7/creating-a-spec-3.png differ diff --git a/0.7.5/_downloads/bd59a3a4d280d4586f4bb2550db6f079/scanspec-specs-7.pdf b/0.7.5/_downloads/bd59a3a4d280d4586f4bb2550db6f079/scanspec-specs-7.pdf new file mode 100644 index 00000000..4a127fa9 Binary files /dev/null and b/0.7.5/_downloads/bd59a3a4d280d4586f4bb2550db6f079/scanspec-specs-7.pdf differ diff --git a/0.7.5/_downloads/be0266aac130d905756ec129d729f864/why-squash-can-change-path-2.py b/0.7.5/_downloads/be0266aac130d905756ec129d729f864/why-squash-can-change-path-2.py new file mode 100644 index 00000000..3da62c24 --- /dev/null +++ b/0.7.5/_downloads/be0266aac130d905756ec129d729f864/why-squash-can-change-path-2.py @@ -0,0 +1,7 @@ +from scanspec.specs import Line, Squash +from scanspec.plot import plot_spec + +spec = Line("z", 0, 1, 3) * Squash( + ~Line("y", 0, 1, 3) * Line("x", 0, 1, 3), check_path_changes=False +) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/be854064316e2e0362d1e7cac6859d21/why-squash-can-change-path-2.hires.png b/0.7.5/_downloads/be854064316e2e0362d1e7cac6859d21/why-squash-can-change-path-2.hires.png new file mode 100644 index 00000000..91a2ee8f Binary files /dev/null and b/0.7.5/_downloads/be854064316e2e0362d1e7cac6859d21/why-squash-can-change-path-2.hires.png differ diff --git a/0.7.5/_downloads/c2faec58e8a7872b8c73e00e780c4f8b/creating-a-spec-2.pdf b/0.7.5/_downloads/c2faec58e8a7872b8c73e00e780c4f8b/creating-a-spec-2.pdf new file mode 100644 index 00000000..c8440c37 Binary files /dev/null and b/0.7.5/_downloads/c2faec58e8a7872b8c73e00e780c4f8b/creating-a-spec-2.pdf differ diff --git a/0.7.5/_downloads/c65de3ee054161d71e4983fd6c960f0d/scanspec-plot-1.pdf b/0.7.5/_downloads/c65de3ee054161d71e4983fd6c960f0d/scanspec-plot-1.pdf new file mode 100644 index 00000000..d85a8791 Binary files /dev/null and b/0.7.5/_downloads/c65de3ee054161d71e4983fd6c960f0d/scanspec-plot-1.pdf differ diff --git a/0.7.5/_downloads/cd8824473bc8e9eb03d621cae1bb4e55/scanspec-plot-1.py b/0.7.5/_downloads/cd8824473bc8e9eb03d621cae1bb4e55/scanspec-plot-1.py new file mode 100644 index 00000000..87c0f949 --- /dev/null +++ b/0.7.5/_downloads/cd8824473bc8e9eb03d621cae1bb4e55/scanspec-plot-1.py @@ -0,0 +1,9 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line +from scanspec.regions import Circle + +cube = Line("z", 1, 3, 3) * Line("y", 1, 3, 10) * ~Line("x", 0, 2, 10) +spec = cube & Circle("x", "y", 1, 2, 0.9) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/cf755cae62efcddb79d35f345aaba8ba/creating-a-spec-6.py b/0.7.5/_downloads/cf755cae62efcddb79d35f345aaba8ba/creating-a-spec-6.py new file mode 100644 index 00000000..48213384 --- /dev/null +++ b/0.7.5/_downloads/cf755cae62efcddb79d35f345aaba8ba/creating-a-spec-6.py @@ -0,0 +1,8 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line +from scanspec.regions import Circle + +spec = Line("y", 3, 4, 3) * ~Line("x", 1, 2, 5) & Circle("x", "y", 1.5, 3.5, 0.6) - Circle("x", "y", 1.4, 3.5, 0.2) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/d07484c8c66eeff187b2311ac0fa61c9/scanspec-specs-2.png b/0.7.5/_downloads/d07484c8c66eeff187b2311ac0fa61c9/scanspec-specs-2.png new file mode 100644 index 00000000..7995543e Binary files /dev/null and b/0.7.5/_downloads/d07484c8c66eeff187b2311ac0fa61c9/scanspec-specs-2.png differ diff --git a/0.7.5/_downloads/d31ee89c9fe4d6d0e70214e6a0e8a4df/creating-a-spec-5.py b/0.7.5/_downloads/d31ee89c9fe4d6d0e70214e6a0e8a4df/creating-a-spec-5.py new file mode 100644 index 00000000..d66bcd9a --- /dev/null +++ b/0.7.5/_downloads/d31ee89c9fe4d6d0e70214e6a0e8a4df/creating-a-spec-5.py @@ -0,0 +1,8 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line +from scanspec.regions import Circle + +spec = Line("y", 3, 4, 3) * ~Line("x", 1, 2, 5) & Circle("x", "y", 1.5, 3.5, 0.6) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/d4a857bafcf09d241d2ddbc974c3eab8/scanspec-specs-1.pdf b/0.7.5/_downloads/d4a857bafcf09d241d2ddbc974c3eab8/scanspec-specs-1.pdf new file mode 100644 index 00000000..e0eab00c Binary files /dev/null and b/0.7.5/_downloads/d4a857bafcf09d241d2ddbc974c3eab8/scanspec-specs-1.pdf differ diff --git a/0.7.5/_downloads/d5d933689d67f07042600b892a1fa576/creating-a-spec-6.png b/0.7.5/_downloads/d5d933689d67f07042600b892a1fa576/creating-a-spec-6.png new file mode 100644 index 00000000..5720e27d Binary files /dev/null and b/0.7.5/_downloads/d5d933689d67f07042600b892a1fa576/creating-a-spec-6.png differ diff --git a/0.7.5/_downloads/d951a913ef49c5656aca72d4ec3d6127/scanspec-specs-11.pdf b/0.7.5/_downloads/d951a913ef49c5656aca72d4ec3d6127/scanspec-specs-11.pdf new file mode 100644 index 00000000..8b327c6b Binary files /dev/null and b/0.7.5/_downloads/d951a913ef49c5656aca72d4ec3d6127/scanspec-specs-11.pdf differ diff --git a/0.7.5/_downloads/de54f45614a78e61d0c3cb83aa563617/scanspec-specs-15.hires.png b/0.7.5/_downloads/de54f45614a78e61d0c3cb83aa563617/scanspec-specs-15.hires.png new file mode 100644 index 00000000..bcff2c8a Binary files /dev/null and b/0.7.5/_downloads/de54f45614a78e61d0c3cb83aa563617/scanspec-specs-15.hires.png differ diff --git a/0.7.5/_downloads/dec387273dfbf951bfe5bf2f7358770c/scanspec-specs-2.hires.png b/0.7.5/_downloads/dec387273dfbf951bfe5bf2f7358770c/scanspec-specs-2.hires.png new file mode 100644 index 00000000..9d31c010 Binary files /dev/null and b/0.7.5/_downloads/dec387273dfbf951bfe5bf2f7358770c/scanspec-specs-2.hires.png differ diff --git a/0.7.5/_downloads/df3bd7e446b0e9d8f00890cc805d8d77/scanspec-specs-11.png b/0.7.5/_downloads/df3bd7e446b0e9d8f00890cc805d8d77/scanspec-specs-11.png new file mode 100644 index 00000000..521ccbff Binary files /dev/null and b/0.7.5/_downloads/df3bd7e446b0e9d8f00890cc805d8d77/scanspec-specs-11.png differ diff --git a/0.7.5/_downloads/df45abd6cf3a536dc40edb8915007a0e/scanspec-specs-9.pdf b/0.7.5/_downloads/df45abd6cf3a536dc40edb8915007a0e/scanspec-specs-9.pdf new file mode 100644 index 00000000..07d5d164 Binary files /dev/null and b/0.7.5/_downloads/df45abd6cf3a536dc40edb8915007a0e/scanspec-specs-9.pdf differ diff --git a/0.7.5/_downloads/dfd125f8fe26e983a096e8d2be420600/creating-a-spec-2.hires.png b/0.7.5/_downloads/dfd125f8fe26e983a096e8d2be420600/creating-a-spec-2.hires.png new file mode 100644 index 00000000..472f320f Binary files /dev/null and b/0.7.5/_downloads/dfd125f8fe26e983a096e8d2be420600/creating-a-spec-2.hires.png differ diff --git a/0.7.5/_downloads/e34655e18a22651d180c110d404698d0/scanspec-specs-4.png b/0.7.5/_downloads/e34655e18a22651d180c110d404698d0/scanspec-specs-4.png new file mode 100644 index 00000000..15dd400a Binary files /dev/null and b/0.7.5/_downloads/e34655e18a22651d180c110d404698d0/scanspec-specs-4.png differ diff --git a/0.7.5/_downloads/e5428a1bf8c516ed6cecc74fbbe0de8f/why-squash-can-change-path-3.py b/0.7.5/_downloads/e5428a1bf8c516ed6cecc74fbbe0de8f/why-squash-can-change-path-3.py new file mode 100644 index 00000000..5b61317d --- /dev/null +++ b/0.7.5/_downloads/e5428a1bf8c516ed6cecc74fbbe0de8f/why-squash-can-change-path-3.py @@ -0,0 +1,5 @@ +from scanspec.specs import Line +from scanspec.plot import plot_spec + +spec = Line("z", 0, 1, 3) * Line("y", 0, 1, 3) * ~Line("x", 0, 1, 3) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_downloads/e65a64116288e7b0b97b63ffe2ab4bbb/why-squash-can-change-path-1.png b/0.7.5/_downloads/e65a64116288e7b0b97b63ffe2ab4bbb/why-squash-can-change-path-1.png new file mode 100644 index 00000000..0ad81803 Binary files /dev/null and b/0.7.5/_downloads/e65a64116288e7b0b97b63ffe2ab4bbb/why-squash-can-change-path-1.png differ diff --git a/0.7.5/_downloads/e8de6363062664933e4168a9325eb35c/scanspec-specs-10.hires.png b/0.7.5/_downloads/e8de6363062664933e4168a9325eb35c/scanspec-specs-10.hires.png new file mode 100644 index 00000000..8caca7cd Binary files /dev/null and b/0.7.5/_downloads/e8de6363062664933e4168a9325eb35c/scanspec-specs-10.hires.png differ diff --git a/0.7.5/_downloads/e97e6c4ea088783de917c4b5859e1595/why-squash-can-change-path-1.pdf b/0.7.5/_downloads/e97e6c4ea088783de917c4b5859e1595/why-squash-can-change-path-1.pdf new file mode 100644 index 00000000..2ce87d5d Binary files /dev/null and b/0.7.5/_downloads/e97e6c4ea088783de917c4b5859e1595/why-squash-can-change-path-1.pdf differ diff --git a/0.7.5/_downloads/ec8d232d0953cdaac6529cb67293b0e8/creating-a-spec-5.pdf b/0.7.5/_downloads/ec8d232d0953cdaac6529cb67293b0e8/creating-a-spec-5.pdf new file mode 100644 index 00000000..fb5980fc Binary files /dev/null and b/0.7.5/_downloads/ec8d232d0953cdaac6529cb67293b0e8/creating-a-spec-5.pdf differ diff --git a/0.7.5/_downloads/edf4182424d7c4118287d2ea50bef6bb/why-squash-can-change-path-2.pdf b/0.7.5/_downloads/edf4182424d7c4118287d2ea50bef6bb/why-squash-can-change-path-2.pdf new file mode 100644 index 00000000..7f7a8c2d Binary files /dev/null and b/0.7.5/_downloads/edf4182424d7c4118287d2ea50bef6bb/why-squash-can-change-path-2.pdf differ diff --git a/0.7.5/_downloads/f25ee9ccc9cf43c3c3addcdab46ff433/creating-a-spec-5.hires.png b/0.7.5/_downloads/f25ee9ccc9cf43c3c3addcdab46ff433/creating-a-spec-5.hires.png new file mode 100644 index 00000000..b7692a60 Binary files /dev/null and b/0.7.5/_downloads/f25ee9ccc9cf43c3c3addcdab46ff433/creating-a-spec-5.hires.png differ diff --git a/0.7.5/_downloads/f5c85345bb31322c4ff4cfb2708fc297/scanspec-specs-3.py b/0.7.5/_downloads/f5c85345bb31322c4ff4cfb2708fc297/scanspec-specs-3.py new file mode 100644 index 00000000..00a898c7 --- /dev/null +++ b/0.7.5/_downloads/f5c85345bb31322c4ff4cfb2708fc297/scanspec-specs-3.py @@ -0,0 +1,7 @@ +# Example Spec + +from scanspec.plot import plot_spec +from scanspec.specs import Line, Repeat + +spec = Repeat(2, gap=False) * ~Line.bounded("x", 3, 4, 1) +plot_spec(spec) \ No newline at end of file diff --git a/0.7.5/_images/creating-a-spec-1.png b/0.7.5/_images/creating-a-spec-1.png new file mode 100644 index 00000000..04509ee2 Binary files /dev/null and b/0.7.5/_images/creating-a-spec-1.png differ diff --git a/0.7.5/_images/creating-a-spec-2.png b/0.7.5/_images/creating-a-spec-2.png new file mode 100644 index 00000000..23cf5e56 Binary files /dev/null and b/0.7.5/_images/creating-a-spec-2.png differ diff --git a/0.7.5/_images/creating-a-spec-3.png b/0.7.5/_images/creating-a-spec-3.png new file mode 100644 index 00000000..51e4836b Binary files /dev/null and b/0.7.5/_images/creating-a-spec-3.png differ diff --git a/0.7.5/_images/creating-a-spec-4.png b/0.7.5/_images/creating-a-spec-4.png new file mode 100644 index 00000000..418231fb Binary files /dev/null and b/0.7.5/_images/creating-a-spec-4.png differ diff --git a/0.7.5/_images/creating-a-spec-5.png b/0.7.5/_images/creating-a-spec-5.png new file mode 100644 index 00000000..255141ac Binary files /dev/null and b/0.7.5/_images/creating-a-spec-5.png differ diff --git a/0.7.5/_images/creating-a-spec-6.png b/0.7.5/_images/creating-a-spec-6.png new file mode 100644 index 00000000..5720e27d Binary files /dev/null and b/0.7.5/_images/creating-a-spec-6.png differ diff --git a/0.7.5/_images/definitions.png b/0.7.5/_images/definitions.png new file mode 100644 index 00000000..8fc7b9ae Binary files /dev/null and b/0.7.5/_images/definitions.png differ diff --git a/0.7.5/_images/inheritance-28c13a050e6432c87e6edb9e7bddd3f3ed2925d6.svg b/0.7.5/_images/inheritance-28c13a050e6432c87e6edb9e7bddd3f3ed2925d6.svg new file mode 100644 index 00000000..81eb8d55 --- /dev/null +++ b/0.7.5/_images/inheritance-28c13a050e6432c87e6edb9e7bddd3f3ed2925d6.svg @@ -0,0 +1,164 @@ + + +inheritancec3ef874399 + + +Concat + + +Concat + + + + + +Spec + + +Spec + + + + + +Spec->Concat + + + + + +Line + + +Line + + + + + +Spec->Line + + + + + +Mask + + +Mask + + + + + +Spec->Mask + + + + + +Product + + +Product + + + + + +Spec->Product + + + + + +Repeat + + +Repeat + + + + + +Spec->Repeat + + + + + +Snake + + +Snake + + + + + +Spec->Snake + + + + + +Spiral + + +Spiral + + + + + +Spec->Spiral + + + + + +Squash + + +Squash + + + + + +Spec->Squash + + + + + +Static + + +Static + + + + + +Spec->Static + + + + + +Zip + + +Zip + + + + + +Spec->Zip + + + + + \ No newline at end of file diff --git a/0.7.5/_images/inheritance-d6c9411b15bb8ebbc1df3c96fe54b3762b90c335.svg b/0.7.5/_images/inheritance-d6c9411b15bb8ebbc1df3c96fe54b3762b90c335.svg new file mode 100644 index 00000000..a9870d2d --- /dev/null +++ b/0.7.5/_images/inheritance-d6c9411b15bb8ebbc1df3c96fe54b3762b90c335.svg @@ -0,0 +1,164 @@ + + +inheritance392524bb86 + + +Circle + + +Circle + + + + + +Region + + +Region + + + + + +Region->Circle + + + + + +CombinationOf + + +CombinationOf + + + + + +Region->CombinationOf + + + + + +Ellipse + + +Ellipse + + + + + +Region->Ellipse + + + + + +Polygon + + +Polygon + + + + + +Region->Polygon + + + + + +Range + + +Range + + + + + +Region->Range + + + + + +Rectangle + + +Rectangle + + + + + +Region->Rectangle + + + + + +DifferenceOf + + +DifferenceOf + + + + + +CombinationOf->DifferenceOf + + + + + +IntersectionOf + + +IntersectionOf + + + + + +CombinationOf->IntersectionOf + + + + + +SymmetricDifferenceOf + + +SymmetricDifferenceOf + + + + + +CombinationOf->SymmetricDifferenceOf + + + + + +UnionOf + + +UnionOf + + + + + +CombinationOf->UnionOf + + + + + \ No newline at end of file diff --git a/0.7.5/_images/plot_spec.png b/0.7.5/_images/plot_spec.png new file mode 100644 index 00000000..7bc36258 Binary files /dev/null and b/0.7.5/_images/plot_spec.png differ diff --git a/0.7.5/_images/scanspec-plot-1.png b/0.7.5/_images/scanspec-plot-1.png new file mode 100644 index 00000000..094d4d1a Binary files /dev/null and b/0.7.5/_images/scanspec-plot-1.png differ diff --git a/0.7.5/_images/scanspec-regions-1.png b/0.7.5/_images/scanspec-regions-1.png new file mode 100644 index 00000000..993c099c Binary files /dev/null and b/0.7.5/_images/scanspec-regions-1.png differ diff --git a/0.7.5/_images/scanspec-regions-2.png b/0.7.5/_images/scanspec-regions-2.png new file mode 100644 index 00000000..bb1adfdb Binary files /dev/null and b/0.7.5/_images/scanspec-regions-2.png differ diff --git a/0.7.5/_images/scanspec-regions-3.png b/0.7.5/_images/scanspec-regions-3.png new file mode 100644 index 00000000..a8acaf00 Binary files /dev/null and b/0.7.5/_images/scanspec-regions-3.png differ diff --git a/0.7.5/_images/scanspec-regions-4.png b/0.7.5/_images/scanspec-regions-4.png new file mode 100644 index 00000000..27e11047 Binary files /dev/null and b/0.7.5/_images/scanspec-regions-4.png differ diff --git a/0.7.5/_images/scanspec-specs-1.png b/0.7.5/_images/scanspec-specs-1.png new file mode 100644 index 00000000..812fd598 Binary files /dev/null and b/0.7.5/_images/scanspec-specs-1.png differ diff --git a/0.7.5/_images/scanspec-specs-10.png b/0.7.5/_images/scanspec-specs-10.png new file mode 100644 index 00000000..d6daa85e Binary files /dev/null and b/0.7.5/_images/scanspec-specs-10.png differ diff --git a/0.7.5/_images/scanspec-specs-11.png b/0.7.5/_images/scanspec-specs-11.png new file mode 100644 index 00000000..521ccbff Binary files /dev/null and b/0.7.5/_images/scanspec-specs-11.png differ diff --git a/0.7.5/_images/scanspec-specs-12.png b/0.7.5/_images/scanspec-specs-12.png new file mode 100644 index 00000000..9e71796d Binary files /dev/null and b/0.7.5/_images/scanspec-specs-12.png differ diff --git a/0.7.5/_images/scanspec-specs-13.png b/0.7.5/_images/scanspec-specs-13.png new file mode 100644 index 00000000..64604a20 Binary files /dev/null and b/0.7.5/_images/scanspec-specs-13.png differ diff --git a/0.7.5/_images/scanspec-specs-14.png b/0.7.5/_images/scanspec-specs-14.png new file mode 100644 index 00000000..88156f69 Binary files /dev/null and b/0.7.5/_images/scanspec-specs-14.png differ diff --git a/0.7.5/_images/scanspec-specs-15.png b/0.7.5/_images/scanspec-specs-15.png new file mode 100644 index 00000000..cd0b2340 Binary files /dev/null and b/0.7.5/_images/scanspec-specs-15.png differ diff --git a/0.7.5/_images/scanspec-specs-16.png b/0.7.5/_images/scanspec-specs-16.png new file mode 100644 index 00000000..74202a1d Binary files /dev/null and b/0.7.5/_images/scanspec-specs-16.png differ diff --git a/0.7.5/_images/scanspec-specs-2.png b/0.7.5/_images/scanspec-specs-2.png new file mode 100644 index 00000000..7995543e Binary files /dev/null and b/0.7.5/_images/scanspec-specs-2.png differ diff --git a/0.7.5/_images/scanspec-specs-3.png b/0.7.5/_images/scanspec-specs-3.png new file mode 100644 index 00000000..b1a79d80 Binary files /dev/null and b/0.7.5/_images/scanspec-specs-3.png differ diff --git a/0.7.5/_images/scanspec-specs-4.png b/0.7.5/_images/scanspec-specs-4.png new file mode 100644 index 00000000..15dd400a Binary files /dev/null and b/0.7.5/_images/scanspec-specs-4.png differ diff --git a/0.7.5/_images/scanspec-specs-5.png b/0.7.5/_images/scanspec-specs-5.png new file mode 100644 index 00000000..5f74c50b Binary files /dev/null and b/0.7.5/_images/scanspec-specs-5.png differ diff --git a/0.7.5/_images/scanspec-specs-6.png b/0.7.5/_images/scanspec-specs-6.png new file mode 100644 index 00000000..bd687072 Binary files /dev/null and b/0.7.5/_images/scanspec-specs-6.png differ diff --git a/0.7.5/_images/scanspec-specs-7.png b/0.7.5/_images/scanspec-specs-7.png new file mode 100644 index 00000000..62fc4e12 Binary files /dev/null and b/0.7.5/_images/scanspec-specs-7.png differ diff --git a/0.7.5/_images/scanspec-specs-8.png b/0.7.5/_images/scanspec-specs-8.png new file mode 100644 index 00000000..6cf49529 Binary files /dev/null and b/0.7.5/_images/scanspec-specs-8.png differ diff --git a/0.7.5/_images/scanspec-specs-9.png b/0.7.5/_images/scanspec-specs-9.png new file mode 100644 index 00000000..04509ee2 Binary files /dev/null and b/0.7.5/_images/scanspec-specs-9.png differ diff --git a/0.7.5/_images/why-squash-can-change-path-1.png b/0.7.5/_images/why-squash-can-change-path-1.png new file mode 100644 index 00000000..0ad81803 Binary files /dev/null and b/0.7.5/_images/why-squash-can-change-path-1.png differ diff --git a/0.7.5/_images/why-squash-can-change-path-2.png b/0.7.5/_images/why-squash-can-change-path-2.png new file mode 100644 index 00000000..8c32b3a5 Binary files /dev/null and b/0.7.5/_images/why-squash-can-change-path-2.png differ diff --git a/0.7.5/_images/why-squash-can-change-path-3.png b/0.7.5/_images/why-squash-can-change-path-3.png new file mode 100644 index 00000000..0a43371d Binary files /dev/null and b/0.7.5/_images/why-squash-can-change-path-3.png differ diff --git a/0.7.5/_images/why-squash-can-change-path-4.png b/0.7.5/_images/why-squash-can-change-path-4.png new file mode 100644 index 00000000..6f9e373a Binary files /dev/null and b/0.7.5/_images/why-squash-can-change-path-4.png differ diff --git a/0.7.5/_modules/index.html b/0.7.5/_modules/index.html new file mode 100644 index 00000000..c70d2730 --- /dev/null +++ b/0.7.5/_modules/index.html @@ -0,0 +1,526 @@ + + + + + + + + + + Overview: module code — scanspec 0.7.5 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
+
+
+
+ +
+ +
+ + + + + +
+
+ + + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + + + + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/0.7.5/_modules/scanspec/core.html b/0.7.5/_modules/scanspec/core.html new file mode 100644 index 00000000..caf10f71 --- /dev/null +++ b/0.7.5/_modules/scanspec/core.html @@ -0,0 +1,1233 @@ + + + + + + + + + + scanspec.core — scanspec 0.7.5 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
+
+
+
+ +
+ +
+ + + + + +
+
+ + + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for scanspec.core

+"""Core classes like `Frames` and `Path`."""
+
+from __future__ import annotations
+
+import itertools
+from collections.abc import Callable, Iterable, Iterator, Sequence
+from functools import lru_cache
+from inspect import isclass
+from typing import (
+    Any,
+    Generic,
+    Literal,
+    TypeVar,
+)
+
+import numpy as np
+import numpy.typing as npt
+from pydantic import BaseModel, ConfigDict, Field, GetCoreSchemaHandler
+from pydantic.dataclasses import is_pydantic_dataclass, rebuild_dataclass
+from pydantic_core import CoreSchema
+from pydantic_core.core_schema import tagged_union_schema
+
+__all__ = [
+    "Axis",
+    "OtherAxis",
+    "if_instance_do",
+    "AxesPoints",
+    "Frames",
+    "SnakedFrames",
+    "gap_between_frames",
+    "squash_frames",
+    "Path",
+    "Midpoints",
+    "discriminated_union_of_subclasses",
+    "StrictConfig",
+]
+
+#: Used to ensure pydantic dataclasses error if given extra arguments
+StrictConfig: ConfigDict = {"extra": "forbid"}
+
+C = TypeVar("C")
+T = TypeVar("T")
+
+GapArray = npt.NDArray[np.bool]
+
+
+
+[docs] +def discriminated_union_of_subclasses( + super_cls: type[C], + discriminator: str = "type", +) -> type[C]: + """Add all subclasses of super_cls to a discriminated union. + + For all subclasses of super_cls, add a discriminator field to identify + the type. Raw JSON should look like {<discriminator>: <type name>, params for + <type name>...}. + + Subclasses that extend this class must be Pydantic dataclasses, and types that + need their schema to be updated when a new type that extends super_cls is + created must be either Pydantic dataclasses or BaseModels. + + Example:: + + @discriminated_union_of_subclasses + class Expression(ABC): + @abstractmethod + def calculate(self) -> int: + ... + + + @dataclass + class Add(Expression): + left: Expression + right: Expression + + def calculate(self) -> int: + return self.left.calculate() + self.right.calculate() + + + @dataclass + class Subtract(Expression): + left: Expression + right: Expression + + def calculate(self) -> int: + return self.left.calculate() - self.right.calculate() + + + @dataclass + class IntLiteral(Expression): + value: int + + def calculate(self) -> int: + return self.value + + + my_sum = Add(IntLiteral(5), Subtract(IntLiteral(10), IntLiteral(2))) + assert my_sum.calculate() == 13 + + assert my_sum == parse_obj_as( + Expression, + { + "type": "Add", + "left": {"type": "IntLiteral", "value": 5}, + "right": { + "type": "Subtract", + "left": {"type": "IntLiteral", "value": 10}, + "right": {"type": "IntLiteral", "value": 2}, + }, + }, + ) + + Args: + super_cls: The superclass of the union, Expression in the above example + discriminator: The discriminator that will be inserted into the + serialized documents for type determination. Defaults to "type". + + Returns: + Type: decorated superclass with handling for subclasses to be added + to its discriminated union for deserialization + + """ + tagged_union = _TaggedUnion(super_cls, discriminator) + _tagged_unions[super_cls] = tagged_union + + def add_subclass_to_union(subclass: type[C]): + # Add a discriminator field to a subclass so it can + # be identified when deserializing + subclass.__annotations__ = { + **subclass.__annotations__, + discriminator: Literal[subclass.__name__], # type: ignore + } + setattr(subclass, discriminator, Field(subclass.__name__, repr=False)) # type: ignore + + def get_schema_of_union( + cls: type[C], source_type: Any, handler: GetCoreSchemaHandler + ): + if cls is not super_cls: + tagged_union.add_member(cls) + return handler(cls) + # Rebuild any dataclass (including this one) that references this union + # Note that this has to be done after the creation of the dataclass so that + # previously created classes can refer to this newly created class + return tagged_union.schema(handler) + + super_cls.__init_subclass__ = classmethod(add_subclass_to_union) # type: ignore + super_cls.__get_pydantic_core_schema__ = classmethod(get_schema_of_union) # type: ignore + return super_cls
+ + + +_tagged_unions: dict[type, _TaggedUnion] = {} + + +class _TaggedUnion: + def __init__(self, base_class: type[Any], discriminator: str): + self._base_class = base_class + # Classes and their field names that refer to this tagged union + self._discriminator = discriminator + # The members of the tagged union, i.e. subclasses of the baseclass + self._subclasses: list[type] = [] + + def add_member(self, cls: type): + if cls in self._subclasses: + return + self._subclasses.append(cls) + for member in self._subclasses: + if member is not cls: + _TaggedUnion._rebuild(member) + + @staticmethod + def _rebuild(cls_or_func: Callable[..., T]) -> None: + if isclass(cls_or_func): + if is_pydantic_dataclass(cls_or_func): + rebuild_dataclass(cls_or_func, force=True) + if issubclass(cls_or_func, BaseModel): + cls_or_func.model_rebuild(force=True) + + def schema(self, handler: GetCoreSchemaHandler) -> CoreSchema: + return tagged_union_schema( + _make_schema(tuple(self._subclasses), handler), + discriminator=self._discriminator, + ref=self._base_class.__name__, + ) + + +@lru_cache(1) +def _make_schema( + members: tuple[type[Any], ...], handler: Callable[[Any], CoreSchema] +) -> dict[str, CoreSchema]: + return {member.__name__: handler(member) for member in members} + + +
+[docs] +def if_instance_do(x: C, cls: type[C], func: Callable[[C], T]) -> T: + """If x is of type cls then return func(x), otherwise return NotImplemented. + + Used as a helper when implementing operator overloading. + """ + if isinstance(x, cls): + return func(x) + else: + return NotImplemented
+ + + +#: A type variable for an `axis_` that can be specified for a scan +Axis = TypeVar("Axis", covariant=True) + +#: Alternative axis variable to be used when two are required in the same type binding +OtherAxis = TypeVar("OtherAxis") + +#: Map of axes to float ndarray of points +#: E.g. {xmotor: array([0, 1, 2]), ymotor: array([2, 2, 2])} +AxesPoints = dict[Axis, npt.NDArray[np.floating[Any]]] + + +
+[docs] +class Frames(Generic[Axis]): + """Represents a series of scan frames along a number of axes. + + During a scan each axis will traverse lower-midpoint-upper for each frame. + + Args: + midpoints: The midpoints of scan frames for each axis + lower: Lower bounds of scan frames if different from midpoints + upper: Upper bounds of scan frames if different from midpoints + gap: If supplied, define if there is a gap between frame and previous + otherwise it is calculated by looking at lower and upper bounds + + Typically used in two ways: + + - A list of Frames objects returned from `Spec.calculate` represents a scan + as a linear stack of frames. Interpreted as nested from slowest moving to + fastest moving, so each faster Frames object will iterate once per + position of the slower Frames object. It is passed to a `Path` for + calculation of the actual scan path. + - A single Frames object returned from `Path.consume` represents a chunk of + frames forming part of a scan path, for interpretation by the code + that will actually perform the scan. + + See Also: + `technical-terms` + + """ + + def __init__( + self, + midpoints: AxesPoints[Axis], + lower: AxesPoints[Axis] | None = None, + upper: AxesPoints[Axis] | None = None, + gap: GapArray | None = None, + ): + #: The midpoints of scan frames for each axis + self.midpoints = midpoints + #: The lower bounds of each scan frame in each axis for fly-scanning + self.lower = lower or midpoints + #: The upper bounds of each scan frame in each axis for fly-scanning + self.upper = upper or midpoints + if gap is not None: + #: Whether there is a gap between this frame and the previous. First + #: element is whether there is a gap between the last frame and the first + self.gap = gap + else: + # Need to calculate gap as not passed one + # We have a gap if upper[i] != lower[i+1] for any axes + axes_gap = [ + np.roll(upper, 1) != lower + for upper, lower in zip( + self.upper.values(), self.lower.values(), strict=False + ) + ] + self.gap = np.logical_or.reduce(axes_gap) + # Check all axes and ordering are the same + assert list(self.midpoints) == list(self.lower) == list(self.upper), ( + f"Mismatching axes " + f"{list(self.midpoints)} != {list(self.lower)} != {list(self.upper)}" + ) + # Check all lengths are the same + lengths = { + len(arr) + for d in (self.midpoints, self.lower, self.upper) + for arr in d.values() + } + lengths.add(len(self.gap)) + assert len(lengths) <= 1, f"Mismatching lengths {list(lengths)}" + +
+[docs] + def axes(self) -> list[Axis]: + """The axes which will move during the scan. + + These will be present in `midpoints`, `lower` and `upper`. + """ + return list(self.midpoints.keys())
+ + + def __len__(self) -> int: + """The number of frames in this section of the scan.""" + # All axespoints arrays are same length, pick the first one + return len(self.gap) + +
+[docs] + def extract( + self, indices: npt.NDArray[np.signedinteger[Any]], calculate_gap: bool = True + ) -> Frames[Axis]: + """Return a new Frames object restricted to the indices provided. + + Args: + indices: The indices of the frames to extract, modulo scan length + calculate_gap: If True then recalculate the gap from upper and lower + + >>> frames = Frames({"x": np.array([1, 2, 3])}) + >>> frames.extract(np.array([1, 0, 1])).midpoints + {'x': array([2, 1, 2])} + + """ + dim_indices = indices % len(self) + + def extract_dict(ds: Iterable[AxesPoints[Axis]]) -> AxesPoints[Axis]: + for d in ds: + return {k: v[dim_indices] for k, v in d.items()} + return {} + + def extract_gap(gaps: Iterable[GapArray]) -> GapArray | None: + for gap in gaps: + if not calculate_gap: + return gap[dim_indices] + return None + + return _merge_frames(self, dict_merge=extract_dict, gap_merge=extract_gap)
+ + +
+[docs] + def concat(self, other: Frames[Axis], gap: bool = False) -> Frames[Axis]: + """Return a new Frames object concatenating self and other. + + Requires both Frames objects to have the same axes, but not necessarily in + the same order. The order is inherited from self, so other may be reordered. + + Args: + other: The Frames to concatenate to self + gap: Whether to force a gap between the two Frames objects + + >>> frames = Frames({"x": np.array([1, 2, 3]), "y": np.array([6, 5, 4])}) + >>> frames2 = Frames({"y": np.array([3, 2, 1]), "x": np.array([4, 5, 6])}) + >>> frames.concat(frames2).midpoints + {'x': array([1, 2, 3, 4, 5, 6]), 'y': array([6, 5, 4, 3, 2, 1])} + + """ + assert set(self.axes()) == set( + other.axes() + ), f"axes {self.axes()} != {other.axes()}" + + def concat_dict(ds: Sequence[AxesPoints[Axis]]) -> AxesPoints[Axis]: + # Concat each array in midpoints, lower, upper. E.g. + # lower[ax] = np.concatenate(self.lower[ax], other.lower[ax]) + return {a: np.concatenate([d[a] for d in ds]) for a in self.axes()} + + def concat_gap(gaps: Sequence[GapArray]) -> GapArray: + g = np.concatenate(gaps) + # Calc the first frame + g[0] = gap_between_frames(other, self) + # And the join frame + g[len(self)] = gap or gap_between_frames(self, other) + return g + + return _merge_frames(self, other, dict_merge=concat_dict, gap_merge=concat_gap)
+ + +
+[docs] + def zip(self, other: Frames[Axis]) -> Frames[Axis]: + """Return a new Frames object merging self and other. + + Require both Frames objects to not share axes. + + >>> fx = Frames({"x": np.array([1, 2, 3])}) + >>> fy = Frames({"y": np.array([5, 6, 7])}) + >>> fx.zip(fy).midpoints + {'x': array([1, 2, 3]), 'y': array([5, 6, 7])} + """ + overlapping = list(set(self.axes()).intersection(other.axes())) + assert not overlapping, f"Zipping would overwrite axes {overlapping}" + + def zip_dict(ds: Sequence[AxesPoints[Axis]]) -> AxesPoints[Axis]: + # Merge dicts for midpoints, lower, upper. E.g. + # lower[ax] = {**self.lower[ax], **other.lower[ax]} + return dict(kv for d in ds for kv in d.items()) + + def zip_gap(gaps: Sequence[GapArray]) -> GapArray: + # Gap if either frames has a gap. E.g. + # gap[i] = self.gap[i] | other.gap[i] + return np.logical_or.reduce(gaps) + + return _merge_frames(self, other, dict_merge=zip_dict, gap_merge=zip_gap)
+
+ + + +def _merge_frames( + *stack: Frames[Axis], + dict_merge: Callable[[Sequence[AxesPoints[Axis]]], AxesPoints[Axis]], # type: ignore + gap_merge: Callable[[Sequence[GapArray]], GapArray | None], +) -> Frames[Axis]: + types = {type(fs) for fs in stack} + assert len(types) == 1, f"Mismatching types for {stack}" + cls = types.pop() + + # Apply to midpoints, force calculation of gap + return cls( + midpoints=dict_merge([fs.midpoints for fs in stack]), + gap=gap_merge([fs.gap for fs in stack]), + # If any lower or upper are different, apply to those + lower=dict_merge([fs.lower for fs in stack]) + if any(fs.midpoints is not fs.lower for fs in stack) + else None, + upper=dict_merge([fs.upper for fs in stack]) + if any(fs.midpoints is not fs.upper for fs in stack) + else None, + ) + + +
+[docs] +class SnakedFrames(Frames[Axis]): + """Like a `Frames` object, but each alternate repetition will run in reverse.""" + + def __init__( + self, + midpoints: AxesPoints[Axis], + lower: AxesPoints[Axis] | None = None, + upper: AxesPoints[Axis] | None = None, + gap: GapArray | None = None, + ): + super().__init__(midpoints, lower=lower, upper=upper, gap=gap) + # Override first element of gap to be True, as subsequent runs + # of snake scans are always joined end -> start + self.gap[0] = False + +
+[docs] + @classmethod + def from_frames( + cls: type[SnakedFrames[Any]], frames: Frames[OtherAxis] + ) -> SnakedFrames[OtherAxis]: + """Create a snaked version of a `Frames` object.""" + return cls(frames.midpoints, frames.lower, frames.upper, frames.gap)
+ + +
+[docs] + def extract( + self, indices: npt.NDArray[np.signedinteger[Any]], calculate_gap: bool = True + ) -> Frames[Axis]: + """Return a new Frames object restricted to the indices provided. + + Args: + indices: The indices of the frames to extract, can extend past len(self) + calculate_gap: If True then recalculate the gap from upper and lower + + >>> frames = SnakedFrames({"x": np.array([1, 2, 3])}) + >>> frames.extract(np.array([0, 1, 2, 3, 4, 5])).midpoints + {'x': array([1, 2, 3, 3, 2, 1])} + + """ + # Calculate the indices + # E.g for len = 4 + # indices: 0123456789 + # backwards: 0000111100 + # snake_indices: 0123321001 + # gap_indices: 0123032101 + length = len(self) + backwards = (indices // length) % 2 + snake_indices = np.where(backwards, (length - 1) - indices, indices) % length + cls: type[Frames[Any]] + if not calculate_gap: + cls = Frames + gap = self.gap[np.where(backwards, length - indices, indices) % length] + else: + cls = type(self) + gap = None + + # Apply to midpoints + return cls( + {k: v[snake_indices] for k, v in self.midpoints.items()}, + gap=gap, + # If lower or upper are different, apply to those + lower={ + k: np.where(backwards, self.upper[k][snake_indices], v[snake_indices]) + for k, v in self.lower.items() + } + if self.midpoints is not self.lower + else None, + upper={ + k: np.where(backwards, self.lower[k][snake_indices], v[snake_indices]) + for k, v in self.upper.items() + } + if self.midpoints is not self.upper + else None, + )
+
+ + + +
+[docs] +def gap_between_frames(frames1: Frames[Axis], frames2: Frames[Axis]) -> bool: + """Is there a gap between end of frames1 and start of frames2.""" + return any(frames1.upper[a][-1] != frames2.lower[a][0] for a in frames1.axes())
+ + + +
+[docs] +def squash_frames( + stack: list[Frames[Axis]], check_path_changes: bool = True +) -> Frames[Axis]: + """Squash a stack of nested Frames into a single one. + + Args: + stack: The Frames stack to squash, from slowest to fastest moving + check_path_changes: If True then check that nesting the output + Frames object within others will provide the same path + as nesting the input Frames stack within others + + See Also: + `why-squash-can-change-path` + + >>> fx = SnakedFrames({"x": np.array([1, 2])}) + >>> fy = Frames({"y": np.array([3, 4])}) + >>> squash_frames([fy, fx]).midpoints + {'y': array([3, 3, 4, 4]), 'x': array([1, 2, 2, 1])} + + """ + path = Path(stack) + # Consuming a Path through these Frames performs the squash + squashed = path.consume() + # Check that the squash is the same as the original + if stack and isinstance(stack[0], SnakedFrames): + squashed = SnakedFrames.from_frames(squashed) + # The top level is snaking, so this Frames object will run backwards + # This means any non-snaking axes will run backwards, which is + # surprising, so don't allow it + if check_path_changes: + non_snaking = [ + k for d in stack for k in d.axes() if not isinstance(d, SnakedFrames) + ] + if non_snaking: + raise ValueError( + f"Cannot squash non-snaking Frames inside a SnakingFrames " + f"otherwise {non_snaking} would run backwards" + ) + elif check_path_changes: + # The top level is not snaking, so make sure there is an even + # number of iterations of any snaking axis within it so it + # doesn't jump when this frames object is iterated a second time + for i, frames in enumerate(stack): + # A SnakedFrames within a non-snaking top level must repeat + # an even number of times + if isinstance(frames, SnakedFrames) and np.prod(path.lengths[:i]) % 2: + raise ValueError( + f"Cannot squash SnakingFrames inside a non-snaking Frames " + f"when they do not repeat an even number of times " + f"otherwise {frames.axes()} would jump in position" + ) + return squashed
+ + + +
+[docs] +class Path(Generic[Axis]): + """A consumable route through a stack of Frames, representing a scan path. + + Args: + stack: The Frames stack describing the scan, from slowest to fastest + moving + start: The index of where in the Path to start + num: The number of scan frames to produce after start. None means up to + the end + + See Also: + `iterate-a-spec` + + """ + + def __init__( + self, stack: list[Frames[Axis]], start: int = 0, num: int | None = None + ): + #: The Frames stack describing the scan, from slowest to fastest moving + self.stack = stack + #: Index that is next to be consumed + self.index = start + #: The lengths of all the stack + self.lengths = np.array([len(f) for f in stack]) + #: Index of the end frame, one more than the last index that will be + #: produced + self.end_index = int(np.prod(self.lengths)) + if num is not None and start + num < self.end_index: + self.end_index = start + num + +
+[docs] + def consume(self, num: int | None = None) -> Frames[Axis]: + """Consume at most num frames from the Path and return as a Frames object. + + >>> fx = SnakedFrames({"x": np.array([1, 2])}) + >>> fy = Frames({"y": np.array([3, 4])}) + >>> path = Path([fy, fx]) + >>> path.consume(3).midpoints + {'y': array([3, 3, 4]), 'x': array([1, 2, 2])} + >>> path.consume(3).midpoints + {'y': array([4]), 'x': array([1])} + >>> path.consume(3).midpoints + {'y': array([], dtype=int64), 'x': array([], dtype=int64)} + """ + if num is None: + end_index = self.end_index + else: + end_index = min(self.index + num, self.end_index) + indices = np.arange(self.index, end_index) + self.index = end_index + stack: Frames[Axis] = Frames( + {}, {}, {}, np.zeros(indices.shape, dtype=np.bool_) + ) + # Example numbers below from a 2x3x4 ZxYxX scan + for i, frames in enumerate(self.stack): + # Number of times each frame will repeat: Z:12, Y:4, X:1 + repeats = np.prod(self.lengths[i + 1 :]) + # Scan indices mapped to indices within Frames object: + # Z:000000000000111111111111 + # Y:000011112222000011112222 + # X:012301230123012301230123 + if repeats > 1: + dim_indices = indices // repeats + else: + dim_indices = indices + # Create the sliced frames + sliced = frames.extract(dim_indices, calculate_gap=False) + if repeats > 1: + # Whether this frames contributes to the gap bit + # Z:000000000000100000000000 + # Y:000010001000100010001000 + # X:111111111111111111111111 + in_gap = (indices % repeats) == 0 + # If in_gap, then keep the relevant gap bit + sliced.gap &= in_gap + # Zip it with the output Frames object + stack = stack.zip(sliced) + return stack
+ + + def __len__(self) -> int: + """Number of frames left in a scan, reduces when `consume` is called.""" + return self.end_index - self.index
+ + + +
+[docs] +class Midpoints(Generic[Axis]): + """Convenience iterable that produces the scan midpoints for each axis. + + For better performance, consume from a `Path` instead. + + Args: + stack: The stack of Frames describing the scan, from slowest to fastest + moving + + See Also: + `iterate-a-spec` + + >>> fx = SnakedFrames({"x": np.array([1, 2])}) + >>> fy = Frames({"y": np.array([3, 4])}) + >>> mp = Midpoints([fy, fx]) + >>> for p in mp: print(p) + {'y': np.int64(3), 'x': np.int64(1)} + {'y': np.int64(3), 'x': np.int64(2)} + {'y': np.int64(4), 'x': np.int64(2)} + {'y': np.int64(4), 'x': np.int64(1)} + + """ + + def __init__(self, stack: list[Frames[Axis]]): + #: The stack of Frames describing the scan, from slowest to fastest moving + self.stack = stack + + @property + def axes(self) -> list[Axis]: + """The axes that will be present in each points dictionary.""" + return list(itertools.chain(*(frames.axes() for frames in self.stack))) + + def __len__(self) -> int: + """The number of dictionaries that will be produced if iterated over.""" + return int(np.prod([len(frames) for frames in self.stack])) + + def __iter__(self) -> Iterator[dict[Axis, float]]: + """Yield {axis: midpoint} for each frame in the scan.""" + path = Path(self.stack) + while len(path): + frames = path.consume(1) + yield {a: frames.midpoints[a][0] for a in frames.axes()}
+ +
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/0.7.5/_modules/scanspec/plot.html b/0.7.5/_modules/scanspec/plot.html new file mode 100644 index 00000000..ff288832 --- /dev/null +++ b/0.7.5/_modules/scanspec/plot.html @@ -0,0 +1,798 @@ + + + + + + + + + + scanspec.plot — scanspec 0.7.5 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
+
+
+
+ +
+ +
+ + + + + +
+
+ + + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for scanspec.plot

+"""`plot_spec` to visualize a scan."""
+
+from collections.abc import Iterable, Iterator
+from itertools import cycle
+from typing import Any
+
+import numpy as np
+import numpy.typing as npt
+from matplotlib import colors, patches
+from matplotlib import pyplot as plt
+from matplotlib.axes import Axes
+from mpl_toolkits.mplot3d import Axes3D, proj3d  # type: ignore
+from scipy import interpolate  # type: ignore
+
+from .core import Path
+from .regions import Circle, Ellipse, Polygon, Rectangle, Region, find_regions
+from .specs import DURATION, Spec
+
+__all__ = ["plot_spec"]
+
+
+def _plot_arrays(
+    axes: Axes, arrays: list[npt.NDArray[np.floating[Any]]], **kwargs: Any
+):
+    if len(arrays) > 2:
+        axes.plot3D(arrays[2], arrays[1], arrays[0], **kwargs)  # type: ignore
+    elif len(arrays) == 2:
+        axes.plot(arrays[1], arrays[0], **kwargs)  # type: ignore
+    else:
+        axes.plot(arrays[0], np.zeros(len(arrays[0])), **kwargs)  # type: ignore
+
+
+# https://stackoverflow.com/a/11156353
+class Arrow3D(patches.FancyArrowPatch):
+    def __init__(
+        self,
+        xs: npt.NDArray[np.floating[Any]],
+        ys: npt.NDArray[np.floating[Any]],
+        zs: npt.NDArray[np.floating[Any]],
+        *args: Any,
+        **kwargs: Any,
+    ):
+        super().__init__((0, 0), (0, 0), *args, **kwargs)  # type: ignore
+        self._verts3d = xs, ys, zs
+
+    # Added here because of https://github.com/matplotlib/matplotlib/issues/21688
+    def do_3d_projection(self, renderer: Any = None):
+        xs3d, ys3d, zs3d = self._verts3d
+        xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M)  # type: ignore
+        self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
+
+        return np.min(zs)
+
+    @property
+    def verts3d(
+        self,
+    ) -> tuple[
+        npt.NDArray[np.floating[Any]],
+        npt.NDArray[np.floating[Any]],
+        npt.NDArray[np.floating[Any]],
+    ]:
+        return self._verts3d
+
+
+def _plot_arrow(axes: Axes, arrays: list[npt.NDArray[np.floating[Any]]]):
+    if len(arrays) == 1:
+        arrays = [np.array([0, 0])] + arrays
+    if len(arrays) == 2:
+        head = [a[-1] for a in reversed(arrays)]
+        tail = [a[-1] - (a[-1] - a[-2]) * 0.1 for a in reversed(arrays)]
+        axes.annotate(  # type: ignore
+            "",
+            tuple(head[:2]),
+            tuple(tail[:2]),
+            arrowprops={"color": "lightgrey", "arrowstyle": "-|>"},
+        )
+    elif len(arrays) == 3:
+        arrows = [a[-2:] for a in reversed(arrays)]
+        a = Arrow3D(*arrows[:3], mutation_scale=10, arrowstyle="-|>", color="lightgrey")
+        axes.add_artist(a)
+
+
+def _plot_spline(
+    axes: Axes,
+    ranges: list[float],
+    arrays: list[npt.NDArray[np.floating[Any]]],
+    index_colours: dict[int, str],
+) -> Iterable[list[npt.NDArray[np.floating[Any]]]]:
+    scaled_arrays = [a / r for a, r in zip(arrays, ranges, strict=False)]
+    # Define curves parametrically
+    t = np.zeros(len(arrays[0]))
+    t[1:] = np.sqrt(sum((arr[1:] - arr[:-1]) ** 2 for arr in scaled_arrays))
+    t = np.cumsum(t)
+    if t[-1] > 0:
+        # Can't make a spline that starts and ends in the same place, so add a small
+        # delta
+        for s, r in zip(scaled_arrays, ranges, strict=False):
+            if s[0] == s[-1]:
+                s += np.linspace(0, r * 1e-7, len(s))
+        # There are no duplicated points, plot a spline
+        t /= t[-1]
+        # Scale the arrays so splines don't favour larger scaled axes
+        tck, _ = interpolate.splprep(scaled_arrays, k=2, s=0)  # type: ignore
+        starts = sorted(index_colours)
+        stops = starts[1:] + [len(arrays[0]) - 1]
+        for start, stop in zip(starts, stops, strict=False):
+            start_value: float = t[start]
+            stop_value: float = t[stop]
+            tnew = np.linspace(start_value, stop_value, num=1001)
+            spline: npt.NDArray[np.floating[Any]] = interpolate.splev(tnew, tck)  # type: ignore
+            # Scale the splines back to the original scaling
+            unscaled_splines = [a * r for a, r in zip(spline, ranges, strict=False)]
+            _plot_arrays(axes, unscaled_splines, color=index_colours[start])
+            yield unscaled_splines
+
+
+
+[docs] +def plot_spec(spec: Spec[Any], title: str | None = None): + """Plot a spec, drawing the path taken through the scan. + + Uses a different colour for each frame, grey for the turnarounds, and + marks the midpoints with a filled circle if there are less than 200 of + them. If the scan is 2D then 2D regions are shown in black. + + .. example_spec:: + + from scanspec.specs import Line + from scanspec.regions import Circle + + cube = Line("z", 1, 3, 3) * Line("y", 1, 3, 10) * ~Line("x", 0, 2, 10) + spec = cube & Circle("x", "y", 1, 2, 0.9) + """ + dims = spec.calculate() + dim = Path(dims).consume() + axes = [a for a in spec.axes() if a is not DURATION] + ndims = len(axes) + + # Setup axes + if ndims > 2: + plt.figure(figsize=(6, 6)) # type: ignore + plt_axes: Axes = plt.axes(projection="3d") # type: ignore + plt_axes.grid(False) # type: ignore + if isinstance(plt_axes, Axes3D): + plt_axes.set_zlabel(axes[-3]) # type: ignore + plt_axes.set_ylabel(axes[-2]) # type: ignore + plt_axes.view_init(elev=15) # type: ignore + else: + raise TypeError( + "Expected matplotlib to create an Axes3D object, " + f"instead got: {plt_axes}" + ) + elif ndims == 2: + plt.figure(figsize=(6, 6)) # type: ignore + plt_axes = plt.axes() # type: ignore + plt_axes.set_ylabel(axes[-2]) # type: ignore + else: + plt.figure(figsize=(6, 2)) # type: ignore + plt_axes = plt.axes() # type: ignore + plt_axes.yaxis.set_visible(False) + plt_axes.set_xlabel(axes[-1]) # type: ignore + + # Title with dimension sizes + title = title or ", ".join(f"Dim[{' '.join(d.axes())} len={len(d)}]" for d in dims) + plt.title(title) # type: ignore + + # Plot any Regions + if ndims <= 2: + regions: Iterator[Region[Any]] = find_regions(spec) + for region in regions: + if isinstance(region, Rectangle): + xy = (region.x_min, region.y_min) + width = region.x_max - region.x_min + height = region.y_max - region.y_min + plt_axes.add_patch( + patches.Rectangle(xy, width, height, angle=region.angle, fill=False) + ) + elif isinstance(region, Circle): + xy = (region.x_middle, region.y_middle) + plt_axes.add_patch(patches.Circle(xy, region.radius, fill=False)) + elif isinstance(region, Ellipse): + xy = (region.x_middle, region.y_middle) + width = region.x_radius * 2 + height = region.y_radius * 2 + angle = region.angle + plt_axes.add_patch( + patches.Ellipse(xy, width, height, angle=angle, fill=False) + ) + elif isinstance(region, Polygon): + # *xy_verts* is a numpy array with shape Nx2. + xy_verts = np.column_stack((region.x_verts, region.y_verts)) + plt_axes.add_patch(patches.Polygon(xy_verts, fill=False)) + + # Plot the splines + tail: dict[str, npt.NDArray[np.floating[Any]] | None] = {a: None for a in axes} + ranges = [max(float(np.max(v) - np.min(v)), 0.0001) for v in dim.midpoints.values()] + seg_col = cycle(colors.TABLEAU_COLORS) + last_index = 0 + splines = None + # The first element of gap is undefined (as there is no previous frame) + # so discard it + gap_indices = list(np.nonzero(dim.gap[1:])[0] + 1) + for index in gap_indices + [len(dim)]: + num_points = index - last_index + arrays: list[npt.NDArray[np.floating[Any]]] = [] + turnaround: list[npt.NDArray[np.floating[Any]]] = [] + for a in axes: + # Add the midpoints and the lower and upper bounds + arr = np.empty(num_points * 2 + 1) + arr[:-1:2] = dim.lower[a][last_index:index] + arr[1::2] = dim.midpoints[a][last_index:index] + arr[-1] = dim.upper[a][index - 1] + arrays.append(arr) + # Add the turnaround + axis_tail = tail[a] + if axis_tail is not None: + # Already had a tail, add lead in points + axis_tail[2:] = np.linspace(-0.01, 0, 2) * (arr[1] - arr[0]) + arr[0] + turnaround.append(axis_tail) + # Add tail off points + axis_tail = np.empty(4) + axis_tail[:2] = np.linspace(0, 0.01, 2) * (arr[-1] - arr[-2]) + arr[-1] + tail[a] = axis_tail + last_index = index + + arrow_arr = None + if turnaround: + # If we didn't move then plot a straight line from start to stop + if all(t[1] - t[0] == 0 for t in turnaround): + for t in turnaround: + t[1] += (t[2] - t[1]) / 4 + if all(t[3] - t[2] == 0 for t in turnaround): + for t in turnaround: + t[2] -= (t[2] - t[1]) / 4 + # Plot the turnaround + arrow_arr = list( + _plot_spline(plt_axes, ranges, turnaround, {0: "lightgrey"}) + )[0] + + # Plot the points + index_colours = {2 * i: next(seg_col) for i in range(num_points)} + splines = list(_plot_spline(plt_axes, ranges, arrays, index_colours)) + + if arrow_arr: + # Plot the arrow on the turnaround + _plot_arrow(plt_axes, arrow_arr) + elif splines: + # Plot the starting arrow in the direction of the first point + arrow_arr = [np.array([2 * a[0] - a[1], a[0]]) for a in splines[0]] + _plot_arrow(plt_axes, arrow_arr) + else: + # First point isn't moving, put a right caret marker + _plot_arrays( + plt_axes, + [np.array([dim.lower[a][0]]) for a in axes], + marker=5, + color="lightgrey", + ) + + # Plot the capture points + if len(dim) < 200: + arrays = [dim.midpoints[a] for a in axes] + _plot_arrays(plt_axes, arrays, linestyle="", marker=".", color="k") + + # Plot the end + _plot_arrays( + plt_axes, + [np.array([dim.upper[a][-1]]) for a in axes], + marker="x", + color="lightgrey", + ) + + plt.show() # type: ignore
+ +
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/0.7.5/_modules/scanspec/regions.html b/0.7.5/_modules/scanspec/regions.html new file mode 100644 index 00000000..f66bdd6a --- /dev/null +++ b/0.7.5/_modules/scanspec/regions.html @@ -0,0 +1,1006 @@ + + + + + + + + + + scanspec.regions — scanspec 0.7.5 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
+
+
+
+ +
+ +
+ + + + + +
+
+ + + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for scanspec.regions

+"""`Region` and its subclasses.
+
+.. inheritance-diagram:: scanspec.regions
+    :top-classes: scanspec.regions.Region
+    :parts: 1
+"""
+
+from __future__ import annotations
+
+from collections.abc import Iterator, Mapping
+from dataclasses import is_dataclass
+from typing import Any, Generic, cast
+
+import numpy as np
+import numpy.typing as npt
+from pydantic import BaseModel, Field, TypeAdapter
+from pydantic.dataclasses import dataclass
+
+from .core import (
+    AxesPoints,
+    Axis,
+    StrictConfig,
+    discriminated_union_of_subclasses,
+    if_instance_do,
+)
+
+__all__ = [
+    "Region",
+    "get_mask",
+    "CombinationOf",
+    "UnionOf",
+    "IntersectionOf",
+    "DifferenceOf",
+    "SymmetricDifferenceOf",
+    "Range",
+    "Rectangle",
+    "Polygon",
+    "Circle",
+    "Ellipse",
+    "find_regions",
+]
+
+NpMask = npt.NDArray[np.bool]
+
+
+
+[docs] +@discriminated_union_of_subclasses +class Region(Generic[Axis]): + """Abstract baseclass for a Region that can `Mask` a `Spec`. + + Supports operators: + + - ``|``: `UnionOf` two Regions, midpoints present in either + - ``&``: `IntersectionOf` two Regions, midpoints present in both + - ``-``: `DifferenceOf` two Regions, midpoints present in first not second + - ``^``: `SymmetricDifferenceOf` two Regions, midpoints present in one not both + """ + +
+[docs] + def axis_sets(self) -> list[set[Axis]]: # noqa: D102 + """Produce the non-overlapping sets of axes this region spans.""" + raise NotImplementedError(self)
+ + +
+[docs] + def mask(self, points: AxesPoints[Axis]) -> NpMask: # noqa: D102 + """Produce a mask of which points are in the region.""" + raise NotImplementedError(self)
+ + + def __or__(self, other: Region[Axis]) -> UnionOf[Axis]: + return if_instance_do(other, Region, lambda o: UnionOf(self, o)) + + def __and__(self, other: Region[Axis]) -> IntersectionOf[Axis]: + return if_instance_do(other, Region, lambda o: IntersectionOf(self, o)) + + def __sub__(self, other: Region[Axis]) -> DifferenceOf[Axis]: + return if_instance_do(other, Region, lambda o: DifferenceOf(self, o)) + + def __xor__(self, other: Region[Axis]) -> SymmetricDifferenceOf[Axis]: + return if_instance_do(other, Region, lambda o: SymmetricDifferenceOf(self, o)) + +
+[docs] + def serialize(self) -> Mapping[str, Any]: + """Serialize the Region to a dictionary.""" + return TypeAdapter(Region[Any]).dump_python(self)
+ + +
+[docs] + @staticmethod + def deserialize(obj: Any) -> Region[Any]: + """Deserialize a Region from a dictionary.""" + return TypeAdapter(Region[Any]).validate_python(obj)
+
+ + + +
+[docs] +def get_mask(region: Region[Axis], points: AxesPoints[Axis]) -> NpMask: + """Return a mask of the points inside the region. + + If there is an overlap of axes of region and points return a + mask of the points in the region, otherwise return all ones + """ + axes = set(points) + needs_mask = any(ks & axes for ks in region.axis_sets()) + if needs_mask: + return region.mask(points) + else: + return np.ones(len(list(points.values())[0]), dtype=np.bool)
+ + + +def _merge_axis_sets(axis_sets: list[set[Axis]]) -> Iterator[set[Axis]]: + # Take overlapping axis sets and merge any that overlap into each + # other + for ks in axis_sets: # ks = key_sets - left over from a previous naming standard + axis_set = ks.copy() + # Empty matching sets into this axis_set + for ks in axis_sets: + if ks & axis_set: + while ks: + axis_set.add(ks.pop()) + # It might be emptied already, only yield if it isn't + if axis_set: + yield axis_set + + +
+[docs] +@dataclass(config=StrictConfig) +class CombinationOf(Region[Axis]): + """Abstract baseclass for a combination of two regions, left and right.""" + + left: Region[Axis] = Field(description="The left-hand Region to combine") + right: Region[Axis] = Field(description="The right-hand Region to combine") + +
+[docs] + def axis_sets(self) -> list[set[Axis]]: # noqa: D102 + axis_sets = list( + _merge_axis_sets(self.left.axis_sets() + self.right.axis_sets()) + ) + return axis_sets
+
+ + + +# Naming so we don't clash with typing.Union +
+[docs] +@dataclass(config=StrictConfig) +class UnionOf(CombinationOf[Axis]): + """A point is in UnionOf(a, b) if in either a or b. + + Typically created with the ``|`` operator + + >>> r = Range("x", 0.5, 2.5) | Range("x", 1.5, 3.5) + >>> r.mask({"x": np.array([0, 1, 2, 3, 4])}) + array([False, True, True, True, False]) + """ + +
+[docs] + def mask(self, points: AxesPoints[Axis]) -> NpMask: # noqa: D102 + mask = get_mask(self.left, points) | get_mask(self.right, points) + return mask
+
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class IntersectionOf(CombinationOf[Axis]): + """A point is in IntersectionOf(a, b) if in both a and b. + + Typically created with the ``&`` operator. + + >>> r = Range("x", 0.5, 2.5) & Range("x", 1.5, 3.5) + >>> r.mask({"x": np.array([0, 1, 2, 3, 4])}) + array([False, False, True, False, False]) + """ + +
+[docs] + def mask(self, points: AxesPoints[Axis]) -> NpMask: # noqa: D102 + mask = get_mask(self.left, points) & get_mask(self.right, points) + return mask
+
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class DifferenceOf(CombinationOf[Axis]): + """A point is in DifferenceOf(a, b) if in a and not in b. + + Typically created with the ``-`` operator. + + >>> r = Range("x", 0.5, 2.5) - Range("x", 1.5, 3.5) + >>> r.mask({"x": np.array([0, 1, 2, 3, 4])}) + array([False, True, False, False, False]) + """ + +
+[docs] + def mask(self, points: AxesPoints[Axis]) -> NpMask: # noqa: D102 + left_mask = get_mask(self.left, points) + # Return the xor restricted to the left region + mask = left_mask ^ get_mask(self.right, points) & left_mask + return mask
+
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class SymmetricDifferenceOf(CombinationOf[Axis]): + """A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both. + + Typically created with the ``^`` operator. + + >>> r = Range("x", 0.5, 2.5) ^ Range("x", 1.5, 3.5) + >>> r.mask({"x": np.array([0, 1, 2, 3, 4])}) + array([False, True, False, True, False]) + """ + +
+[docs] + def mask(self, points: AxesPoints[Axis]) -> NpMask: # noqa: D102 + mask = get_mask(self.left, points) ^ get_mask(self.right, points) + return mask
+
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class Range(Region[Axis]): + """Mask contains points of axis >= min and <= max. + + >>> r = Range("x", 1, 2) + >>> r.mask({"x": np.array([0, 1, 2, 3, 4])}) + array([False, True, True, False, False]) + """ + + axis: Axis = Field(description="The name matching the axis to mask in spec") + min: float = Field(description="The minimum inclusive value in the region") + max: float = Field(description="The minimum inclusive value in the region") + +
+[docs] + def axis_sets(self) -> list[set[Axis]]: # noqa: D102 + return [{self.axis}]
+ + +
+[docs] + def mask(self, points: AxesPoints[Axis]) -> NpMask: # noqa: D102 + v = points[self.axis] + mask = np.bitwise_and(v >= self.min, v <= self.max) + return mask
+
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class Rectangle(Region[Axis]): + """Mask contains points of axis within a rotated xy rectangle. + + .. example_spec:: + + from scanspec.regions import Rectangle + from scanspec.specs import Line + + grid = Line("y", 1, 3, 10) * ~Line("x", 0, 2, 10) + spec = grid & Rectangle("x", "y", 0, 1.1, 1.5, 2.1, 30) + """ + + x_axis: Axis = Field(description="The name matching the x axis of the spec") + y_axis: Axis = Field(description="The name matching the y axis of the spec") + x_min: float = Field(description="Minimum inclusive x value in the region") + y_min: float = Field(description="Minimum inclusive y value in the region") + x_max: float = Field(description="Maximum inclusive x value in the region") + y_max: float = Field(description="Maximum inclusive y value in the region") + angle: float = Field( + description="Clockwise rotation angle of the rectangle", default=0.0 + ) + +
+[docs] + def axis_sets(self) -> list[set[Axis]]: # noqa: D102 + return [{self.x_axis, self.y_axis}]
+ + +
+[docs] + def mask(self, points: AxesPoints[Axis]) -> NpMask: # noqa: D102 + x = points[self.x_axis] - self.x_min + y = points[self.y_axis] - self.y_min + if self.angle != 0: + # Rotate src points by -angle + phi = np.radians(-self.angle) + rx = x * np.cos(phi) - y * np.sin(phi) + ry = x * np.sin(phi) + y * np.cos(phi) + x = rx + y = ry + mask_x = np.bitwise_and(x >= 0, x <= (self.x_max - self.x_min)) + mask_y = np.bitwise_and(y >= 0, y <= (self.y_max - self.y_min)) + return mask_x & mask_y
+
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class Polygon(Region[Axis]): + """Mask contains points of axis within a rotated xy polygon. + + .. example_spec:: + + from scanspec.regions import Polygon + from scanspec.specs import Line + + grid = Line("y", 3, 8, 10) * ~Line("x", 1 ,8, 10) + spec = grid & Polygon("x", "y", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0]) + """ + + x_axis: Axis = Field(description="The name matching the x axis of the spec") + y_axis: Axis = Field(description="The name matching the y axis of the spec") + x_verts: list[float] = Field( + description="The Nx1 x coordinates of the polygons vertices", min_length=3 + ) + y_verts: list[float] = Field( + description="The Nx1 y coordinates of the polygons vertices", min_length=3 + ) + +
+[docs] + def axis_sets(self) -> list[set[Axis]]: # noqa: D102 + return [{self.x_axis, self.y_axis}]
+ + +
+[docs] + def mask(self, points: AxesPoints[Axis]) -> NpMask: # noqa: D102 + x = points[self.x_axis] + y = points[self.y_axis] + v1x, v1y = self.x_verts[-1], self.y_verts[-1] + mask = np.full(len(x), False, dtype=np.bool) + for v2x, v2y in zip(self.x_verts, self.y_verts, strict=False): + # skip horizontal edges + if v2y != v1y: + vmask = np.full(len(x), False, dtype=np.bool) + vmask |= (y < v2y) & (y >= v1y) + vmask |= (y < v1y) & (y >= v2y) + t = (y - v1y) / (v2y - v1y) + vmask &= x < v1x + t * (v2x - v1x) + mask ^= vmask + v1x, v1y = v2x, v2y + return mask
+
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class Circle(Region[Axis]): + """Mask contains points of axis within an xy circle of given radius. + + .. example_spec:: + + from scanspec.regions import Circle + from scanspec.specs import Line + + grid = Line("y", 1, 3, 10) * ~Line("x", 0, 2, 10) + spec = grid & Circle("x", "y", 1, 2, 0.9) + """ + + x_axis: Axis = Field(description="The name matching the x axis of the spec") + y_axis: Axis = Field(description="The name matching the y axis of the spec") + x_middle: float = Field(description="The central x point of the circle") + y_middle: float = Field(description="The central y point of the circle") + radius: float = Field(description="Radius of the circle", gt=0.0) + +
+[docs] + def axis_sets(self) -> list[set[Axis]]: # noqa: D102 + return [{self.x_axis, self.y_axis}]
+ + +
+[docs] + def mask(self, points: AxesPoints[Axis]) -> NpMask: # noqa: D102 + x = points[self.x_axis] - self.x_middle + y = points[self.y_axis] - self.y_middle + mask = x * x + y * y <= (self.radius * self.radius) + return mask
+
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class Ellipse(Region[Axis]): + """Mask contains points of axis within an xy ellipse of given radius. + + .. example_spec:: + + from scanspec.regions import Ellipse + from scanspec.specs import Line + + grid = Line("y", 3, 8, 10) * ~Line("x", 1 ,8, 10) + spec = grid & Ellipse("x", "y", 5, 5, 2, 3, 75) + """ + + x_axis: Axis = Field(description="The name matching the x axis of the spec") + y_axis: Axis = Field(description="The name matching the y axis of the spec") + x_middle: float = Field(description="The central x point of the ellipse") + y_middle: float = Field(description="The central y point of the ellipse") + x_radius: float = Field( + description="The radius along the x axis of the ellipse", gt=0.0 + ) + y_radius: float = Field( + description="The radius along the y axis of the ellipse", gt=0.0 + ) + angle: float = Field(description="The angle of the ellipse (degrees)", default=0.0) + +
+[docs] + def axis_sets(self) -> list[set[Axis]]: # noqa: D102 + return [{self.x_axis, self.y_axis}]
+ + +
+[docs] + def mask(self, points: AxesPoints[Axis]) -> NpMask: # noqa: D102 + x = points[self.x_axis] - self.x_middle + y = points[self.y_axis] - self.y_middle + if self.angle != 0: + # Rotate src points by -angle + phi = np.radians(-self.angle) + tx = x * np.cos(phi) - y * np.sin(phi) + ty = x * np.sin(phi) + y * np.cos(phi) + x = tx + y = ty + mask = (x / self.x_radius) ** 2 + (y / self.y_radius) ** 2 <= 1 + return mask
+
+ + + +
+[docs] +def find_regions(obj: Any) -> Iterator[Region[Any]]: # noqa: D102 + """Recursively yield Regions from obj and its children.""" + if ( + hasattr(obj, "__pydantic_model__") + and issubclass(obj.__pydantic_model__, BaseModel) + or is_dataclass(obj) + ): + if isinstance(obj, Region): + yield obj + for name in obj.__dict__.keys(): + regions: Iterator[Region[Any]] = find_regions(getattr(cast(Any, obj), name)) + yield from regions
+ +
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/0.7.5/_modules/scanspec/specs.html b/0.7.5/_modules/scanspec/specs.html new file mode 100644 index 00000000..e337ee27 --- /dev/null +++ b/0.7.5/_modules/scanspec/specs.html @@ -0,0 +1,1422 @@ + + + + + + + + + + scanspec.specs — scanspec 0.7.5 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
+
+
+
+ +
+ +
+ + + + + +
+
+ + + + + +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for scanspec.specs

+"""`Spec` and its subclasses.
+
+.. inheritance-diagram:: scanspec.specs
+    :top-classes: scanspec.specs.Spec
+    :parts: 1
+"""
+
+from __future__ import annotations
+
+from collections.abc import Callable, Mapping
+from typing import Any, Generic, overload
+
+import numpy as np
+import numpy.typing as npt
+from pydantic import Field, TypeAdapter, validate_call
+from pydantic.dataclasses import dataclass
+
+from .core import (
+    Axis,
+    Frames,
+    Midpoints,
+    OtherAxis,
+    Path,
+    SnakedFrames,
+    StrictConfig,
+    discriminated_union_of_subclasses,
+    gap_between_frames,
+    if_instance_do,
+    squash_frames,
+)
+from .regions import Region, get_mask
+
+__all__ = [
+    "DURATION",
+    "Spec",
+    "Product",
+    "Repeat",
+    "Zip",
+    "Mask",
+    "Snake",
+    "Concat",
+    "Squash",
+    "Line",
+    "Static",
+    "Spiral",
+    "fly",
+    "step",
+]
+
+
+#: Can be used as a special key to indicate how long each point should be
+DURATION = "DURATION"
+
+
+
+[docs] +@discriminated_union_of_subclasses +class Spec(Generic[Axis]): + """A serializable representation of the type and parameters of a scan. + + Abstract baseclass for the specification of a scan. Supports operators: + + - ``*``: Outer `Product` of two Specs, nesting the second within the first. + If the first operand is an integer, wrap it in a `Repeat` + - ``&``: `Mask` the Spec with a `Region`, excluding midpoints outside of it + - ``~``: `Snake` the Spec, reversing every other iteration of it + """ + +
+[docs] + def axes(self) -> list[Axis]: # noqa: D102 + """Return the list of axes that are present in the scan. + + Ordered from slowest moving to fastest moving. + """ + raise NotImplementedError(self)
+ + +
+[docs] + def calculate( + self, bounds: bool = True, nested: bool = False + ) -> list[Frames[Axis]]: # noqa: D102 + """Produce a stack of nested `Frames` that form the scan. + + Ordered from slowest moving to fastest moving. + """ + raise NotImplementedError(self)
+ + +
+[docs] + def frames(self) -> Frames[Axis]: + """Expand all the scan `Frames` and return them.""" + return Path(self.calculate()).consume()
+ + +
+[docs] + def midpoints(self) -> Midpoints[Axis]: + """Return `Midpoints` that can be iterated point by point.""" + return Midpoints(self.calculate(bounds=False))
+ + +
+[docs] + def shape(self) -> tuple[int, ...]: + """Return the final, simplified shape of the scan.""" + return tuple(len(dim) for dim in self.calculate())
+ + + def __rmul__(self, other: int) -> Product[Axis]: + return if_instance_do(other, int, lambda o: Product(Repeat(o), self)) + + @overload + def __mul__(self, other: Spec[Axis]) -> Product[Axis]: ... + + @overload + def __mul__(self, other: Spec[OtherAxis]) -> Product[Axis | OtherAxis]: ... + + def __mul__( + self, other: Spec[Axis] | Spec[OtherAxis] + ) -> Product[Axis] | Product[Axis | OtherAxis]: + return if_instance_do(other, Spec, lambda o: Product(self, o)) + + def __and__(self, other: Region[Axis]) -> Mask[Axis]: + return if_instance_do(other, Region, lambda o: Mask(self, o)) + + def __invert__(self) -> Snake[Axis]: + return Snake(self) + +
+[docs] + def zip(self, other: Spec[OtherAxis]) -> Zip[Axis | OtherAxis]: + """`Zip` the Spec with another, iterating in tandem.""" + return Zip(left=self, right=other)
+ + +
+[docs] + def concat(self, other: Spec[Axis]) -> Concat[Axis]: + """`Concat` the Spec with another, iterating one after the other.""" + return Concat(self, other)
+ + +
+[docs] + def serialize(self) -> Mapping[str, Any]: + """Serialize the Spec to a dictionary.""" + return TypeAdapter(Spec[Any]).dump_python(self)
+ + +
+[docs] + @staticmethod + def deserialize(obj: Any) -> Spec[Any]: + """Deserialize a Spec from a dictionary.""" + return TypeAdapter(Spec[Any]).validate_python(obj)
+
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class Product(Spec[Axis]): + """Outer product of two Specs, nesting inner within outer. + + This means that inner will run in its entirety at each point in outer. + + .. example_spec:: + + from scanspec.specs import Line + + spec = Line("y", 1, 2, 3) * Line("x", 3, 4, 12) + """ + + outer: Spec[Axis] = Field(description="Will be executed once") + inner: Spec[Axis] = Field(description="Will be executed len(outer) times") + +
+[docs] + def axes(self) -> list[Axis]: # noqa: D102 + return self.outer.axes() + self.inner.axes()
+ + +
+[docs] + def calculate( # noqa: D102 + self, bounds: bool = True, nested: bool = False + ) -> list[Frames[Axis]]: + frames_outer = self.outer.calculate(bounds=False, nested=nested) + frames_inner = self.inner.calculate(bounds, nested=True) + return frames_outer + frames_inner
+
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class Repeat(Spec[Axis]): + """Repeat an empty frame num times. + + Can be used on the outside of a scan to repeat the same scan many times. + + .. example_spec:: + + from scanspec.specs import Line + + spec = 2 * ~Line.bounded("x", 3, 4, 1) + + If you want snaked axes to have no gap between iterations you can do: + + .. example_spec:: + + from scanspec.specs import Line, Repeat + + spec = Repeat(2, gap=False) * ~Line.bounded("x", 3, 4, 1) + + .. note:: There is no turnaround arrow at x=4 + """ + + num: int = Field(ge=1, description="Number of frames to produce") + gap: bool = Field( + description="If False and the slowest of the stack of Frames is snaked " + "then the end and start of consecutive iterations of Spec will have no gap", + default=True, + ) + +
+[docs] + def axes(self) -> list[Axis]: # noqa: D102 + return []
+ + +
+[docs] + def calculate( # noqa: D102 + self, bounds: bool = True, nested: bool = False + ) -> list[Frames[Axis]]: + return [Frames({}, gap=np.full(self.num, self.gap))]
+
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class Zip(Spec[Axis]): + """Run two Specs in parallel, merging their midpoints together. + + Typically formed using `Spec.zip`. + + Stacks of Frames are merged by: + + - If right creates a stack of a single Frames object of size 1, expand it to + the size of the fastest Frames object created by left + - Merge individual Frames objects together from fastest to slowest + + This means that Zipping a Spec producing stack [l2, l1] with a Spec + producing stack [r1] will assert len(l1)==len(r1), and produce + stack [l2, l1.zip(r1)]. + + .. example_spec:: + + from scanspec.specs import Line + + spec = Line("z", 1, 2, 3) * Line("y", 3, 4, 5).zip(Line("x", 4, 5, 5)) + """ + + left: Spec[Axis] = Field( + description="The left-hand Spec to Zip, will appear earlier in axes" + ) + right: Spec[Axis] = Field( + description="The right-hand Spec to Zip, will appear later in axes" + ) + +
+[docs] + def axes(self) -> list[Axis]: # noqa: D102 + return self.left.axes() + self.right.axes()
+ + +
+[docs] + def calculate( # noqa: D102 + self, bounds: bool = True, nested: bool = False + ) -> list[Frames[Axis]]: + frames_left = self.left.calculate(bounds, nested) + frames_right = self.right.calculate(bounds, nested) + assert len(frames_left) >= len( + frames_right + ), f"Zip requires len({self.left}) >= len({self.right})" + + # Pad and expand the right to be the same size as left. Special case, if + # only one Frames object with size 1, expand to the right size + if len(frames_right) == 1 and len(frames_right[0]) == 1: + # Take the 0th element N times to make a repeated Frames object + indices = np.zeros(len(frames_left[-1]), dtype=np.int8) + repeated = frames_right[0].extract(indices) + if isinstance(frames_left[-1], SnakedFrames): + repeated = SnakedFrames.from_frames(repeated) + frames_right = [repeated] + + # Left pad frames_right with Nones so they are the same size + npad = len(frames_left) - len(frames_right) + padded_right: list[Frames[Axis] | None] = [None] * npad + # Mypy doesn't like this because lists are invariant: + # https://github.com/python/mypy/issues/4244 + padded_right += frames_right # type: ignore + + # Work through, zipping them together one by one + frames: list[Frames[Axis]] = [] + for left, right in zip(frames_left, padded_right, strict=False): + if right is None: + combined = left + else: + combined = left.zip(right) + assert isinstance( + combined, Frames + ), f"Padding went wrong {frames_left} {padded_right}" + frames.append(combined) + return frames
+
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class Mask(Spec[Axis]): + """Restrict Spec to only midpoints that fall inside the given Region. + + Typically created with the ``&`` operator. It also pushes down the + ``& | ^ -`` operators to its `Region` to avoid the need for brackets on + combinations of Regions. + + If a Region spans multiple Frames objects, they will be squashed together. + + .. example_spec:: + + from scanspec.regions import Circle + from scanspec.specs import Line + + spec = Line("y", 1, 3, 3) * Line("x", 3, 5, 5) & Circle("x", "y", 4, 2, 1.2) + + See Also: `why-squash-can-change-path` + """ + + spec: Spec[Axis] = Field(description="The Spec containing the source midpoints") + region: Region[Axis] = Field(description="The Region that midpoints will be inside") + check_path_changes: bool = Field( + description="If True path through scan will not be modified by squash", + default=True, + ) + +
+[docs] + def axes(self) -> list[Axis]: # noqa: D102 + return self.spec.axes()
+ + +
+[docs] + def calculate( # noqa: D102 + self, bounds: bool = True, nested: bool = False + ) -> list[Frames[Axis]]: + frames = self.spec.calculate(bounds, nested) + for axis_set in self.region.axis_sets(): + # Find the start and end index of any dimensions containing these axes + matches = [i for i, d in enumerate(frames) if set(d.axes()) & axis_set] + assert matches, f"No Specs match axes {list(axis_set)}" + si, ei = matches[0], matches[-1] + if si != ei: + # The axis_set spans multiple Dimensions, squash them together + # If the spec to be squashed is nested (inside the Mask or outside) + # then check the path changes if requested + check_path_changes = bool(nested or si) and self.check_path_changes + squashed = squash_frames(frames[si : ei + 1], check_path_changes) + frames = frames[:si] + [squashed] + frames[ei + 1 :] + # Generate masks from the midpoints showing what's inside + masked_frames: list[Frames[Axis]] = [] + for f in frames: + indices = get_mask(self.region, f.midpoints).nonzero()[0] + masked_frames.append(f.extract(indices)) + return masked_frames
+ + + # *+ bind more tightly than &|^ so without these overrides we + # would need to add brackets to all combinations of Regions + def __or__(self, other: Region[Axis]) -> Mask[Axis]: + return if_instance_do(other, Region, lambda o: Mask(self.spec, self.region | o)) + + def __and__(self, other: Region[Axis]) -> Mask[Axis]: + return if_instance_do(other, Region, lambda o: Mask(self.spec, self.region & o)) + + def __xor__(self, other: Region[Axis]) -> Mask[Axis]: + return if_instance_do(other, Region, lambda o: Mask(self.spec, self.region ^ o)) + + # This is here for completeness, tends not to be called as - binds + # tighter than & + def __sub__(self, other: Region[Axis]) -> Mask[Axis]: + return if_instance_do(other, Region, lambda o: Mask(self.spec, self.region - o))
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class Snake(Spec[Axis]): + """Run the Spec in reverse on every other iteration when nested. + + Typically created with the ``~`` operator. + + .. example_spec:: + + from scanspec.specs import Line + + spec = Line("y", 1, 3, 3) * ~Line("x", 3, 5, 5) + """ + + spec: Spec[Axis] = Field( + description="The Spec to run in reverse every other iteration" + ) + +
+[docs] + def axes(self) -> list[Axis]: # noqa: D102 + return self.spec.axes()
+ + +
+[docs] + def calculate( # noqa: D102 + self, bounds: bool = True, nested: bool = False + ) -> list[Frames[Axis]]: + return [ + SnakedFrames.from_frames(segment) + for segment in self.spec.calculate(bounds, nested) + ]
+
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class Concat(Spec[Axis]): + """Concatenate two Specs together, running one after the other. + + Each Dimension of left and right must contain the same axes. Typically + formed using `Spec.concat`. + + .. example_spec:: + + from scanspec.specs import Line + + spec = Line("x", 1, 3, 3).concat(Line("x", 4, 5, 5)) + """ + + left: Spec[Axis] = Field( + description="The left-hand Spec to Concat, midpoints will appear earlier" + ) + right: Spec[Axis] = Field( + description="The right-hand Spec to Concat, midpoints will appear later" + ) + + gap: bool = Field( + description="If True, force a gap in the output at the join", default=False + ) + check_path_changes: bool = Field( + description="If True path through scan will not be modified by squash", + default=True, + ) + +
+[docs] + def axes(self) -> list[Axis]: # noqa: D102 + left_axes, right_axes = self.left.axes(), self.right.axes() + # Assuming the axes are the same, the order does not matter, we inherit the + # order from the left-hand side. See also scanspec.core.concat. + assert set(left_axes) == set(right_axes), f"axes {left_axes} != {right_axes}" + return left_axes
+ + +
+[docs] + def calculate( # noqa: D102 + self, bounds: bool = True, nested: bool = False + ) -> list[Frames[Axis]]: + dim_left = squash_frames( + self.left.calculate(bounds, nested), nested and self.check_path_changes + ) + dim_right = squash_frames( + self.right.calculate(bounds, nested), nested and self.check_path_changes + ) + dim = dim_left.concat(dim_right, self.gap) + return [dim]
+
+ + + +
+[docs] +@dataclass(config=StrictConfig) +class Squash(Spec[Axis]): + """Squash a stack of Frames together into a single expanded Frames object. + + See Also: + `why-squash-can-change-path` + + .. example_spec:: + + from scanspec.specs import Line, Squash + + spec = Squash(Line("y", 1, 2, 3) * Line("x", 0, 1, 4)) + + """ + + spec: Spec[Axis] = Field(description="The Spec to squash the dimensions of") + check_path_changes: bool = Field( + description="If True path through scan will not be modified by squash", + default=True, + ) + +
+[docs] + def axes(self) -> list[Axis]: # noqa: D102 + return self.spec.axes()
+ + +
+[docs] + def calculate( # noqa: D102 + self, bounds: bool = True, nested: bool = False + ) -> list[Frames[Axis]]: + dims = self.spec.calculate(bounds, nested) + dim = squash_frames(dims, nested and self.check_path_changes) + return [dim]
+
+ + + +def _dimensions_from_indexes( + func: Callable[[npt.NDArray[np.float64]], dict[Axis, npt.NDArray[np.float64]]], + axes: list[Axis], + num: int, + bounds: bool, +) -> list[Frames[Axis]]: + # Calc num midpoints (fences) from 0.5 .. num - 0.5 + midpoints_calc = func(np.linspace(0.5, num - 0.5, num)) + midpoints = {a: midpoints_calc[a] for a in axes} + if bounds: + # Calc num + 1 bounds (posts) from 0 .. num + bounds_calc = func(np.linspace(0, num, num + 1)) + lower = {a: bounds_calc[a][:-1] for a in axes} + upper = {a: bounds_calc[a][1:] for a in axes} + # Points must have no gap as upper[a][i] == lower[a][i+1] + # because we initialized it to be that way + gap = np.zeros(num, dtype=np.bool_) + dimension = Frames(midpoints, lower, upper, gap) + # But calc the first point as difference between first + # and last + gap[0] = gap_between_frames(dimension, dimension) + else: + # Gap can be calculated in Dimension + dimension = Frames(midpoints) + return [dimension] + + +
+[docs] +@dataclass(config=StrictConfig) +class Line(Spec[Axis]): + """Linearly spaced frames with start and stop as first and last midpoints. + + .. example_spec:: + + from scanspec.specs import Line + + spec = Line("x", 1, 2, 5) + """ + + axis: Axis = Field(description="An identifier for what to move") + start: float = Field(description="Midpoint of the first point of the line") + stop: float = Field(description="Midpoint of the last point of the line") + num: int = Field(ge=1, description="Number of frames to produce") + +
+[docs] + def axes(self) -> list[Axis]: # noqa: D102 + return [self.axis]
+ + + def _line_from_indexes( + self, indexes: npt.NDArray[np.float64] + ) -> dict[Axis, npt.NDArray[np.float64]]: + if self.num == 1: + # Only one point, stop-start gives length of one point + step = self.stop - self.start + else: + # Multiple points, stop-start gives length of num-1 points + step = (self.stop - self.start) / (self.num - 1) + # self.start is the first centre point, but we need the lower bound + # of the first point as this is where the index array starts + first = self.start - step / 2 + return {self.axis: indexes * step + first} + +
+[docs] + def calculate( # noqa: D102 + self, bounds: bool = True, nested: bool = False + ) -> list[Frames[Axis]]: + return _dimensions_from_indexes( + self._line_from_indexes, self.axes(), self.num, bounds + )
+ + +
+[docs] + @classmethod + def bounded( + cls: type[Line[Any]], + axis: OtherAxis = Field(description="An identifier for what to move"), + lower: float = Field(description="Lower bound of the first point of the line"), + upper: float = Field(description="Upper bound of the last point of the line"), + num: int = Field(ge=1, description="Number of frames to produce"), + ) -> Line[OtherAxis]: + """Specify a Line by extreme bounds instead of midpoints. + + .. example_spec:: + + from scanspec.specs import Line + + spec = Line.bounded("x", 1, 2, 5) + """ + half_step = (upper - lower) / num / 2 + start = lower + half_step + if num == 1: + # One point, stop will only be used for step size + stop = upper + half_step + else: + # Many points, stop will be produced + stop = upper - half_step + return cls(axis, start, stop, num)
+
+ + + +""" +Defers wrapping function with validate_call until class is fully instantiated +""" +Line.bounded = validate_call(Line.bounded) # type:ignore + + +
+[docs] +@dataclass(config=StrictConfig) +class Static(Spec[Axis]): + """A static frame, repeated num times, with axis at value. + + Can be used to set axis=value at every point in a scan. + + .. example_spec:: + + from scanspec.specs import Line, Static + + spec = Line("y", 1, 2, 3).zip(Static("x", 3)) + """ + + axis: Axis = Field(description="An identifier for what to move") + value: float = Field(description="The value at each point") + num: int = Field(ge=1, description="Number of frames to produce", default=1) + +
+[docs] + @classmethod + def duration( + cls: type[Static[Any]], + duration: float = Field(description="The duration of each static point"), + num: int = Field(ge=1, description="Number of frames to produce", default=1), + ) -> Static[str]: + """A static spec with no motion, only a duration repeated "num" times. + + .. example_spec:: + + from scanspec.specs import Line, Static + + spec = Line("y", 1, 2, 3).zip(Static.duration(0.1)) + """ + return Static(DURATION, duration, num)
+ + +
+[docs] + def axes(self) -> list[Axis]: # noqa: D102 + return [self.axis]
+ + + def _repeats_from_indexes( + self, indexes: npt.NDArray[np.float64] + ) -> dict[Axis, npt.NDArray[np.float64]]: + return {self.axis: np.full(len(indexes), self.value)} + +
+[docs] + def calculate( # noqa: D102 + self, bounds: bool = True, nested: bool = False + ) -> list[Frames[Axis]]: + return _dimensions_from_indexes( + self._repeats_from_indexes, self.axes(), self.num, bounds + )
+
+ + + +Static.duration = validate_call(Static.duration) # type:ignore + + +
+[docs] +@dataclass(config=StrictConfig) +class Spiral(Spec[Axis]): + """Archimedean spiral of "x_axis" and "y_axis". + + Starts at centre point ("x_start", "y_start") with angle "rotate". Produces + "num" points in a spiral spanning width of "x_range" and height of "y_range" + + .. example_spec:: + + from scanspec.specs import Spiral + + spec = Spiral("x", "y", 1, 5, 10, 50, 30) + """ + + # TODO: Make use of typing.Annotated upon fix of + # https://github.com/pydantic/pydantic/issues/3496 + x_axis: Axis = Field(description="An identifier for what to move for x") + y_axis: Axis = Field(description="An identifier for what to move for y") + x_start: float = Field(description="x centre of the spiral") + y_start: float = Field(description="y centre of the spiral") + x_range: float = Field(description="x width of the spiral") + y_range: float = Field(description="y width of the spiral") + num: int = Field(ge=1, description="Number of frames to produce") + rotate: float = Field( + description="How much to rotate the angle of the spiral", default=0.0 + ) + +
+[docs] + def axes(self) -> list[Axis]: # noqa: D102 + # TODO: reversed from __init__ args, a good idea? + return [self.y_axis, self.x_axis]
+ + + def _spiral_from_indexes( + self, indexes: npt.NDArray[np.float64] + ) -> dict[Axis, npt.NDArray[np.float64]]: + # simplest spiral equation: r = phi + # we want point spacing across area to be the same as between rings + # so: sqrt(area / num) = ring_spacing + # so: sqrt(pi * phi^2 / num) = 2 * pi + # so: phi = sqrt(4 * pi * num) + phi = np.sqrt(4 * np.pi * indexes) + # indexes are 0..num inclusive, and diameter is 2x biggest phi + diameter = 2 * np.sqrt(4 * np.pi * self.num) + # scale so that the spiral is strictly smaller than the range + x_scale = self.x_range / diameter + y_scale = self.y_range / diameter + return { + self.y_axis: self.y_start + y_scale * phi * np.cos(phi + self.rotate), + self.x_axis: self.x_start + x_scale * phi * np.sin(phi + self.rotate), + } + +
+[docs] + def calculate( # noqa: D102 + self, bounds: bool = True, nested: bool = False + ) -> list[Frames[Axis]]: + return _dimensions_from_indexes( + self._spiral_from_indexes, self.axes(), self.num, bounds + )
+ + +
+[docs] + @classmethod + def spaced( + cls: type[Spiral[Any]], + x_axis: OtherAxis = Field(description="An identifier for what to move for x"), + y_axis: OtherAxis = Field(description="An identifier for what to move for y"), + x_start: float = Field(description="x centre of the spiral"), + y_start: float = Field(description="y centre of the spiral"), + radius: float = Field(description="radius of the spiral"), + dr: float = Field(description="difference between each ring"), + rotate: float = Field( + description="How much to rotate the angle of the spiral", default=0.0 + ), + ) -> Spiral[OtherAxis]: + """Specify a Spiral equally spaced in "x_axis" and "y_axis". + + .. example_spec:: + + from scanspec.specs import Spiral + + spec = Spiral.spaced("x", "y", 0, 0, 10, 3) + """ + # phi = sqrt(4 * pi * num) + # and: n_rings = phi / (2 * pi) + # so: n_rings * 2 * pi = sqrt(4 * pi * num) + # so: num = n_rings^2 * pi + n_rings = radius / dr + num = int(n_rings**2 * np.pi) + return cls( + x_axis, + y_axis, + x_start, + y_start, + radius * 2, + radius * 2, + num, + rotate, + )
+
+ + + +Spiral.spaced = validate_call(Spiral.spaced) # type:ignore + + +
+[docs] +def fly(spec: Spec[Axis], duration: float) -> Spec[Axis | str]: + """Flyscan, zipping with fixed duration for every frame. + + Args: + spec: The source `Spec` to continuously move + duration: How long to spend at each frame in the spec + + .. example_spec:: + + from scanspec.specs import Line, fly + + spec = fly(Line("x", 1, 2, 3), 0.1) + + """ + return spec.zip(Static.duration(duration))
+ + + +
+[docs] +def step(spec: Spec[Axis], duration: float, num: int = 1) -> Spec[Axis | str]: + """Step scan, with num frames of given duration at each frame in the spec. + + Args: + spec: The source `Spec` with midpoints to move to and stop + duration: The duration of each scan frame + num: Number of frames to produce with given duration at each of frame + in the spec + + .. example_spec:: + + from scanspec.specs import Line, step + + spec = step(Line("x", 1, 2, 3), 0.1) + + """ + return spec * Static.duration(duration, num)
+ + + +def get_constant_duration(frames: list[Frames[Any]]) -> float | None: + """Returns the duration of a number of ScanSpec frames, if known and consistent. + + Args: + frames (List[Frames]): A number of Frame objects + + Returns: + duration (float): if all frames have a consistent duration + None: otherwise + + """ + duration_frame = [ + f for f in frames if DURATION in f.axes() and len(f.midpoints[DURATION]) + ] + if len(duration_frame) != 1 or len(duration_frame[0]) < 1: + # Either no frame has DURATION axis, + # the frame with a DURATION axis has 0 points, + # or multiple frames have DURATION axis + return None + durations = duration_frame[0].midpoints[DURATION] + first_duration = durations[0] + if np.any(durations != first_duration): + # Not all durations are the same + return None + return first_duration +
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/0.7.5/_sources/_api.rst.txt b/0.7.5/_sources/_api.rst.txt new file mode 100644 index 00000000..b4b0a6c9 --- /dev/null +++ b/0.7.5/_sources/_api.rst.txt @@ -0,0 +1,16 @@ +:orphan: + +.. + This page is not included in the TOC tree, but must exist so that the + autosummary pages are generated for scanspec and all its + subpackages + +API +=== + +.. autosummary:: + :toctree: _api + :template: custom-module-template.rst + :recursive: + + scanspec diff --git a/0.7.5/_sources/_api/scanspec.core.rst.txt b/0.7.5/_sources/_api/scanspec.core.rst.txt new file mode 100644 index 00000000..86e36d0c --- /dev/null +++ b/0.7.5/_sources/_api/scanspec.core.rst.txt @@ -0,0 +1,43 @@ +``scanspec.core`` +================= + + + + + + + + + + + + + +.. automodule:: scanspec.core + :members: + + + + + + + + .. rubric:: Members + + .. autosummary:: + :nosignatures: + + Axis + OtherAxis + if_instance_do + AxesPoints + Frames + SnakedFrames + gap_between_frames + squash_frames + Path + Midpoints + discriminated_union_of_subclasses + StrictConfig + + \ No newline at end of file diff --git a/0.7.5/_sources/_api/scanspec.plot.rst.txt b/0.7.5/_sources/_api/scanspec.plot.rst.txt new file mode 100644 index 00000000..b4731281 --- /dev/null +++ b/0.7.5/_sources/_api/scanspec.plot.rst.txt @@ -0,0 +1,21 @@ +``scanspec.plot`` +================= + + +.. automodule:: scanspec.plot + :members: + + + + + + + + .. rubric:: Members + + .. autosummary:: + :nosignatures: + + plot_spec + + \ No newline at end of file diff --git a/0.7.5/_sources/_api/scanspec.regions.rst.txt b/0.7.5/_sources/_api/scanspec.regions.rst.txt new file mode 100644 index 00000000..833ab212 --- /dev/null +++ b/0.7.5/_sources/_api/scanspec.regions.rst.txt @@ -0,0 +1,25 @@ +``scanspec.regions`` +==================== + + + + +.. automodule:: scanspec.regions + :members: + + + + + + + + .. rubric:: Members + + .. autosummary:: + :nosignatures: + + Region + get_mask + find_regions + + \ No newline at end of file diff --git a/0.7.5/_sources/_api/scanspec.rst.txt b/0.7.5/_sources/_api/scanspec.rst.txt new file mode 100644 index 00000000..a17df606 --- /dev/null +++ b/0.7.5/_sources/_api/scanspec.rst.txt @@ -0,0 +1,25 @@ +``scanspec`` +============ + +.. automodule:: scanspec + :members: + + + + .. rubric:: Submodules + + .. autosummary:: + :toctree: + :template: custom-module-template.rst + :recursive: + + core + specs + regions + plot + + + + + + \ No newline at end of file diff --git a/0.7.5/_sources/_api/scanspec.specs.rst.txt b/0.7.5/_sources/_api/scanspec.specs.rst.txt new file mode 100644 index 00000000..18d65b9b --- /dev/null +++ b/0.7.5/_sources/_api/scanspec.specs.rst.txt @@ -0,0 +1,27 @@ +``scanspec.specs`` +================== + + + + + +.. automodule:: scanspec.specs + :members: + + + + + + + + .. rubric:: Members + + .. autosummary:: + :nosignatures: + + DURATION + Spec + fly + step + + \ No newline at end of file diff --git a/0.7.5/_sources/explanations.md.txt b/0.7.5/_sources/explanations.md.txt new file mode 100644 index 00000000..73ab289b --- /dev/null +++ b/0.7.5/_sources/explanations.md.txt @@ -0,0 +1,10 @@ +# Explanations + +Explanations of how it works and why it works that way. + +```{toctree} +:maxdepth: 1 +:glob: + +explanations/* +``` diff --git a/0.7.5/_sources/explanations/decisions.md.txt b/0.7.5/_sources/explanations/decisions.md.txt new file mode 100644 index 00000000..0533b98d --- /dev/null +++ b/0.7.5/_sources/explanations/decisions.md.txt @@ -0,0 +1,12 @@ +# Architectural Decision Records + +Architectural decisions are made throughout a project's lifetime. As a way of keeping track of these decisions, we record these decisions in Architecture Decision Records (ADRs) listed below. + +```{toctree} +:glob: true +:maxdepth: 1 + +decisions/* +``` + +For more information on ADRs see this [blog by Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions). diff --git a/0.7.5/_sources/explanations/decisions/0001-record-architecture-decisions.md.txt b/0.7.5/_sources/explanations/decisions/0001-record-architecture-decisions.md.txt new file mode 100644 index 00000000..44d234ef --- /dev/null +++ b/0.7.5/_sources/explanations/decisions/0001-record-architecture-decisions.md.txt @@ -0,0 +1,18 @@ +# 1. Record architecture decisions + +## Status + +Accepted + +## Context + +We need to record the architectural decisions made on this project. + +## Decision + +We will use Architecture Decision Records, as [described by Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions). + +## Consequences + +See Michael Nygard's article, linked above. To create new ADRs we will copy and +paste from existing ones. diff --git a/0.7.5/_sources/explanations/decisions/0002-switched-to-python-copier-template.md.txt b/0.7.5/_sources/explanations/decisions/0002-switched-to-python-copier-template.md.txt new file mode 100644 index 00000000..66fe5d8b --- /dev/null +++ b/0.7.5/_sources/explanations/decisions/0002-switched-to-python-copier-template.md.txt @@ -0,0 +1,28 @@ +# 2. Adopt python-copier-template for project structure + +## Status + +Accepted + +## Context + +We should use the following [python-copier-template](https://github.com/DiamondLightSource/python-copier-template). +The template will ensure consistency in developer +environments and package management. + +## Decision + +We have switched to using the template. + +## Consequences + +This module will use a fixed set of tools as developed in `python-copier-template` +and can pull from this template to update the packaging to the latest techniques. + +As such, the developer environment may have changed, the following could be +different: + +- linting +- formatting +- pip venv setup +- CI/CD diff --git a/0.7.5/_sources/explanations/technical-terms.rst.txt b/0.7.5/_sources/explanations/technical-terms.rst.txt new file mode 100644 index 00000000..21c7d1fa --- /dev/null +++ b/0.7.5/_sources/explanations/technical-terms.rst.txt @@ -0,0 +1,59 @@ +.. _technical-terms: + +Technical Terms +=============== + +This page draws together some of the technical terms used throughout the +documentation. Consider a 1D line scan: + +.. image:: ../images/definitions.png + +.. _axis_: + +Axis +---- + +A fixed reference that can be scanned, i.e. a motor or the `frame_` `DURATION`. +In the diagram above, the Axis is ``x``. `Spec.axes` will return the Axes that +should be scanned for a given Spec. + +.. _point_: + +Point +----- + +A single or multidimensional location in scan space. In the diagram above, each +`frame_` is made up of lower, midpoint and upper Points. `Midpoints` are +available as an interator from `Spec.midpoints`. Arrays of these are available +as `Frames.lower`, `Frames.midpoints` and `Frames.upper`. + +.. _frame_: + +Frame +----- + +A vector of three `Points ` in scan space: lower, midpoint, upper. They +describe the trajectory that should be taken while a detector is active while +fly scanning. In the diagram above each Frame is denoted by a different coloured +section. + +.. _stack_: + +Stack of Frames +--------------- + +A repeatable, possibly snaking, series of `Frames` along a number of `Axes +`. In the diagram above, the whole Line produces a single `Frames` +object, while a grid scan would be a stack of two `Frames` objects. A stack of +`Frames` objects are produced by `Spec.calculate`. + +.. seealso:: `./why-stack-frames` + +.. _path_: + +Path +---- + +A consumable route through a _stack_. If the Line in the above diagram was +stacked within another line of length 5, then the Path would contain 15 `Frames +`. A `Path` is created from a `list` of `Frames` objects. diff --git a/0.7.5/_sources/explanations/why-squash-can-change-path.rst.txt b/0.7.5/_sources/explanations/why-squash-can-change-path.rst.txt new file mode 100644 index 00000000..61125272 --- /dev/null +++ b/0.7.5/_sources/explanations/why-squash-can-change-path.rst.txt @@ -0,0 +1,91 @@ +.. _why-squash-can-change-path: + +Why Squash (and Mask) can change the Path +========================================= + +A Spec creates a stack of `Frames`, some of which can be snaking. When snaking, +every other run of that Frames object will run in reverse. `Squash` and `Mask` +will merge Frames objects together. This may change the Path compared with the +unsquashed version if the squashed Frames objects are nested within a slower +Frames object, and so run more than once. This page lists the times where this +is the case. + +.. note:: + + The cases illustrated below will only be produced if + ``check_path_changes=False`` is passed to `Squash` or `Mask`, otherwise they + will fail with `ValueError` + +Squash unsnaked axis into a snaked Frames +----------------------------------------- + +Squashing Frames objects together will take the snake setting of the slowest +moving Frames object in the squash. If this squashed Frames object is nested +within another, on the second run the originally unsnaked axis will run in +reverse. This would make a motor that the user had demanded to always run in one +direction run in reverse, which could make the scan invalid. + +For example, consider a non-snaking x within a snaking y within z: + +.. plot:: + + from scanspec.specs import Line + from scanspec.plot import plot_spec + + spec = Line("z", 0, 1, 3) * ~Line("y", 0, 1, 3) * Line("x", 0, 1, 3) + plot_spec(spec) + +If we squash the x and y Frames objects together then x will run in reverse on +the second run: + +.. plot:: + + from scanspec.specs import Line, Squash + from scanspec.plot import plot_spec + + spec = Line("z", 0, 1, 3) * Squash( + ~Line("y", 0, 1, 3) * Line("x", 0, 1, 3), check_path_changes=False + ) + plot_spec(spec) + +Squash snaked axis into unsnaked odd length axis +------------------------------------------------ + +A snaked axis must repeat an even number of times within a squashed Frames +object in order to be able to nest this Frames object within another and keep +the Path of the snaked axis. If this is not the case, the snaked axis will +"jump" after each iteration of the squashed Frames object. + +For example, consider a snaking x within an odd non-snaking y within z: + +.. plot:: + + from scanspec.specs import Line + from scanspec.plot import plot_spec + + spec = Line("z", 0, 1, 3) * Line("y", 0, 1, 3) * ~Line("x", 0, 1, 3) + plot_spec(spec) + +If we squash the x and y Frames objects then x will jump between the first and +second runs: + +.. plot:: + + from scanspec.specs import Line, Squash + from scanspec.plot import plot_spec + + spec = Line("z", 0, 1, 3) * Squash( + Line("y", 0, 1, 3) * ~Line("x", 0, 1, 3), check_path_changes=False + ) + plot_spec(spec) + +Why this matters +---------------- + +Apart from these two cases, squashing can be considered Path invariant. This +means that the detector could write data in a stack, then the data could be +reshaped with a VDS into the original dimensionality. Unfortunately a negative +stride is not supported in VDS, so the strategy is to squash snaked Frames +objects into the Frames object above. If this changes the Path through a scan +then this needs to be flagged or explicitly allowed in the Spec, otherwise the +results for the user could be potentially surprising. diff --git a/0.7.5/_sources/explanations/why-stack-frames.rst.txt b/0.7.5/_sources/explanations/why-stack-frames.rst.txt new file mode 100644 index 00000000..815c93b9 --- /dev/null +++ b/0.7.5/_sources/explanations/why-stack-frames.rst.txt @@ -0,0 +1,65 @@ +Why create a stack of Frames? +============================= + +If a `Spec` tells you the parameters of a scan, `Frames` gives you the `Points +` that will let you actually execute the scan. A stack of Frames is +interpreted as nested from slowest moving to fastest moving, so each faster +Frames object will iterate once per position of the slower Frames object. When +fly-scanning the axis will traverse lower-midpoint-upper on the fastest Frames +object for each point in the scan. + +An Example +---------- + +>>> from scanspec.specs import Line +>>> spec = Line("y", 4, 5, 6) * Line("x", 1, 2, 3) +>>> stack = spec.calculate() +>>> len(stack) +2 +>>> len(stack[0]) +6 +>>> len(stack[1]) +3 +>>> stack[0].midpoints +{'y': array([4. , 4.2, 4.4, 4.6, 4.8, 5. ])} +>>> stack[1].midpoints +{'x': array([1. , 1.5, 2. ])} + +So the `Product` of two `Lines ` creates a stack of 2 Frames objects, the first +having the same size as the outer line, and the second having the same size as +the inner. Executing the scan will iterate the inner Frames object 6 times, once for +each point in the outer Frames object, 18 points in all. + +Why not squash them into a flat sequence? +----------------------------------------- + +A stack of Frames objects are created to give the most compact representation of +the scan. Imagine a 100x2000x2000 point scan, which creates a list of 3 Frames +objects. Considering just the midpoint arrays, they would take 100 + 2000 + 2000 +float64 = 32.8kB RAM in our list form. If we squashed the list into a single +Frames object it would take 100 * 2000 * 2000 float64 = 3.2GB of RAM. The scan +itself is likely to be executed over a long period of time, so it makes sense to +save on the memory and calculate the squashed points as they are needed. + +What about Regions? +------------------- + +Regions will stop the regularity of the nested Frames objects, so will cause +them to be squashed into a single Frames object. Taking our example above, if we +`Mask` the grid with a `Circle`, then the `Line` in ``x`` won't have 3 points in +each iteration, the number of points is dependent on ``y``. This means that a +`Mask` will squash any Specs together referred to by its Regions. + +How does this stack relate to HDF5 Dimensions? +---------------------------------------------- + +A Spec by itself does not specify how the scan points should be written to disk. +The simplest strategy is to simply write a stack of images, along with the +setpoint positions specified in the Frames objects, and let the reader of the data +pick out the required frames from the positions. However, the stack of Frames objects +contains all the information required to reshape a sequence of HDF5 frames into the +dimensionality of the scan using a VDS. This holds until we turn snake on, at +which point it destroys the performance of the VDS. For this reason, it is +advisable to `Squash` any snaking Specs with the first non-snaking axis above it +so that the HDF Dimension will not be snaking. See `./why-squash-can-change-path` for +some details on this. diff --git a/0.7.5/_sources/genindex.md.txt b/0.7.5/_sources/genindex.md.txt new file mode 100644 index 00000000..73f1191b --- /dev/null +++ b/0.7.5/_sources/genindex.md.txt @@ -0,0 +1,3 @@ +# Index + + diff --git a/0.7.5/_sources/how-to.md.txt b/0.7.5/_sources/how-to.md.txt new file mode 100644 index 00000000..6b161417 --- /dev/null +++ b/0.7.5/_sources/how-to.md.txt @@ -0,0 +1,10 @@ +# How-to Guides + +Practical step-by-step guides for the more experienced user. + +```{toctree} +:maxdepth: 1 +:glob: + +how-to/* +``` diff --git a/0.7.5/_sources/how-to/contribute.md.txt b/0.7.5/_sources/how-to/contribute.md.txt new file mode 100644 index 00000000..6e419797 --- /dev/null +++ b/0.7.5/_sources/how-to/contribute.md.txt @@ -0,0 +1,2 @@ +```{include} ../../.github/CONTRIBUTING.md +``` diff --git a/0.7.5/_sources/how-to/iterate-a-spec.rst.txt b/0.7.5/_sources/how-to/iterate-a-spec.rst.txt new file mode 100644 index 00000000..9d9333a2 --- /dev/null +++ b/0.7.5/_sources/how-to/iterate-a-spec.rst.txt @@ -0,0 +1,110 @@ +.. _iterate-a-spec: + +How to Iterate a Spec +===================== + +A Spec is only the specification for a scan. To execute the scan we need the +`Frames `. We can do this in a few ways. + +If you only need the midpoints +------------------------------ + +If you are conducting a step scan, you only need the midpoints of each scan +frame. You can get these by using the `Spec.midpoints()` method to produce a +`Midpoints` iterator of scan `Points `: + +>>> from scanspec.specs import Line +>>> spec = Line("x", 1, 2, 3) +>>> for d in spec.midpoints(): +... print(d) +... +{'x': np.float64(1.0)} +{'x': np.float64(1.5)} +{'x': np.float64(2.0)} + +This is simple, but not particularly performant, as the numpy arrays of +points are unpacked point by point into point dictionaries + +If you need to do a fly scan +---------------------------- + +If you are conducting a fly scan then you need the frames that the motor moves +through. You can get that from the lower and upper bounds of each point. If the +scan is small enough to fit in memory on the machine you can use the `Spec.frames()` +method to produce a single `Frames` object containing the entire scan: + +>>> segment = spec.frames() +>>> len(segment) +3 +>>> segment.lower +{'x': array([0.75, 1.25, 1.75])} +>>> segment.midpoints +{'x': array([1. , 1.5, 2. ])} +>>> segment.upper +{'x': array([1.25, 1.75, 2.25])} + + +If you want the most performant option +-------------------------------------- + +A `Path` instance is a one-shot consumable view of the stack of `Frames` +objects created by `Spec.calculate()`. Once you have consumed it you +should create a new instance of it. For performance reasons, you can keep the +intermediate `Frames` stack and create as many `Path` wrappers to them +as you need. You can also give a maximum size to `Path.consume()` + +>>> from scanspec.core import Path +>>> stack = spec.calculate() +>>> path = Path(stack) +>>> len(path) +3 +>>> chunk = path.consume(2) +>>> len(chunk) +2 +>>> len(path) +1 +>>> chunk = path.consume(2) +>>> len(chunk) +1 +>>> len(path) +0 + +You can also use this method to only run a subset of the scan: + +>>> path = Path(stack, start=1, num=1) +>>> len(path) +1 +>>> chunk = path.consume() +>>> len(chunk) +1 +>>> len(path) +0 + +.. seealso:: `../explanations/why-stack-frames` + +If you need to know whether there is a gap between points +--------------------------------------------------------- + +You may need to know where there is a gap between points, so that you can do +something in the turnaround. For example, if we take the x axis of a grid scan, +you can see it snakes back and forth: + +>>> from scanspec.specs import Line, fly +>>> grid = fly(Line("y", 0, 1, 2) * ~Line("x", 1, 2, 3), 0.1) +>>> chunk = grid.frames() +>>> chunk.midpoints["x"] +array([1. , 1.5, 2. , 2. , 1.5, 1. ]) + +You can check where the gaps are by using the `Frames.gap` attribute: + +>>> chunk.gap +array([ True, False, False, True, False, False]) + +This says whether there is a gap between this frame and the previous frame. In +the example we see 2 gaps: + +- On the very first frame (as there is a gap between the last and first frames) +- Between the 2 frames with midpoint of 2.0 + +You could use this information to work out when to insert turnaround between +rows for the motors diff --git a/0.7.5/_sources/how-to/run-container.md.txt b/0.7.5/_sources/how-to/run-container.md.txt new file mode 100644 index 00000000..8737adee --- /dev/null +++ b/0.7.5/_sources/how-to/run-container.md.txt @@ -0,0 +1,14 @@ +# Run in a container + +Pre-built containers with scanspec and its dependencies already +installed are available on [Github Container Registry](https://ghcr.io/bluesky/scanspec). + +## Starting the container + +To pull the container from github container registry and run: + +``` +$ docker run ghcr.io/bluesky/scanspec:latest --version +``` + +To get a released version, use a numbered release instead of `latest`. diff --git a/0.7.5/_sources/how-to/serialize-a-spec.rst.txt b/0.7.5/_sources/how-to/serialize-a-spec.rst.txt new file mode 100644 index 00000000..b0265779 --- /dev/null +++ b/0.7.5/_sources/how-to/serialize-a-spec.rst.txt @@ -0,0 +1,31 @@ +.. _serialize-a-spec: + +How to Serialize and Deserialize a Spec +======================================= + +Lets start with an example `Spec`. + +>>> from scanspec.specs import Line, Spec +>>> spec = Line("y", 4, 5, 6) * Line("x", 1, 2, 3) + +This Spec has a `repr` that shows its parameters it was instantiated with: + +>>> spec +Product(outer=Line(axis='y', start=4.0, stop=5.0, num=6), inner=Line(axis='x', start=1.0, stop=2.0, num=3)) + + +How to Serialize +---------------- + +We can recursively serialize it to a dictionary: + +>>> spec.serialize() +{'outer': {'axis': 'y', 'start': 4.0, 'stop': 5.0, 'num': 6, 'type': 'Line'}, 'inner': {'axis': 'x', 'start': 1.0, 'stop': 2.0, 'num': 3, 'type': 'Line'}, 'type': 'Product'} + +How to Deserialize +------------------ + +We can turn this back into a spec using `Spec.deserialize`: + +>>> Spec.deserialize({'outer': {'axis': 'y', 'start': 4.0, 'stop': 5.0, 'num': 6, 'type': 'Line'}, 'inner': {'axis': 'x', 'start': 1.0, 'stop': 2.0, 'num': 3, 'type': 'Line'}, 'type': 'Product'}) +Product(outer=Line(axis='y', start=4.0, stop=5.0, num=6), inner=Line(axis='x', start=1.0, stop=2.0, num=3)) diff --git a/0.7.5/_sources/index.md.txt b/0.7.5/_sources/index.md.txt new file mode 100644 index 00000000..a6f58e33 --- /dev/null +++ b/0.7.5/_sources/index.md.txt @@ -0,0 +1,58 @@ +--- +html_theme.sidebar_secondary.remove: true +--- + +```{include} ../README.md +:end-before: + +::::{grid} 2 +:gutter: 4 + +:::{grid-item-card} {material-regular}`directions_walk;2em` +```{toctree} +:maxdepth: 2 +tutorials +``` ++++ +Tutorials for installation and typical usage. New users start here. +::: + +:::{grid-item-card} {material-regular}`directions;2em` +```{toctree} +:maxdepth: 2 +how-to +``` ++++ +Practical step-by-step guides for the more experienced user. +::: + +:::{grid-item-card} {material-regular}`info;2em` +```{toctree} +:maxdepth: 2 +explanations +``` ++++ +Explanations of how it works and why it works that way. +::: + +:::{grid-item-card} {material-regular}`menu_book;2em` +```{toctree} +:maxdepth: 2 +reference +``` ++++ +Technical reference material including APIs and release notes. +::: + +:::: diff --git a/0.7.5/_sources/reference.md.txt b/0.7.5/_sources/reference.md.txt new file mode 100644 index 00000000..e2ef404a --- /dev/null +++ b/0.7.5/_sources/reference.md.txt @@ -0,0 +1,13 @@ +# Reference + +Technical reference material including APIs and release notes. + +```{toctree} +:maxdepth: 1 +:glob: + +API <_api/scanspec> +reference/* +genindex +Release Notes +``` diff --git a/0.7.5/_sources/reference/rest_api.md.txt b/0.7.5/_sources/reference/rest_api.md.txt new file mode 100644 index 00000000..f54aabcb --- /dev/null +++ b/0.7.5/_sources/reference/rest_api.md.txt @@ -0,0 +1,7 @@ +# REST API + +The endpoints of the REST service are documented below. + +```{eval-rst} +.. openapi:: ../../schema.json +``` diff --git a/0.7.5/_sources/tutorials.md.txt b/0.7.5/_sources/tutorials.md.txt new file mode 100644 index 00000000..b88db528 --- /dev/null +++ b/0.7.5/_sources/tutorials.md.txt @@ -0,0 +1,12 @@ +# Tutorials + +Tutorials for installation and typical usage. New users start here. + +```{toctree} +:maxdepth: 1 +:glob: + +tutorials/installation +tutorials/creating-a-spec +tutorials/rest-service +``` diff --git a/0.7.5/_sources/tutorials/creating-a-spec.rst.txt b/0.7.5/_sources/tutorials/creating-a-spec.rst.txt new file mode 100644 index 00000000..0c73c35b --- /dev/null +++ b/0.7.5/_sources/tutorials/creating-a-spec.rst.txt @@ -0,0 +1,119 @@ +Creating a Scan Spec +==================== + +This tutorial shows how to create Scan Specs of increasing complexity, plotting +the results. + +Line +---- + +We'll start with a simple one, a `Line`. If you enter the following code into an +interactive Python terminal, it should plot a graph of a 1D line: + +.. example_spec:: + + from scanspec.specs import Line + + spec = Line("x", 1, 2, 5) + +This will create a Spec with 5 frames, the first centred on 1, the last centred +on 2. The black dots mark the midpoints on the Path. The coloured lines mark the +motion from the lower to upper bound of each frame on the Path. The grey +arrowhead marks the start of the scan, and the cross marks the end. + + +Plotting from the commandline +----------------------------- + +To quickly plot Scan Specs you can use the commandline client. The input is +evaluated with variables ``a`` to ``z`` defined and the output plotted. + +For example, for the Line example above you would type:: + + $ scanspec plot 'Line(x, 1, 2, 5)' + + +Line with 2 axes +---------------- + +If we want to plot a Line in two axes, we can do this with `Zip`, or `Spec.zip`: + +.. example_spec:: + + from scanspec.specs import Line + + spec = Line("y", 3, 4, 5).zip(Line("x", 1, 2, 5)) + + +Grid +---- + +We can make a grid by creating the `Product` of 2 Lines with the ``*`` operator: + +.. example_spec:: + + from scanspec.specs import Line + + spec = Line("y", 3, 4, 3) * Line("x", 1, 2, 5) + +The plot shows grey arrowed lines marking the turnarounds. These are added by +the plotting function as an indication of what a scanning program might do +between two disjoint frames, it is not a guarantee of the path that will be +taken. + +.. _snaked-grid: + +Snaked Grid +----------- + +We can `Snake` a Spec with the ``~`` operator. If we apply this to the inner +Spec of our grid we get: + +.. example_spec:: + + from scanspec.specs import Line + + spec = Line("y", 3, 4, 3) * ~Line("x", 1, 2, 5) + + +Masking with Regions +-------------------- + +We can apply a `Mask` to only include frames where the midpoints are within a +given `Region` using the ``&`` operator: + +.. example_spec:: + + from scanspec.specs import Line + from scanspec.regions import Circle + + spec = Line("y", 3, 4, 3) * ~Line("x", 1, 2, 5) & Circle("x", "y", 1.5, 3.5, 0.6) + + +Masking with Multiple Regions +----------------------------- + +We can apply set-like operators to Masked Specs: + +- ``|``: `UnionOf` two Regions +- ``&``: `IntersectionOf` two Regions +- ``-``: `DifferenceOf` two Regions +- ``^``: `SymmetricDifferenceOf` two Regions + +For example: + +.. example_spec:: + + from scanspec.specs import Line + from scanspec.regions import Circle + + spec = Line("y", 3, 4, 3) * ~Line("x", 1, 2, 5) & Circle("x", "y", 1.5, 3.5, 0.6) - Circle("x", "y", 1.4, 3.5, 0.2) + + +Conclusion +---------- + +This tutorial has demonstrated some Specs and combinations of them. From here +you may like to read `iterate-a-spec` to see how a scanning system could use +these Specs and `serialize-a-spec` to see how you might send one to such a +scanning system. diff --git a/0.7.5/_sources/tutorials/installation.md.txt b/0.7.5/_sources/tutorials/installation.md.txt new file mode 100644 index 00000000..b9c85bd1 --- /dev/null +++ b/0.7.5/_sources/tutorials/installation.md.txt @@ -0,0 +1,55 @@ +# Installation + +## Check your version of python + +You will need python 3.10 or later. You can check your version of python by +typing into a terminal: + +``` +$ python3 --version +``` + +## Create a virtual environment + +It is recommended that you install into a “virtual environment” so this +installation will not interfere with any existing Python software: + +``` +$ python3 -m venv /path/to/venv +$ source /path/to/venv/bin/activate +``` + +## Installing the library + +You can now use `pip` to install the library and its dependencies: + +``` +$ python3 -m pip install scanspec +``` + +If you require a feature that is not currently released you can also install +from github: + +``` +$ python3 -m pip install git+https://github.com/bluesky/scanspec.git +``` + +If you need to do any plotting (recommended), you should install the `plotting` extra: + +``` +python3 -m pip install scanspec[plotting] +``` + +If you need to run scanspec as a REST service for generating points, you should +install the `service` extra: + +``` +python3 -m pip install scanspec[service] +``` + +The library should now be installed and the commandline interface on your path. +You can check the version that has been installed by typing: + +``` +$ scanspec --version +``` diff --git a/0.7.5/_sources/tutorials/rest-service.rst.txt b/0.7.5/_sources/tutorials/rest-service.rst.txt new file mode 100644 index 00000000..772b90a8 --- /dev/null +++ b/0.7.5/_sources/tutorials/rest-service.rst.txt @@ -0,0 +1,125 @@ +.. _rest-service: + +Running a REST service for generating points +============================================ + +The `creating-a-spec` tutorial shows how you would use the commandline client to +plot a `Spec`. This maps nicely to using scanspec in a commandline utility, but +not if you want to expose those points to a web GUI. To do this we will bring up +a RESTful service, compatible with OpenAPI_, that allows a web GUI to request the +points it would like to plot. + +Running the server +------------------ + +In a terminal, run:: + + $ scanspec service --cors + ======== Running on http://localhost:8080 ======== + (Press CTRL+C to quit) + +You can now open a browser to http://localhost:8080/docs and see a `Swagger UI`_ editor +which will allow you to send requests to the server using, for example, the ``curl`` command. + +.. seealso:: `../reference/rest_api` + +.. _OpenAPI: https://www.openapis.org/ +.. _`Swagger UI`: https://swagger.io/tools/swagger-ui/ + + +Validating a Spec +----------------- + +You can ensure a spec is valid by passing it to the ``/valid`` endpoint. + +.. code:: shell + + curl -X 'POST' \ + 'http://localhost:8080/valid' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "outer": { + "axis": "y", + "start": 0, + "stop": 10, + "num": 3, + "type": "Line" + }, + "inner": { + "axis": "x", + "start": 0, + "stop": 10, + "type": "Line" + }, + "type": "Product" + }' + +Should return a 422 error code because the inner axis is missing a parameter. + + +Generating Midpoints +-------------------- + +There are several endpoints to inspect generated points. The most useful is ``/midpoints``, +which gives the middle coordinate of each scan point, organised by axis name. + +.. code:: shell + + curl -X 'POST' \ + 'http://localhost:8080/midpoints' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "spec": { + "outer": { + "axis": "y", + "start": 0, + "stop": 10, + "num": 3, + "type": "Line" + }, + "inner": { + "axis": "x", + "start": 0, + "stop": 10, + "num": 4, + "type": "Line" + }, + "type": "Product" + }, + "max_frames": 1024, + "format": "FLOAT_LIST" + }' + +Should output: + +.. code:: JSON + + {"format": "FLOAT_LIST", + "midpoints": {"x": [0.0, + 3.333333333333333, + 6.666666666666667, + 10.000000000000002, + 0.0, + 3.333333333333333, + 6.666666666666667, + 10.000000000000002, + 0.0, + 3.333333333333333, + 6.666666666666667, + 10.000000000000002], + "y": [0.0, + 0.0, + 0.0, + 0.0, + 5.0, + 5.0, + 5.0, + 5.0, + 10.0, + 10.0, + 10.0, + 10.0]}, + "returned_frames": 1024, + "total_frames": 12} diff --git a/0.7.5/_sphinx_design_static/design-tabs.js b/0.7.5/_sphinx_design_static/design-tabs.js new file mode 100644 index 00000000..b25bd6a4 --- /dev/null +++ b/0.7.5/_sphinx_design_static/design-tabs.js @@ -0,0 +1,101 @@ +// @ts-check + +// Extra JS capability for selected tabs to be synced +// The selection is stored in local storage so that it persists across page loads. + +/** + * @type {Record} + */ +let sd_id_to_elements = {}; +const storageKeyPrefix = "sphinx-design-tab-id-"; + +/** + * Create a key for a tab element. + * @param {HTMLElement} el - The tab element. + * @returns {[string, string, string] | null} - The key. + * + */ +function create_key(el) { + let syncId = el.getAttribute("data-sync-id"); + let syncGroup = el.getAttribute("data-sync-group"); + if (!syncId || !syncGroup) return null; + return [syncGroup, syncId, syncGroup + "--" + syncId]; +} + +/** + * Initialize the tab selection. + * + */ +function ready() { + // Find all tabs with sync data + + /** @type {string[]} */ + let groups = []; + + document.querySelectorAll(".sd-tab-label").forEach((label) => { + if (label instanceof HTMLElement) { + let data = create_key(label); + if (data) { + let [group, id, key] = data; + + // add click event listener + // @ts-ignore + label.onclick = onSDLabelClick; + + // store map of key to elements + if (!sd_id_to_elements[key]) { + sd_id_to_elements[key] = []; + } + sd_id_to_elements[key].push(label); + + if (groups.indexOf(group) === -1) { + groups.push(group); + // Check if a specific tab has been selected via URL parameter + const tabParam = new URLSearchParams(window.location.search).get( + group + ); + if (tabParam) { + console.log( + "sphinx-design: Selecting tab id for group '" + + group + + "' from URL parameter: " + + tabParam + ); + window.sessionStorage.setItem(storageKeyPrefix + group, tabParam); + } + } + + // Check is a specific tab has been selected previously + let previousId = window.sessionStorage.getItem( + storageKeyPrefix + group + ); + if (previousId === id) { + // console.log( + // "sphinx-design: Selecting tab from session storage: " + id + // ); + // @ts-ignore + label.previousElementSibling.checked = true; + } + } + } + }); +} + +/** + * Activate other tabs with the same sync id. + * + * @this {HTMLElement} - The element that was clicked. + */ +function onSDLabelClick() { + let data = create_key(this); + if (!data) return; + let [group, id, key] = data; + for (const label of sd_id_to_elements[key]) { + if (label === this) continue; + // @ts-ignore + label.previousElementSibling.checked = true; + } + window.sessionStorage.setItem(storageKeyPrefix + group, id); +} + +document.addEventListener("DOMContentLoaded", ready, false); diff --git a/0.7.5/_sphinx_design_static/sphinx-design.min.css b/0.7.5/_sphinx_design_static/sphinx-design.min.css new file mode 100644 index 00000000..860c36da --- /dev/null +++ b/0.7.5/_sphinx_design_static/sphinx-design.min.css @@ -0,0 +1 @@ +.sd-bg-primary{background-color:var(--sd-color-primary) !important}.sd-bg-text-primary{color:var(--sd-color-primary-text) !important}button.sd-bg-primary:focus,button.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}a.sd-bg-primary:focus,a.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}.sd-bg-secondary{background-color:var(--sd-color-secondary) !important}.sd-bg-text-secondary{color:var(--sd-color-secondary-text) !important}button.sd-bg-secondary:focus,button.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}a.sd-bg-secondary:focus,a.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}.sd-bg-success{background-color:var(--sd-color-success) !important}.sd-bg-text-success{color:var(--sd-color-success-text) !important}button.sd-bg-success:focus,button.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}a.sd-bg-success:focus,a.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}.sd-bg-info{background-color:var(--sd-color-info) !important}.sd-bg-text-info{color:var(--sd-color-info-text) !important}button.sd-bg-info:focus,button.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}a.sd-bg-info:focus,a.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}.sd-bg-warning{background-color:var(--sd-color-warning) !important}.sd-bg-text-warning{color:var(--sd-color-warning-text) !important}button.sd-bg-warning:focus,button.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}a.sd-bg-warning:focus,a.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}.sd-bg-danger{background-color:var(--sd-color-danger) !important}.sd-bg-text-danger{color:var(--sd-color-danger-text) !important}button.sd-bg-danger:focus,button.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}a.sd-bg-danger:focus,a.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}.sd-bg-light{background-color:var(--sd-color-light) !important}.sd-bg-text-light{color:var(--sd-color-light-text) !important}button.sd-bg-light:focus,button.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}a.sd-bg-light:focus,a.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}.sd-bg-muted{background-color:var(--sd-color-muted) !important}.sd-bg-text-muted{color:var(--sd-color-muted-text) !important}button.sd-bg-muted:focus,button.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}a.sd-bg-muted:focus,a.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}.sd-bg-dark{background-color:var(--sd-color-dark) !important}.sd-bg-text-dark{color:var(--sd-color-dark-text) !important}button.sd-bg-dark:focus,button.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}a.sd-bg-dark:focus,a.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}.sd-bg-black{background-color:var(--sd-color-black) !important}.sd-bg-text-black{color:var(--sd-color-black-text) !important}button.sd-bg-black:focus,button.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}a.sd-bg-black:focus,a.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}.sd-bg-white{background-color:var(--sd-color-white) !important}.sd-bg-text-white{color:var(--sd-color-white-text) !important}button.sd-bg-white:focus,button.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}a.sd-bg-white:focus,a.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}.sd-text-primary,.sd-text-primary>p{color:var(--sd-color-primary) !important}a.sd-text-primary:focus,a.sd-text-primary:hover{color:var(--sd-color-primary-highlight) !important}.sd-text-secondary,.sd-text-secondary>p{color:var(--sd-color-secondary) !important}a.sd-text-secondary:focus,a.sd-text-secondary:hover{color:var(--sd-color-secondary-highlight) !important}.sd-text-success,.sd-text-success>p{color:var(--sd-color-success) !important}a.sd-text-success:focus,a.sd-text-success:hover{color:var(--sd-color-success-highlight) !important}.sd-text-info,.sd-text-info>p{color:var(--sd-color-info) !important}a.sd-text-info:focus,a.sd-text-info:hover{color:var(--sd-color-info-highlight) !important}.sd-text-warning,.sd-text-warning>p{color:var(--sd-color-warning) !important}a.sd-text-warning:focus,a.sd-text-warning:hover{color:var(--sd-color-warning-highlight) !important}.sd-text-danger,.sd-text-danger>p{color:var(--sd-color-danger) !important}a.sd-text-danger:focus,a.sd-text-danger:hover{color:var(--sd-color-danger-highlight) !important}.sd-text-light,.sd-text-light>p{color:var(--sd-color-light) !important}a.sd-text-light:focus,a.sd-text-light:hover{color:var(--sd-color-light-highlight) !important}.sd-text-muted,.sd-text-muted>p{color:var(--sd-color-muted) !important}a.sd-text-muted:focus,a.sd-text-muted:hover{color:var(--sd-color-muted-highlight) !important}.sd-text-dark,.sd-text-dark>p{color:var(--sd-color-dark) !important}a.sd-text-dark:focus,a.sd-text-dark:hover{color:var(--sd-color-dark-highlight) !important}.sd-text-black,.sd-text-black>p{color:var(--sd-color-black) !important}a.sd-text-black:focus,a.sd-text-black:hover{color:var(--sd-color-black-highlight) !important}.sd-text-white,.sd-text-white>p{color:var(--sd-color-white) !important}a.sd-text-white:focus,a.sd-text-white:hover{color:var(--sd-color-white-highlight) !important}.sd-outline-primary{border-color:var(--sd-color-primary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-primary:focus,a.sd-outline-primary:hover{border-color:var(--sd-color-primary-highlight) !important}.sd-outline-secondary{border-color:var(--sd-color-secondary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-secondary:focus,a.sd-outline-secondary:hover{border-color:var(--sd-color-secondary-highlight) !important}.sd-outline-success{border-color:var(--sd-color-success) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-success:focus,a.sd-outline-success:hover{border-color:var(--sd-color-success-highlight) !important}.sd-outline-info{border-color:var(--sd-color-info) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-info:focus,a.sd-outline-info:hover{border-color:var(--sd-color-info-highlight) !important}.sd-outline-warning{border-color:var(--sd-color-warning) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-warning:focus,a.sd-outline-warning:hover{border-color:var(--sd-color-warning-highlight) !important}.sd-outline-danger{border-color:var(--sd-color-danger) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-danger:focus,a.sd-outline-danger:hover{border-color:var(--sd-color-danger-highlight) !important}.sd-outline-light{border-color:var(--sd-color-light) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-light:focus,a.sd-outline-light:hover{border-color:var(--sd-color-light-highlight) !important}.sd-outline-muted{border-color:var(--sd-color-muted) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-muted:focus,a.sd-outline-muted:hover{border-color:var(--sd-color-muted-highlight) !important}.sd-outline-dark{border-color:var(--sd-color-dark) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-dark:focus,a.sd-outline-dark:hover{border-color:var(--sd-color-dark-highlight) !important}.sd-outline-black{border-color:var(--sd-color-black) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-black:focus,a.sd-outline-black:hover{border-color:var(--sd-color-black-highlight) !important}.sd-outline-white{border-color:var(--sd-color-white) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-white:focus,a.sd-outline-white:hover{border-color:var(--sd-color-white-highlight) !important}.sd-bg-transparent{background-color:transparent !important}.sd-outline-transparent{border-color:transparent !important}.sd-text-transparent{color:transparent !important}.sd-p-0{padding:0 !important}.sd-pt-0,.sd-py-0{padding-top:0 !important}.sd-pr-0,.sd-px-0{padding-right:0 !important}.sd-pb-0,.sd-py-0{padding-bottom:0 !important}.sd-pl-0,.sd-px-0{padding-left:0 !important}.sd-p-1{padding:.25rem !important}.sd-pt-1,.sd-py-1{padding-top:.25rem !important}.sd-pr-1,.sd-px-1{padding-right:.25rem !important}.sd-pb-1,.sd-py-1{padding-bottom:.25rem !important}.sd-pl-1,.sd-px-1{padding-left:.25rem !important}.sd-p-2{padding:.5rem !important}.sd-pt-2,.sd-py-2{padding-top:.5rem !important}.sd-pr-2,.sd-px-2{padding-right:.5rem !important}.sd-pb-2,.sd-py-2{padding-bottom:.5rem !important}.sd-pl-2,.sd-px-2{padding-left:.5rem !important}.sd-p-3{padding:1rem !important}.sd-pt-3,.sd-py-3{padding-top:1rem !important}.sd-pr-3,.sd-px-3{padding-right:1rem !important}.sd-pb-3,.sd-py-3{padding-bottom:1rem !important}.sd-pl-3,.sd-px-3{padding-left:1rem !important}.sd-p-4{padding:1.5rem !important}.sd-pt-4,.sd-py-4{padding-top:1.5rem !important}.sd-pr-4,.sd-px-4{padding-right:1.5rem !important}.sd-pb-4,.sd-py-4{padding-bottom:1.5rem !important}.sd-pl-4,.sd-px-4{padding-left:1.5rem !important}.sd-p-5{padding:3rem !important}.sd-pt-5,.sd-py-5{padding-top:3rem !important}.sd-pr-5,.sd-px-5{padding-right:3rem !important}.sd-pb-5,.sd-py-5{padding-bottom:3rem !important}.sd-pl-5,.sd-px-5{padding-left:3rem !important}.sd-m-auto{margin:auto !important}.sd-mt-auto,.sd-my-auto{margin-top:auto !important}.sd-mr-auto,.sd-mx-auto{margin-right:auto !important}.sd-mb-auto,.sd-my-auto{margin-bottom:auto !important}.sd-ml-auto,.sd-mx-auto{margin-left:auto !important}.sd-m-0{margin:0 !important}.sd-mt-0,.sd-my-0{margin-top:0 !important}.sd-mr-0,.sd-mx-0{margin-right:0 !important}.sd-mb-0,.sd-my-0{margin-bottom:0 !important}.sd-ml-0,.sd-mx-0{margin-left:0 !important}.sd-m-1{margin:.25rem !important}.sd-mt-1,.sd-my-1{margin-top:.25rem !important}.sd-mr-1,.sd-mx-1{margin-right:.25rem !important}.sd-mb-1,.sd-my-1{margin-bottom:.25rem !important}.sd-ml-1,.sd-mx-1{margin-left:.25rem !important}.sd-m-2{margin:.5rem !important}.sd-mt-2,.sd-my-2{margin-top:.5rem !important}.sd-mr-2,.sd-mx-2{margin-right:.5rem !important}.sd-mb-2,.sd-my-2{margin-bottom:.5rem !important}.sd-ml-2,.sd-mx-2{margin-left:.5rem !important}.sd-m-3{margin:1rem !important}.sd-mt-3,.sd-my-3{margin-top:1rem !important}.sd-mr-3,.sd-mx-3{margin-right:1rem !important}.sd-mb-3,.sd-my-3{margin-bottom:1rem !important}.sd-ml-3,.sd-mx-3{margin-left:1rem !important}.sd-m-4{margin:1.5rem !important}.sd-mt-4,.sd-my-4{margin-top:1.5rem !important}.sd-mr-4,.sd-mx-4{margin-right:1.5rem !important}.sd-mb-4,.sd-my-4{margin-bottom:1.5rem !important}.sd-ml-4,.sd-mx-4{margin-left:1.5rem !important}.sd-m-5{margin:3rem !important}.sd-mt-5,.sd-my-5{margin-top:3rem !important}.sd-mr-5,.sd-mx-5{margin-right:3rem !important}.sd-mb-5,.sd-my-5{margin-bottom:3rem !important}.sd-ml-5,.sd-mx-5{margin-left:3rem !important}.sd-w-25{width:25% !important}.sd-w-50{width:50% !important}.sd-w-75{width:75% !important}.sd-w-100{width:100% !important}.sd-w-auto{width:auto !important}.sd-h-25{height:25% !important}.sd-h-50{height:50% !important}.sd-h-75{height:75% !important}.sd-h-100{height:100% !important}.sd-h-auto{height:auto !important}.sd-d-none{display:none !important}.sd-d-inline{display:inline !important}.sd-d-inline-block{display:inline-block !important}.sd-d-block{display:block !important}.sd-d-grid{display:grid !important}.sd-d-flex-row{display:-ms-flexbox !important;display:flex !important;flex-direction:row !important}.sd-d-flex-column{display:-ms-flexbox !important;display:flex !important;flex-direction:column !important}.sd-d-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}@media(min-width: 576px){.sd-d-sm-none{display:none !important}.sd-d-sm-inline{display:inline !important}.sd-d-sm-inline-block{display:inline-block !important}.sd-d-sm-block{display:block !important}.sd-d-sm-grid{display:grid !important}.sd-d-sm-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-sm-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 768px){.sd-d-md-none{display:none !important}.sd-d-md-inline{display:inline !important}.sd-d-md-inline-block{display:inline-block !important}.sd-d-md-block{display:block !important}.sd-d-md-grid{display:grid !important}.sd-d-md-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-md-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 992px){.sd-d-lg-none{display:none !important}.sd-d-lg-inline{display:inline !important}.sd-d-lg-inline-block{display:inline-block !important}.sd-d-lg-block{display:block !important}.sd-d-lg-grid{display:grid !important}.sd-d-lg-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-lg-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 1200px){.sd-d-xl-none{display:none !important}.sd-d-xl-inline{display:inline !important}.sd-d-xl-inline-block{display:inline-block !important}.sd-d-xl-block{display:block !important}.sd-d-xl-grid{display:grid !important}.sd-d-xl-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-xl-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}.sd-align-major-start{justify-content:flex-start !important}.sd-align-major-end{justify-content:flex-end !important}.sd-align-major-center{justify-content:center !important}.sd-align-major-justify{justify-content:space-between !important}.sd-align-major-spaced{justify-content:space-evenly !important}.sd-align-minor-start{align-items:flex-start !important}.sd-align-minor-end{align-items:flex-end !important}.sd-align-minor-center{align-items:center !important}.sd-align-minor-stretch{align-items:stretch !important}.sd-text-justify{text-align:justify !important}.sd-text-left{text-align:left !important}.sd-text-right{text-align:right !important}.sd-text-center{text-align:center !important}.sd-font-weight-light{font-weight:300 !important}.sd-font-weight-lighter{font-weight:lighter !important}.sd-font-weight-normal{font-weight:400 !important}.sd-font-weight-bold{font-weight:700 !important}.sd-font-weight-bolder{font-weight:bolder !important}.sd-font-italic{font-style:italic !important}.sd-text-decoration-none{text-decoration:none !important}.sd-text-lowercase{text-transform:lowercase !important}.sd-text-uppercase{text-transform:uppercase !important}.sd-text-capitalize{text-transform:capitalize !important}.sd-text-wrap{white-space:normal !important}.sd-text-nowrap{white-space:nowrap !important}.sd-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-fs-1,.sd-fs-1>p{font-size:calc(1.375rem + 1.5vw) !important;line-height:unset !important}.sd-fs-2,.sd-fs-2>p{font-size:calc(1.325rem + 0.9vw) !important;line-height:unset !important}.sd-fs-3,.sd-fs-3>p{font-size:calc(1.3rem + 0.6vw) !important;line-height:unset !important}.sd-fs-4,.sd-fs-4>p{font-size:calc(1.275rem + 0.3vw) !important;line-height:unset !important}.sd-fs-5,.sd-fs-5>p{font-size:1.25rem !important;line-height:unset !important}.sd-fs-6,.sd-fs-6>p{font-size:1rem !important;line-height:unset !important}.sd-border-0{border:0 solid !important}.sd-border-top-0{border-top:0 solid !important}.sd-border-bottom-0{border-bottom:0 solid !important}.sd-border-right-0{border-right:0 solid !important}.sd-border-left-0{border-left:0 solid !important}.sd-border-1{border:1px solid !important}.sd-border-top-1{border-top:1px solid !important}.sd-border-bottom-1{border-bottom:1px solid !important}.sd-border-right-1{border-right:1px solid !important}.sd-border-left-1{border-left:1px solid !important}.sd-border-2{border:2px solid !important}.sd-border-top-2{border-top:2px solid !important}.sd-border-bottom-2{border-bottom:2px solid !important}.sd-border-right-2{border-right:2px solid !important}.sd-border-left-2{border-left:2px solid !important}.sd-border-3{border:3px solid !important}.sd-border-top-3{border-top:3px solid !important}.sd-border-bottom-3{border-bottom:3px solid !important}.sd-border-right-3{border-right:3px solid !important}.sd-border-left-3{border-left:3px solid !important}.sd-border-4{border:4px solid !important}.sd-border-top-4{border-top:4px solid !important}.sd-border-bottom-4{border-bottom:4px solid !important}.sd-border-right-4{border-right:4px solid !important}.sd-border-left-4{border-left:4px solid !important}.sd-border-5{border:5px solid !important}.sd-border-top-5{border-top:5px solid !important}.sd-border-bottom-5{border-bottom:5px solid !important}.sd-border-right-5{border-right:5px solid !important}.sd-border-left-5{border-left:5px solid !important}.sd-rounded-0{border-radius:0 !important}.sd-rounded-1{border-radius:.2rem !important}.sd-rounded-2{border-radius:.3rem !important}.sd-rounded-3{border-radius:.5rem !important}.sd-rounded-pill{border-radius:50rem !important}.sd-rounded-circle{border-radius:50% !important}.shadow-none{box-shadow:none !important}.sd-shadow-sm{box-shadow:0 .125rem .25rem var(--sd-color-shadow) !important}.sd-shadow-md{box-shadow:0 .5rem 1rem var(--sd-color-shadow) !important}.sd-shadow-lg{box-shadow:0 1rem 3rem var(--sd-color-shadow) !important}@keyframes sd-slide-from-left{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes sd-slide-from-right{0%{transform:translateX(200%)}100%{transform:translateX(0)}}@keyframes sd-grow100{0%{transform:scale(0);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50{0%{transform:scale(0.5);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50-rot20{0%{transform:scale(0.5) rotateZ(-20deg);opacity:.5}75%{transform:scale(1) rotateZ(5deg);opacity:1}95%{transform:scale(1) rotateZ(-1deg);opacity:1}100%{transform:scale(1) rotateZ(0);opacity:1}}.sd-animate-slide-from-left{animation:1s ease-out 0s 1 normal none running sd-slide-from-left}.sd-animate-slide-from-right{animation:1s ease-out 0s 1 normal none running sd-slide-from-right}.sd-animate-grow100{animation:1s ease-out 0s 1 normal none running sd-grow100}.sd-animate-grow50{animation:1s ease-out 0s 1 normal none running sd-grow50}.sd-animate-grow50-rot20{animation:1s ease-out 0s 1 normal none running sd-grow50-rot20}.sd-badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.sd-badge:empty{display:none}a.sd-badge{text-decoration:none}.sd-btn .sd-badge{position:relative;top:-1px}.sd-btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;cursor:pointer;display:inline-block;font-weight:400;font-size:1rem;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;vertical-align:middle;user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none}.sd-btn:hover{text-decoration:none}@media(prefers-reduced-motion: reduce){.sd-btn{transition:none}}.sd-btn-primary,.sd-btn-outline-primary:hover,.sd-btn-outline-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-primary:hover,.sd-btn-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary-highlight) !important;border-color:var(--sd-color-primary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-primary{color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary,.sd-btn-outline-secondary:hover,.sd-btn-outline-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary:hover,.sd-btn-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary-highlight) !important;border-color:var(--sd-color-secondary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-secondary{color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success,.sd-btn-outline-success:hover,.sd-btn-outline-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success:hover,.sd-btn-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success-highlight) !important;border-color:var(--sd-color-success-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-success{color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info,.sd-btn-outline-info:hover,.sd-btn-outline-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info:hover,.sd-btn-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info-highlight) !important;border-color:var(--sd-color-info-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-info{color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning,.sd-btn-outline-warning:hover,.sd-btn-outline-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning:hover,.sd-btn-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning-highlight) !important;border-color:var(--sd-color-warning-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-warning{color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger,.sd-btn-outline-danger:hover,.sd-btn-outline-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger:hover,.sd-btn-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger-highlight) !important;border-color:var(--sd-color-danger-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-danger{color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light,.sd-btn-outline-light:hover,.sd-btn-outline-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light:hover,.sd-btn-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light-highlight) !important;border-color:var(--sd-color-light-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-light{color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted,.sd-btn-outline-muted:hover,.sd-btn-outline-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted:hover,.sd-btn-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted-highlight) !important;border-color:var(--sd-color-muted-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-muted{color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark,.sd-btn-outline-dark:hover,.sd-btn-outline-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark:hover,.sd-btn-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark-highlight) !important;border-color:var(--sd-color-dark-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-dark{color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black,.sd-btn-outline-black:hover,.sd-btn-outline-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black:hover,.sd-btn-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black-highlight) !important;border-color:var(--sd-color-black-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-black{color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white,.sd-btn-outline-white:hover,.sd-btn-outline-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white:hover,.sd-btn-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white-highlight) !important;border-color:var(--sd-color-white-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-white{color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.sd-hide-link-text{font-size:0}.sd-octicon,.sd-material-icon{display:inline-block;fill:currentColor;vertical-align:middle}.sd-avatar-xs{border-radius:50%;object-fit:cover;object-position:center;width:1rem;height:1rem}.sd-avatar-sm{border-radius:50%;object-fit:cover;object-position:center;width:3rem;height:3rem}.sd-avatar-md{border-radius:50%;object-fit:cover;object-position:center;width:5rem;height:5rem}.sd-avatar-lg{border-radius:50%;object-fit:cover;object-position:center;width:7rem;height:7rem}.sd-avatar-xl{border-radius:50%;object-fit:cover;object-position:center;width:10rem;height:10rem}.sd-avatar-inherit{border-radius:50%;object-fit:cover;object-position:center;width:inherit;height:inherit}.sd-avatar-initial{border-radius:50%;object-fit:cover;object-position:center;width:initial;height:initial}.sd-card{background-clip:border-box;background-color:var(--sd-color-card-background);border:1px solid var(--sd-color-card-border);border-radius:.25rem;color:var(--sd-color-card-text);display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.sd-card>hr{margin-left:0;margin-right:0}.sd-card-hover:hover{border-color:var(--sd-color-card-border-hover);transform:scale(1.01)}.sd-card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem 1rem}.sd-card-title{margin-bottom:.5rem}.sd-card-subtitle{margin-top:-0.25rem;margin-bottom:0}.sd-card-text:last-child{margin-bottom:0}.sd-card-link:hover{text-decoration:none}.sd-card-link+.card-link{margin-left:1rem}.sd-card-header{padding:.5rem 1rem;margin-bottom:0;background-color:var(--sd-color-card-header);border-bottom:1px solid var(--sd-color-card-border)}.sd-card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.sd-card-footer{padding:.5rem 1rem;background-color:var(--sd-color-card-footer);border-top:1px solid var(--sd-color-card-border)}.sd-card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.sd-card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.sd-card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.sd-card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom,.sd-card-img-top{width:100%}.sd-card-img,.sd-card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom{border-bottom-left-radius:calc(0.25rem - 1px);border-bottom-right-radius:calc(0.25rem - 1px)}.sd-cards-carousel{width:100%;display:flex;flex-wrap:nowrap;-ms-flex-direction:row;flex-direction:row;overflow-x:hidden;scroll-snap-type:x mandatory}.sd-cards-carousel.sd-show-scrollbar{overflow-x:auto}.sd-cards-carousel:hover,.sd-cards-carousel:focus{overflow-x:auto}.sd-cards-carousel>.sd-card{flex-shrink:0;scroll-snap-align:start}.sd-cards-carousel>.sd-card:not(:last-child){margin-right:3px}.sd-card-cols-1>.sd-card{width:90%}.sd-card-cols-2>.sd-card{width:45%}.sd-card-cols-3>.sd-card{width:30%}.sd-card-cols-4>.sd-card{width:22.5%}.sd-card-cols-5>.sd-card{width:18%}.sd-card-cols-6>.sd-card{width:15%}.sd-card-cols-7>.sd-card{width:12.8571428571%}.sd-card-cols-8>.sd-card{width:11.25%}.sd-card-cols-9>.sd-card{width:10%}.sd-card-cols-10>.sd-card{width:9%}.sd-card-cols-11>.sd-card{width:8.1818181818%}.sd-card-cols-12>.sd-card{width:7.5%}.sd-container,.sd-container-fluid,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container-xl{margin-left:auto;margin-right:auto;padding-left:var(--sd-gutter-x, 0.75rem);padding-right:var(--sd-gutter-x, 0.75rem);width:100%}@media(min-width: 576px){.sd-container-sm,.sd-container{max-width:540px}}@media(min-width: 768px){.sd-container-md,.sd-container-sm,.sd-container{max-width:720px}}@media(min-width: 992px){.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:960px}}@media(min-width: 1200px){.sd-container-xl,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:1140px}}.sd-row{--sd-gutter-x: 1.5rem;--sd-gutter-y: 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:calc(var(--sd-gutter-y) * -1);margin-right:calc(var(--sd-gutter-x) * -0.5);margin-left:calc(var(--sd-gutter-x) * -0.5)}.sd-row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--sd-gutter-x) * 0.5);padding-left:calc(var(--sd-gutter-x) * 0.5);margin-top:var(--sd-gutter-y)}.sd-col{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-auto>*{flex:0 0 auto;width:auto}.sd-row-cols-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}@media(min-width: 576px){.sd-col-sm{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-sm-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-sm-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-sm-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-sm-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-sm-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-sm-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-sm-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-sm-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-sm-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-sm-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-sm-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-sm-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-sm-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 768px){.sd-col-md{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-md-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-md-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-md-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-md-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-md-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-md-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-md-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-md-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-md-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-md-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-md-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-md-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-md-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 992px){.sd-col-lg{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-lg-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-lg-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-lg-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-lg-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-lg-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-lg-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-lg-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-lg-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-lg-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-lg-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-lg-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-lg-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-lg-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 1200px){.sd-col-xl{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-xl-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-xl-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-xl-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-xl-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-xl-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-xl-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-xl-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-xl-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-xl-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-xl-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-xl-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-xl-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-xl-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}.sd-col-auto{flex:0 0 auto;-ms-flex:0 0 auto;width:auto}.sd-col-1{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}.sd-col-2{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-col-3{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-col-4{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-col-5{flex:0 0 auto;-ms-flex:0 0 auto;width:41.6666666667%}.sd-col-6{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-col-7{flex:0 0 auto;-ms-flex:0 0 auto;width:58.3333333333%}.sd-col-8{flex:0 0 auto;-ms-flex:0 0 auto;width:66.6666666667%}.sd-col-9{flex:0 0 auto;-ms-flex:0 0 auto;width:75%}.sd-col-10{flex:0 0 auto;-ms-flex:0 0 auto;width:83.3333333333%}.sd-col-11{flex:0 0 auto;-ms-flex:0 0 auto;width:91.6666666667%}.sd-col-12{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-g-0,.sd-gy-0{--sd-gutter-y: 0}.sd-g-0,.sd-gx-0{--sd-gutter-x: 0}.sd-g-1,.sd-gy-1{--sd-gutter-y: 0.25rem}.sd-g-1,.sd-gx-1{--sd-gutter-x: 0.25rem}.sd-g-2,.sd-gy-2{--sd-gutter-y: 0.5rem}.sd-g-2,.sd-gx-2{--sd-gutter-x: 0.5rem}.sd-g-3,.sd-gy-3{--sd-gutter-y: 1rem}.sd-g-3,.sd-gx-3{--sd-gutter-x: 1rem}.sd-g-4,.sd-gy-4{--sd-gutter-y: 1.5rem}.sd-g-4,.sd-gx-4{--sd-gutter-x: 1.5rem}.sd-g-5,.sd-gy-5{--sd-gutter-y: 3rem}.sd-g-5,.sd-gx-5{--sd-gutter-x: 3rem}@media(min-width: 576px){.sd-col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-sm-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-sm-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-sm-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-sm-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-sm-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-sm-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-sm-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-sm-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-sm-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-sm-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-sm-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-sm-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-sm-0,.sd-gy-sm-0{--sd-gutter-y: 0}.sd-g-sm-0,.sd-gx-sm-0{--sd-gutter-x: 0}.sd-g-sm-1,.sd-gy-sm-1{--sd-gutter-y: 0.25rem}.sd-g-sm-1,.sd-gx-sm-1{--sd-gutter-x: 0.25rem}.sd-g-sm-2,.sd-gy-sm-2{--sd-gutter-y: 0.5rem}.sd-g-sm-2,.sd-gx-sm-2{--sd-gutter-x: 0.5rem}.sd-g-sm-3,.sd-gy-sm-3{--sd-gutter-y: 1rem}.sd-g-sm-3,.sd-gx-sm-3{--sd-gutter-x: 1rem}.sd-g-sm-4,.sd-gy-sm-4{--sd-gutter-y: 1.5rem}.sd-g-sm-4,.sd-gx-sm-4{--sd-gutter-x: 1.5rem}.sd-g-sm-5,.sd-gy-sm-5{--sd-gutter-y: 3rem}.sd-g-sm-5,.sd-gx-sm-5{--sd-gutter-x: 3rem}}@media(min-width: 768px){.sd-col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-md-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-md-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-md-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-md-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-md-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-md-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-md-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-md-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-md-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-md-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-md-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-md-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-md-0,.sd-gy-md-0{--sd-gutter-y: 0}.sd-g-md-0,.sd-gx-md-0{--sd-gutter-x: 0}.sd-g-md-1,.sd-gy-md-1{--sd-gutter-y: 0.25rem}.sd-g-md-1,.sd-gx-md-1{--sd-gutter-x: 0.25rem}.sd-g-md-2,.sd-gy-md-2{--sd-gutter-y: 0.5rem}.sd-g-md-2,.sd-gx-md-2{--sd-gutter-x: 0.5rem}.sd-g-md-3,.sd-gy-md-3{--sd-gutter-y: 1rem}.sd-g-md-3,.sd-gx-md-3{--sd-gutter-x: 1rem}.sd-g-md-4,.sd-gy-md-4{--sd-gutter-y: 1.5rem}.sd-g-md-4,.sd-gx-md-4{--sd-gutter-x: 1.5rem}.sd-g-md-5,.sd-gy-md-5{--sd-gutter-y: 3rem}.sd-g-md-5,.sd-gx-md-5{--sd-gutter-x: 3rem}}@media(min-width: 992px){.sd-col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-lg-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-lg-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-lg-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-lg-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-lg-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-lg-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-lg-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-lg-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-lg-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-lg-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-lg-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-lg-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-lg-0,.sd-gy-lg-0{--sd-gutter-y: 0}.sd-g-lg-0,.sd-gx-lg-0{--sd-gutter-x: 0}.sd-g-lg-1,.sd-gy-lg-1{--sd-gutter-y: 0.25rem}.sd-g-lg-1,.sd-gx-lg-1{--sd-gutter-x: 0.25rem}.sd-g-lg-2,.sd-gy-lg-2{--sd-gutter-y: 0.5rem}.sd-g-lg-2,.sd-gx-lg-2{--sd-gutter-x: 0.5rem}.sd-g-lg-3,.sd-gy-lg-3{--sd-gutter-y: 1rem}.sd-g-lg-3,.sd-gx-lg-3{--sd-gutter-x: 1rem}.sd-g-lg-4,.sd-gy-lg-4{--sd-gutter-y: 1.5rem}.sd-g-lg-4,.sd-gx-lg-4{--sd-gutter-x: 1.5rem}.sd-g-lg-5,.sd-gy-lg-5{--sd-gutter-y: 3rem}.sd-g-lg-5,.sd-gx-lg-5{--sd-gutter-x: 3rem}}@media(min-width: 1200px){.sd-col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-xl-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-xl-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-xl-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-xl-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-xl-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-xl-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-xl-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-xl-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-xl-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-xl-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-xl-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-xl-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-xl-0,.sd-gy-xl-0{--sd-gutter-y: 0}.sd-g-xl-0,.sd-gx-xl-0{--sd-gutter-x: 0}.sd-g-xl-1,.sd-gy-xl-1{--sd-gutter-y: 0.25rem}.sd-g-xl-1,.sd-gx-xl-1{--sd-gutter-x: 0.25rem}.sd-g-xl-2,.sd-gy-xl-2{--sd-gutter-y: 0.5rem}.sd-g-xl-2,.sd-gx-xl-2{--sd-gutter-x: 0.5rem}.sd-g-xl-3,.sd-gy-xl-3{--sd-gutter-y: 1rem}.sd-g-xl-3,.sd-gx-xl-3{--sd-gutter-x: 1rem}.sd-g-xl-4,.sd-gy-xl-4{--sd-gutter-y: 1.5rem}.sd-g-xl-4,.sd-gx-xl-4{--sd-gutter-x: 1.5rem}.sd-g-xl-5,.sd-gy-xl-5{--sd-gutter-y: 3rem}.sd-g-xl-5,.sd-gx-xl-5{--sd-gutter-x: 3rem}}.sd-flex-row-reverse{flex-direction:row-reverse !important}details.sd-dropdown{position:relative;font-size:var(--sd-fontsize-dropdown)}details.sd-dropdown:hover{cursor:pointer}details.sd-dropdown .sd-summary-content{cursor:default}details.sd-dropdown summary.sd-summary-title{padding:.5em .6em .5em 1em;font-size:var(--sd-fontsize-dropdown-title);font-weight:var(--sd-fontweight-dropdown-title);user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;list-style:none;display:inline-flex;justify-content:space-between}details.sd-dropdown summary.sd-summary-title::-webkit-details-marker{display:none}details.sd-dropdown summary.sd-summary-title:focus{outline:none}details.sd-dropdown summary.sd-summary-title .sd-summary-icon{margin-right:.6em;display:inline-flex;align-items:center}details.sd-dropdown summary.sd-summary-title .sd-summary-icon svg{opacity:.8}details.sd-dropdown summary.sd-summary-title .sd-summary-text{flex-grow:1;line-height:1.5;padding-right:.5rem}details.sd-dropdown summary.sd-summary-title .sd-summary-state-marker{pointer-events:none;display:inline-flex;align-items:center}details.sd-dropdown summary.sd-summary-title .sd-summary-state-marker svg{opacity:.6}details.sd-dropdown summary.sd-summary-title:hover .sd-summary-state-marker svg{opacity:1;transform:scale(1.1)}details.sd-dropdown[open] summary .sd-octicon.no-title{visibility:hidden}details.sd-dropdown .sd-summary-chevron-right{transition:.25s}details.sd-dropdown[open]>.sd-summary-title .sd-summary-chevron-right{transform:rotate(90deg)}details.sd-dropdown[open]>.sd-summary-title .sd-summary-chevron-down{transform:rotate(180deg)}details.sd-dropdown:not([open]).sd-card{border:none}details.sd-dropdown:not([open])>.sd-card-header{border:1px solid var(--sd-color-card-border);border-radius:.25rem}details.sd-dropdown.sd-fade-in[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out;animation:sd-fade-in .5s ease-in-out}details.sd-dropdown.sd-fade-in-slide-down[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out}.sd-col>.sd-dropdown{width:100%}.sd-summary-content>.sd-tab-set:first-child{margin-top:0}@keyframes sd-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes sd-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.sd-tab-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.sd-tab-set>input{opacity:0;position:absolute}.sd-tab-set>input:checked+label{border-color:var(--sd-color-tabs-underline-active);color:var(--sd-color-tabs-label-active)}.sd-tab-set>input:checked+label+.sd-tab-content{display:block}.sd-tab-set>input:not(:checked)+label:hover{color:var(--sd-color-tabs-label-hover);border-color:var(--sd-color-tabs-underline-hover)}.sd-tab-set>input:focus+label{outline-style:auto}.sd-tab-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.sd-tab-set>label{border-bottom:.125rem solid transparent;margin-bottom:0;color:var(--sd-color-tabs-label-inactive);border-color:var(--sd-color-tabs-underline-inactive);cursor:pointer;font-size:var(--sd-fontsize-tabs-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .sd-tab-set>label:hover{color:var(--sd-color-tabs-label-active)}.sd-col>.sd-tab-set{width:100%}.sd-tab-content{box-shadow:0 -0.0625rem var(--sd-color-tabs-overline),0 .0625rem var(--sd-color-tabs-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.sd-tab-content>:first-child{margin-top:0 !important}.sd-tab-content>:last-child{margin-bottom:0 !important}.sd-tab-content>.sd-tab-set{margin:0}.sd-sphinx-override,.sd-sphinx-override *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sd-sphinx-override p{margin-top:0}:root{--sd-color-primary: #0071bc;--sd-color-secondary: #6c757d;--sd-color-success: #28a745;--sd-color-info: #17a2b8;--sd-color-warning: #f0b37e;--sd-color-danger: #dc3545;--sd-color-light: #f8f9fa;--sd-color-muted: #6c757d;--sd-color-dark: #212529;--sd-color-black: black;--sd-color-white: white;--sd-color-primary-highlight: #0060a0;--sd-color-secondary-highlight: #5c636a;--sd-color-success-highlight: #228e3b;--sd-color-info-highlight: #148a9c;--sd-color-warning-highlight: #cc986b;--sd-color-danger-highlight: #bb2d3b;--sd-color-light-highlight: #d3d4d5;--sd-color-muted-highlight: #5c636a;--sd-color-dark-highlight: #1c1f23;--sd-color-black-highlight: black;--sd-color-white-highlight: #d9d9d9;--sd-color-primary-bg: rgba(0, 113, 188, 0.2);--sd-color-secondary-bg: rgba(108, 117, 125, 0.2);--sd-color-success-bg: rgba(40, 167, 69, 0.2);--sd-color-info-bg: rgba(23, 162, 184, 0.2);--sd-color-warning-bg: rgba(240, 179, 126, 0.2);--sd-color-danger-bg: rgba(220, 53, 69, 0.2);--sd-color-light-bg: rgba(248, 249, 250, 0.2);--sd-color-muted-bg: rgba(108, 117, 125, 0.2);--sd-color-dark-bg: rgba(33, 37, 41, 0.2);--sd-color-black-bg: rgba(0, 0, 0, 0.2);--sd-color-white-bg: rgba(255, 255, 255, 0.2);--sd-color-primary-text: #fff;--sd-color-secondary-text: #fff;--sd-color-success-text: #fff;--sd-color-info-text: #fff;--sd-color-warning-text: #212529;--sd-color-danger-text: #fff;--sd-color-light-text: #212529;--sd-color-muted-text: #fff;--sd-color-dark-text: #fff;--sd-color-black-text: #fff;--sd-color-white-text: #212529;--sd-color-shadow: rgba(0, 0, 0, 0.15);--sd-color-card-border: rgba(0, 0, 0, 0.125);--sd-color-card-border-hover: hsla(231, 99%, 66%, 1);--sd-color-card-background: transparent;--sd-color-card-text: inherit;--sd-color-card-header: transparent;--sd-color-card-footer: transparent;--sd-color-tabs-label-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-hover: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-inactive: hsl(0, 0%, 66%);--sd-color-tabs-underline-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-underline-hover: rgba(178, 206, 245, 0.62);--sd-color-tabs-underline-inactive: transparent;--sd-color-tabs-overline: rgb(222, 222, 222);--sd-color-tabs-underline: rgb(222, 222, 222);--sd-fontsize-tabs-label: 1rem;--sd-fontsize-dropdown: inherit;--sd-fontsize-dropdown-title: 1rem;--sd-fontweight-dropdown-title: 700} diff --git a/0.7.5/_static/autodoc_pydantic.css b/0.7.5/_static/autodoc_pydantic.css new file mode 100644 index 00000000..994a3e54 --- /dev/null +++ b/0.7.5/_static/autodoc_pydantic.css @@ -0,0 +1,11 @@ +.autodoc_pydantic_validator_arrow { + padding-left: 8px; + } + +.autodoc_pydantic_collapsable_json { + cursor: pointer; + } + +.autodoc_pydantic_collapsable_erd { + cursor: pointer; + } \ No newline at end of file diff --git a/0.7.5/_static/basic.css b/0.7.5/_static/basic.css new file mode 100644 index 00000000..2a9e4114 --- /dev/null +++ b/0.7.5/_static/basic.css @@ -0,0 +1,914 @@ +/* + * Sphinx stylesheet -- basic theme. + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 270px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin-top: 10px; +} + +ul.search li { + padding: 5px 0; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/0.7.5/_static/check-solid.svg b/0.7.5/_static/check-solid.svg new file mode 100644 index 00000000..92fad4b5 --- /dev/null +++ b/0.7.5/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/0.7.5/_static/clipboard.min.js b/0.7.5/_static/clipboard.min.js new file mode 100644 index 00000000..54b3c463 --- /dev/null +++ b/0.7.5/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * 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 o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/0.7.5/_static/copybutton.css b/0.7.5/_static/copybutton.css new file mode 100644 index 00000000..f1916ec7 --- /dev/null +++ b/0.7.5/_static/copybutton.css @@ -0,0 +1,94 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +/* Show the copybutton */ +.highlight:hover button.copybtn, button.copybtn.success { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/0.7.5/_static/copybutton.js b/0.7.5/_static/copybutton.js new file mode 100644 index 00000000..e0da1932 --- /dev/null +++ b/0.7.5/_static/copybutton.js @@ -0,0 +1,248 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copier dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for a moment, then changes it back +// We want the timeout of our `success` class to be a bit shorter than the +// tooltip and icon change, so that we can hide the icon before changing back. +var timeoutIcon = 2000; +var timeoutSuccessClass = 1500; + +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos'; + + let text = filterText(target, exclude); + return formatCopyText(text, '>>> |\\.\\.\\. |\\$ |In \\[\\d*\\]: | {2,5}\\.\\.\\.: | {5,8}: ', true, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/0.7.5/_static/copybutton_funcs.js b/0.7.5/_static/copybutton_funcs.js new file mode 100644 index 00000000..dbe1aaad --- /dev/null +++ b/0.7.5/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/0.7.5/_static/design-tabs.js b/0.7.5/_static/design-tabs.js new file mode 100644 index 00000000..b25bd6a4 --- /dev/null +++ b/0.7.5/_static/design-tabs.js @@ -0,0 +1,101 @@ +// @ts-check + +// Extra JS capability for selected tabs to be synced +// The selection is stored in local storage so that it persists across page loads. + +/** + * @type {Record} + */ +let sd_id_to_elements = {}; +const storageKeyPrefix = "sphinx-design-tab-id-"; + +/** + * Create a key for a tab element. + * @param {HTMLElement} el - The tab element. + * @returns {[string, string, string] | null} - The key. + * + */ +function create_key(el) { + let syncId = el.getAttribute("data-sync-id"); + let syncGroup = el.getAttribute("data-sync-group"); + if (!syncId || !syncGroup) return null; + return [syncGroup, syncId, syncGroup + "--" + syncId]; +} + +/** + * Initialize the tab selection. + * + */ +function ready() { + // Find all tabs with sync data + + /** @type {string[]} */ + let groups = []; + + document.querySelectorAll(".sd-tab-label").forEach((label) => { + if (label instanceof HTMLElement) { + let data = create_key(label); + if (data) { + let [group, id, key] = data; + + // add click event listener + // @ts-ignore + label.onclick = onSDLabelClick; + + // store map of key to elements + if (!sd_id_to_elements[key]) { + sd_id_to_elements[key] = []; + } + sd_id_to_elements[key].push(label); + + if (groups.indexOf(group) === -1) { + groups.push(group); + // Check if a specific tab has been selected via URL parameter + const tabParam = new URLSearchParams(window.location.search).get( + group + ); + if (tabParam) { + console.log( + "sphinx-design: Selecting tab id for group '" + + group + + "' from URL parameter: " + + tabParam + ); + window.sessionStorage.setItem(storageKeyPrefix + group, tabParam); + } + } + + // Check is a specific tab has been selected previously + let previousId = window.sessionStorage.getItem( + storageKeyPrefix + group + ); + if (previousId === id) { + // console.log( + // "sphinx-design: Selecting tab from session storage: " + id + // ); + // @ts-ignore + label.previousElementSibling.checked = true; + } + } + } + }); +} + +/** + * Activate other tabs with the same sync id. + * + * @this {HTMLElement} - The element that was clicked. + */ +function onSDLabelClick() { + let data = create_key(this); + if (!data) return; + let [group, id, key] = data; + for (const label of sd_id_to_elements[key]) { + if (label === this) continue; + // @ts-ignore + label.previousElementSibling.checked = true; + } + window.sessionStorage.setItem(storageKeyPrefix + group, id); +} + +document.addEventListener("DOMContentLoaded", ready, false); diff --git a/0.7.5/_static/doctools.js b/0.7.5/_static/doctools.js new file mode 100644 index 00000000..0398ebb9 --- /dev/null +++ b/0.7.5/_static/doctools.js @@ -0,0 +1,149 @@ +/* + * Base JavaScript utilities for all Sphinx HTML documentation. + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/0.7.5/_static/documentation_options.js b/0.7.5/_static/documentation_options.js new file mode 100644 index 00000000..7d6e36a7 --- /dev/null +++ b/0.7.5/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '0.7.5', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/0.7.5/_static/file.png b/0.7.5/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/0.7.5/_static/file.png differ diff --git a/0.7.5/_static/graphviz.css b/0.7.5/_static/graphviz.css new file mode 100644 index 00000000..30f3837b --- /dev/null +++ b/0.7.5/_static/graphviz.css @@ -0,0 +1,12 @@ +/* + * Sphinx stylesheet -- graphviz extension. + */ + +img.graphviz { + border: 0; + max-width: 100%; +} + +object.graphviz { + max-width: 100%; +} diff --git a/0.7.5/_static/language_data.js b/0.7.5/_static/language_data.js new file mode 100644 index 00000000..c7fe6c6f --- /dev/null +++ b/0.7.5/_static/language_data.js @@ -0,0 +1,192 @@ +/* + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, if available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/0.7.5/_static/minus.png b/0.7.5/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/0.7.5/_static/minus.png differ diff --git a/0.7.5/_static/plot_directive.css b/0.7.5/_static/plot_directive.css new file mode 100644 index 00000000..d45593c9 --- /dev/null +++ b/0.7.5/_static/plot_directive.css @@ -0,0 +1,16 @@ +/* + * plot_directive.css + * ~~~~~~~~~~~~ + * + * Stylesheet controlling images created using the `plot` directive within + * Sphinx. + * + * :copyright: Copyright 2020-* by the Matplotlib development team. + * :license: Matplotlib, see LICENSE for details. + * + */ + +img.plot-directive { + border: 0; + max-width: 100%; +} diff --git a/0.7.5/_static/plus.png b/0.7.5/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/0.7.5/_static/plus.png differ diff --git a/0.7.5/_static/pygments.css b/0.7.5/_static/pygments.css new file mode 100644 index 00000000..012e6a00 --- /dev/null +++ b/0.7.5/_static/pygments.css @@ -0,0 +1,152 @@ +html[data-theme="light"] .highlight pre { line-height: 125%; } +html[data-theme="light"] .highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +html[data-theme="light"] .highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +html[data-theme="light"] .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +html[data-theme="light"] .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +html[data-theme="light"] .highlight .hll { background-color: #fae4c2 } +html[data-theme="light"] .highlight { background: #fefefe; color: #080808 } +html[data-theme="light"] .highlight .c { color: #515151 } /* Comment */ +html[data-theme="light"] .highlight .err { color: #a12236 } /* Error */ +html[data-theme="light"] .highlight .k { color: #6730c5 } /* Keyword */ +html[data-theme="light"] .highlight .l { color: #7f4707 } /* Literal */ +html[data-theme="light"] .highlight .n { color: #080808 } /* Name */ +html[data-theme="light"] .highlight .o { color: #00622f } /* Operator */ +html[data-theme="light"] .highlight .p { color: #080808 } /* Punctuation */ +html[data-theme="light"] .highlight .ch { color: #515151 } /* Comment.Hashbang */ +html[data-theme="light"] .highlight .cm { color: #515151 } /* Comment.Multiline */ +html[data-theme="light"] .highlight .cp { color: #515151 } /* Comment.Preproc */ +html[data-theme="light"] .highlight .cpf { color: #515151 } /* Comment.PreprocFile */ +html[data-theme="light"] .highlight .c1 { color: #515151 } /* Comment.Single */ +html[data-theme="light"] .highlight .cs { color: #515151 } /* Comment.Special */ +html[data-theme="light"] .highlight .gd { color: #005b82 } /* Generic.Deleted */ +html[data-theme="light"] .highlight .ge { font-style: italic } /* Generic.Emph */ +html[data-theme="light"] .highlight .gh { color: #005b82 } /* Generic.Heading */ +html[data-theme="light"] .highlight .gs { font-weight: bold } /* Generic.Strong */ +html[data-theme="light"] .highlight .gu { color: #005b82 } /* Generic.Subheading */ +html[data-theme="light"] .highlight .kc { color: #6730c5 } /* Keyword.Constant */ +html[data-theme="light"] .highlight .kd { color: #6730c5 } /* Keyword.Declaration */ +html[data-theme="light"] .highlight .kn { color: #6730c5 } /* Keyword.Namespace */ +html[data-theme="light"] .highlight .kp { color: #6730c5 } /* Keyword.Pseudo */ +html[data-theme="light"] .highlight .kr { color: #6730c5 } /* Keyword.Reserved */ +html[data-theme="light"] .highlight .kt { color: #7f4707 } /* Keyword.Type */ +html[data-theme="light"] .highlight .ld { color: #7f4707 } /* Literal.Date */ +html[data-theme="light"] .highlight .m { color: #7f4707 } /* Literal.Number */ +html[data-theme="light"] .highlight .s { color: #00622f } /* Literal.String */ +html[data-theme="light"] .highlight .na { color: #912583 } /* Name.Attribute */ +html[data-theme="light"] .highlight .nb { color: #7f4707 } /* Name.Builtin */ +html[data-theme="light"] .highlight .nc { color: #005b82 } /* Name.Class */ +html[data-theme="light"] .highlight .no { color: #005b82 } /* Name.Constant */ +html[data-theme="light"] .highlight .nd { color: #7f4707 } /* Name.Decorator */ +html[data-theme="light"] .highlight .ni { color: #00622f } /* Name.Entity */ +html[data-theme="light"] .highlight .ne { color: #6730c5 } /* Name.Exception */ +html[data-theme="light"] .highlight .nf { color: #005b82 } /* Name.Function */ +html[data-theme="light"] .highlight .nl { color: #7f4707 } /* Name.Label */ +html[data-theme="light"] .highlight .nn { color: #080808 } /* Name.Namespace */ +html[data-theme="light"] .highlight .nx { color: #080808 } /* Name.Other */ +html[data-theme="light"] .highlight .py { color: #005b82 } /* Name.Property */ +html[data-theme="light"] .highlight .nt { color: #005b82 } /* Name.Tag */ +html[data-theme="light"] .highlight .nv { color: #a12236 } /* Name.Variable */ +html[data-theme="light"] .highlight .ow { color: #6730c5 } /* Operator.Word */ +html[data-theme="light"] .highlight .pm { color: #080808 } /* Punctuation.Marker */ +html[data-theme="light"] .highlight .w { color: #080808 } /* Text.Whitespace */ +html[data-theme="light"] .highlight .mb { color: #7f4707 } /* Literal.Number.Bin */ +html[data-theme="light"] .highlight .mf { color: #7f4707 } /* Literal.Number.Float */ +html[data-theme="light"] .highlight .mh { color: #7f4707 } /* Literal.Number.Hex */ +html[data-theme="light"] .highlight .mi { color: #7f4707 } /* Literal.Number.Integer */ +html[data-theme="light"] .highlight .mo { color: #7f4707 } /* Literal.Number.Oct */ +html[data-theme="light"] .highlight .sa { color: #00622f } /* Literal.String.Affix */ +html[data-theme="light"] .highlight .sb { color: #00622f } /* Literal.String.Backtick */ +html[data-theme="light"] .highlight .sc { color: #00622f } /* Literal.String.Char */ +html[data-theme="light"] .highlight .dl { color: #00622f } /* Literal.String.Delimiter */ +html[data-theme="light"] .highlight .sd { color: #00622f } /* Literal.String.Doc */ +html[data-theme="light"] .highlight .s2 { color: #00622f } /* Literal.String.Double */ +html[data-theme="light"] .highlight .se { color: #00622f } /* Literal.String.Escape */ +html[data-theme="light"] .highlight .sh { color: #00622f } /* Literal.String.Heredoc */ +html[data-theme="light"] .highlight .si { color: #00622f } /* Literal.String.Interpol */ +html[data-theme="light"] .highlight .sx { color: #00622f } /* Literal.String.Other */ +html[data-theme="light"] .highlight .sr { color: #a12236 } /* Literal.String.Regex */ +html[data-theme="light"] .highlight .s1 { color: #00622f } /* Literal.String.Single */ +html[data-theme="light"] .highlight .ss { color: #005b82 } /* Literal.String.Symbol */ +html[data-theme="light"] .highlight .bp { color: #7f4707 } /* Name.Builtin.Pseudo */ +html[data-theme="light"] .highlight .fm { color: #005b82 } /* Name.Function.Magic */ +html[data-theme="light"] .highlight .vc { color: #a12236 } /* Name.Variable.Class */ +html[data-theme="light"] .highlight .vg { color: #a12236 } /* Name.Variable.Global */ +html[data-theme="light"] .highlight .vi { color: #a12236 } /* Name.Variable.Instance */ +html[data-theme="light"] .highlight .vm { color: #7f4707 } /* Name.Variable.Magic */ +html[data-theme="light"] .highlight .il { color: #7f4707 } /* Literal.Number.Integer.Long */ +html[data-theme="dark"] .highlight pre { line-height: 125%; } +html[data-theme="dark"] .highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +html[data-theme="dark"] .highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +html[data-theme="dark"] .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +html[data-theme="dark"] .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +html[data-theme="dark"] .highlight .hll { background-color: #ffd9002e } +html[data-theme="dark"] .highlight { background: #2b2b2b; color: #f8f8f2 } +html[data-theme="dark"] .highlight .c { color: #ffd900 } /* Comment */ +html[data-theme="dark"] .highlight .err { color: #ffa07a } /* Error */ +html[data-theme="dark"] .highlight .k { color: #dcc6e0 } /* Keyword */ +html[data-theme="dark"] .highlight .l { color: #ffd900 } /* Literal */ +html[data-theme="dark"] .highlight .n { color: #f8f8f2 } /* Name */ +html[data-theme="dark"] .highlight .o { color: #abe338 } /* Operator */ +html[data-theme="dark"] .highlight .p { color: #f8f8f2 } /* Punctuation */ +html[data-theme="dark"] .highlight .ch { color: #ffd900 } /* Comment.Hashbang */ +html[data-theme="dark"] .highlight .cm { color: #ffd900 } /* Comment.Multiline */ +html[data-theme="dark"] .highlight .cp { color: #ffd900 } /* Comment.Preproc */ +html[data-theme="dark"] .highlight .cpf { color: #ffd900 } /* Comment.PreprocFile */ +html[data-theme="dark"] .highlight .c1 { color: #ffd900 } /* Comment.Single */ +html[data-theme="dark"] .highlight .cs { color: #ffd900 } /* Comment.Special */ +html[data-theme="dark"] .highlight .gd { color: #00e0e0 } /* Generic.Deleted */ +html[data-theme="dark"] .highlight .ge { font-style: italic } /* Generic.Emph */ +html[data-theme="dark"] .highlight .gh { color: #00e0e0 } /* Generic.Heading */ +html[data-theme="dark"] .highlight .gs { font-weight: bold } /* Generic.Strong */ +html[data-theme="dark"] .highlight .gu { color: #00e0e0 } /* Generic.Subheading */ +html[data-theme="dark"] .highlight .kc { color: #dcc6e0 } /* Keyword.Constant */ +html[data-theme="dark"] .highlight .kd { color: #dcc6e0 } /* Keyword.Declaration */ +html[data-theme="dark"] .highlight .kn { color: #dcc6e0 } /* Keyword.Namespace */ +html[data-theme="dark"] .highlight .kp { color: #dcc6e0 } /* Keyword.Pseudo */ +html[data-theme="dark"] .highlight .kr { color: #dcc6e0 } /* Keyword.Reserved */ +html[data-theme="dark"] .highlight .kt { color: #ffd900 } /* Keyword.Type */ +html[data-theme="dark"] .highlight .ld { color: #ffd900 } /* Literal.Date */ +html[data-theme="dark"] .highlight .m { color: #ffd900 } /* Literal.Number */ +html[data-theme="dark"] .highlight .s { color: #abe338 } /* Literal.String */ +html[data-theme="dark"] .highlight .na { color: #ffd900 } /* Name.Attribute */ +html[data-theme="dark"] .highlight .nb { color: #ffd900 } /* Name.Builtin */ +html[data-theme="dark"] .highlight .nc { color: #00e0e0 } /* Name.Class */ +html[data-theme="dark"] .highlight .no { color: #00e0e0 } /* Name.Constant */ +html[data-theme="dark"] .highlight .nd { color: #ffd900 } /* Name.Decorator */ +html[data-theme="dark"] .highlight .ni { color: #abe338 } /* Name.Entity */ +html[data-theme="dark"] .highlight .ne { color: #dcc6e0 } /* Name.Exception */ +html[data-theme="dark"] .highlight .nf { color: #00e0e0 } /* Name.Function */ +html[data-theme="dark"] .highlight .nl { color: #ffd900 } /* Name.Label */ +html[data-theme="dark"] .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ +html[data-theme="dark"] .highlight .nx { color: #f8f8f2 } /* Name.Other */ +html[data-theme="dark"] .highlight .py { color: #00e0e0 } /* Name.Property */ +html[data-theme="dark"] .highlight .nt { color: #00e0e0 } /* Name.Tag */ +html[data-theme="dark"] .highlight .nv { color: #ffa07a } /* Name.Variable */ +html[data-theme="dark"] .highlight .ow { color: #dcc6e0 } /* Operator.Word */ +html[data-theme="dark"] .highlight .pm { color: #f8f8f2 } /* Punctuation.Marker */ +html[data-theme="dark"] .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ +html[data-theme="dark"] .highlight .mb { color: #ffd900 } /* Literal.Number.Bin */ +html[data-theme="dark"] .highlight .mf { color: #ffd900 } /* Literal.Number.Float */ +html[data-theme="dark"] .highlight .mh { color: #ffd900 } /* Literal.Number.Hex */ +html[data-theme="dark"] .highlight .mi { color: #ffd900 } /* Literal.Number.Integer */ +html[data-theme="dark"] .highlight .mo { color: #ffd900 } /* Literal.Number.Oct */ +html[data-theme="dark"] .highlight .sa { color: #abe338 } /* Literal.String.Affix */ +html[data-theme="dark"] .highlight .sb { color: #abe338 } /* Literal.String.Backtick */ +html[data-theme="dark"] .highlight .sc { color: #abe338 } /* Literal.String.Char */ +html[data-theme="dark"] .highlight .dl { color: #abe338 } /* Literal.String.Delimiter */ +html[data-theme="dark"] .highlight .sd { color: #abe338 } /* Literal.String.Doc */ +html[data-theme="dark"] .highlight .s2 { color: #abe338 } /* Literal.String.Double */ +html[data-theme="dark"] .highlight .se { color: #abe338 } /* Literal.String.Escape */ +html[data-theme="dark"] .highlight .sh { color: #abe338 } /* Literal.String.Heredoc */ +html[data-theme="dark"] .highlight .si { color: #abe338 } /* Literal.String.Interpol */ +html[data-theme="dark"] .highlight .sx { color: #abe338 } /* Literal.String.Other */ +html[data-theme="dark"] .highlight .sr { color: #ffa07a } /* Literal.String.Regex */ +html[data-theme="dark"] .highlight .s1 { color: #abe338 } /* Literal.String.Single */ +html[data-theme="dark"] .highlight .ss { color: #00e0e0 } /* Literal.String.Symbol */ +html[data-theme="dark"] .highlight .bp { color: #ffd900 } /* Name.Builtin.Pseudo */ +html[data-theme="dark"] .highlight .fm { color: #00e0e0 } /* Name.Function.Magic */ +html[data-theme="dark"] .highlight .vc { color: #ffa07a } /* Name.Variable.Class */ +html[data-theme="dark"] .highlight .vg { color: #ffa07a } /* Name.Variable.Global */ +html[data-theme="dark"] .highlight .vi { color: #ffa07a } /* Name.Variable.Instance */ +html[data-theme="dark"] .highlight .vm { color: #ffd900 } /* Name.Variable.Magic */ +html[data-theme="dark"] .highlight .il { color: #ffd900 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/0.7.5/_static/scanspec-logo.svg b/0.7.5/_static/scanspec-logo.svg new file mode 100644 index 00000000..9ec265a0 --- /dev/null +++ b/0.7.5/_static/scanspec-logo.svg @@ -0,0 +1,363 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/0.7.5/_static/scripts/bootstrap.js b/0.7.5/_static/scripts/bootstrap.js new file mode 100644 index 00000000..c8178deb --- /dev/null +++ b/0.7.5/_static/scripts/bootstrap.js @@ -0,0 +1,3 @@ +/*! For license information please see bootstrap.js.LICENSE.txt */ +(()=>{"use strict";var t={d:(e,i)=>{for(var n in i)t.o(i,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:i[n]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{afterMain:()=>E,afterRead:()=>v,afterWrite:()=>C,applyStyles:()=>$,arrow:()=>J,auto:()=>a,basePlacements:()=>l,beforeMain:()=>y,beforeRead:()=>_,beforeWrite:()=>A,bottom:()=>s,clippingParents:()=>d,computeStyles:()=>it,createPopper:()=>Dt,createPopperBase:()=>St,createPopperLite:()=>$t,detectOverflow:()=>_t,end:()=>h,eventListeners:()=>st,flip:()=>bt,hide:()=>wt,left:()=>r,main:()=>w,modifierPhases:()=>O,offset:()=>Et,placements:()=>g,popper:()=>f,popperGenerator:()=>Lt,popperOffsets:()=>At,preventOverflow:()=>Tt,read:()=>b,reference:()=>p,right:()=>o,start:()=>c,top:()=>n,variationPlacements:()=>m,viewport:()=>u,write:()=>T});var i={};t.r(i),t.d(i,{Alert:()=>Oe,Button:()=>ke,Carousel:()=>li,Collapse:()=>Ei,Dropdown:()=>Ki,Modal:()=>Ln,Offcanvas:()=>Kn,Popover:()=>bs,ScrollSpy:()=>Ls,Tab:()=>Js,Toast:()=>po,Tooltip:()=>fs});var n="top",s="bottom",o="right",r="left",a="auto",l=[n,s,o,r],c="start",h="end",d="clippingParents",u="viewport",f="popper",p="reference",m=l.reduce((function(t,e){return t.concat([e+"-"+c,e+"-"+h])}),[]),g=[].concat(l,[a]).reduce((function(t,e){return t.concat([e,e+"-"+c,e+"-"+h])}),[]),_="beforeRead",b="read",v="afterRead",y="beforeMain",w="main",E="afterMain",A="beforeWrite",T="write",C="afterWrite",O=[_,b,v,y,w,E,A,T,C];function x(t){return t?(t.nodeName||"").toLowerCase():null}function k(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function L(t){return t instanceof k(t).Element||t instanceof Element}function S(t){return t instanceof k(t).HTMLElement||t instanceof HTMLElement}function D(t){return"undefined"!=typeof ShadowRoot&&(t instanceof k(t).ShadowRoot||t instanceof ShadowRoot)}const $={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];S(s)&&x(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}),{});S(n)&&x(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function I(t){return t.split("-")[0]}var N=Math.max,P=Math.min,M=Math.round;function j(){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 F(){return!/^((?!chrome|android).)*safari/i.test(j())}function H(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&S(t)&&(s=t.offsetWidth>0&&M(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&M(n.height)/t.offsetHeight||1);var r=(L(t)?k(t):window).visualViewport,a=!F()&&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 B(t){var e=H(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 W(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&D(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function z(t){return k(t).getComputedStyle(t)}function R(t){return["table","td","th"].indexOf(x(t))>=0}function q(t){return((L(t)?t.ownerDocument:t.document)||window.document).documentElement}function V(t){return"html"===x(t)?t:t.assignedSlot||t.parentNode||(D(t)?t.host:null)||q(t)}function Y(t){return S(t)&&"fixed"!==z(t).position?t.offsetParent:null}function K(t){for(var e=k(t),i=Y(t);i&&R(i)&&"static"===z(i).position;)i=Y(i);return i&&("html"===x(i)||"body"===x(i)&&"static"===z(i).position)?e:i||function(t){var e=/firefox/i.test(j());if(/Trident/i.test(j())&&S(t)&&"fixed"===z(t).position)return null;var i=V(t);for(D(i)&&(i=i.host);S(i)&&["html","body"].indexOf(x(i))<0;){var n=z(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 Q(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function X(t,e,i){return N(t,P(e,i))}function U(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function G(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const J={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,a=t.name,c=t.options,h=i.elements.arrow,d=i.modifiersData.popperOffsets,u=I(i.placement),f=Q(u),p=[r,o].indexOf(u)>=0?"height":"width";if(h&&d){var m=function(t,e){return U("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:G(t,l))}(c.padding,i),g=B(h),_="y"===f?n:r,b="y"===f?s:o,v=i.rects.reference[p]+i.rects.reference[f]-d[f]-i.rects.popper[p],y=d[f]-i.rects.reference[f],w=K(h),E=w?"y"===f?w.clientHeight||0:w.clientWidth||0:0,A=v/2-y/2,T=m[_],C=E-g[p]-m[b],O=E/2-g[p]/2+A,x=X(T,O,C),k=f;i.modifiersData[a]=((e={})[k]=x,e.centerOffset=x-O,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)))&&W(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Z(t){return t.split("-")[1]}var tt={top:"auto",right:"auto",bottom:"auto",left:"auto"};function et(t){var e,i=t.popper,a=t.popperRect,l=t.placement,c=t.variation,d=t.offsets,u=t.position,f=t.gpuAcceleration,p=t.adaptive,m=t.roundOffsets,g=t.isFixed,_=d.x,b=void 0===_?0:_,v=d.y,y=void 0===v?0:v,w="function"==typeof m?m({x:b,y}):{x:b,y};b=w.x,y=w.y;var E=d.hasOwnProperty("x"),A=d.hasOwnProperty("y"),T=r,C=n,O=window;if(p){var x=K(i),L="clientHeight",S="clientWidth";x===k(i)&&"static"!==z(x=q(i)).position&&"absolute"===u&&(L="scrollHeight",S="scrollWidth"),(l===n||(l===r||l===o)&&c===h)&&(C=s,y-=(g&&x===O&&O.visualViewport?O.visualViewport.height:x[L])-a.height,y*=f?1:-1),l!==r&&(l!==n&&l!==s||c!==h)||(T=o,b-=(g&&x===O&&O.visualViewport?O.visualViewport.width:x[S])-a.width,b*=f?1:-1)}var D,$=Object.assign({position:u},p&&tt),I=!0===m?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:M(i*s)/s||0,y:M(n*s)/s||0}}({x:b,y},k(i)):{x:b,y};return b=I.x,y=I.y,f?Object.assign({},$,((D={})[C]=A?"0":"",D[T]=E?"0":"",D.transform=(O.devicePixelRatio||1)<=1?"translate("+b+"px, "+y+"px)":"translate3d("+b+"px, "+y+"px, 0)",D)):Object.assign({},$,((e={})[C]=A?y+"px":"",e[T]=E?b+"px":"",e.transform="",e))}const it={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:I(e.placement),variation:Z(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,et(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,et(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 nt={passive:!0};const st={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=k(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,nt)})),a&&l.addEventListener("resize",i.update,nt),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,nt)})),a&&l.removeEventListener("resize",i.update,nt)}},data:{}};var ot={left:"right",right:"left",bottom:"top",top:"bottom"};function rt(t){return t.replace(/left|right|bottom|top/g,(function(t){return ot[t]}))}var at={start:"end",end:"start"};function lt(t){return t.replace(/start|end/g,(function(t){return at[t]}))}function ct(t){var e=k(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ht(t){return H(q(t)).left+ct(t).scrollLeft}function dt(t){var e=z(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function ut(t){return["html","body","#document"].indexOf(x(t))>=0?t.ownerDocument.body:S(t)&&dt(t)?t:ut(V(t))}function ft(t,e){var i;void 0===e&&(e=[]);var n=ut(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=k(n),r=s?[o].concat(o.visualViewport||[],dt(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(ft(V(r)))}function pt(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function mt(t,e,i){return e===u?pt(function(t,e){var i=k(t),n=q(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=F();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+ht(t),y:l}}(t,i)):L(e)?function(t,e){var i=H(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):pt(function(t){var e,i=q(t),n=ct(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=N(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=N(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ht(t),l=-n.scrollTop;return"rtl"===z(s||i).direction&&(a+=N(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(q(t)))}function gt(t){var e,i=t.reference,a=t.element,l=t.placement,d=l?I(l):null,u=l?Z(l):null,f=i.x+i.width/2-a.width/2,p=i.y+i.height/2-a.height/2;switch(d){case n:e={x:f,y:i.y-a.height};break;case s:e={x:f,y:i.y+i.height};break;case o:e={x:i.x+i.width,y:p};break;case r:e={x:i.x-a.width,y:p};break;default:e={x:i.x,y:i.y}}var m=d?Q(d):null;if(null!=m){var g="y"===m?"height":"width";switch(u){case c:e[m]=e[m]-(i[g]/2-a[g]/2);break;case h:e[m]=e[m]+(i[g]/2-a[g]/2)}}return e}function _t(t,e){void 0===e&&(e={});var i=e,r=i.placement,a=void 0===r?t.placement:r,c=i.strategy,h=void 0===c?t.strategy:c,m=i.boundary,g=void 0===m?d:m,_=i.rootBoundary,b=void 0===_?u:_,v=i.elementContext,y=void 0===v?f:v,w=i.altBoundary,E=void 0!==w&&w,A=i.padding,T=void 0===A?0:A,C=U("number"!=typeof T?T:G(T,l)),O=y===f?p:f,k=t.rects.popper,D=t.elements[E?O:y],$=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=ft(V(t)),i=["absolute","fixed"].indexOf(z(t).position)>=0&&S(t)?K(t):t;return L(i)?e.filter((function(t){return L(t)&&W(t,i)&&"body"!==x(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=mt(t,i,n);return e.top=N(s.top,e.top),e.right=P(s.right,e.right),e.bottom=P(s.bottom,e.bottom),e.left=N(s.left,e.left),e}),mt(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}(L(D)?D:D.contextElement||q(t.elements.popper),g,b,h),I=H(t.elements.reference),M=gt({reference:I,element:k,strategy:"absolute",placement:a}),j=pt(Object.assign({},k,M)),F=y===f?j:I,B={top:$.top-F.top+C.top,bottom:F.bottom-$.bottom+C.bottom,left:$.left-F.left+C.left,right:F.right-$.right+C.right},R=t.modifiersData.offset;if(y===f&&R){var Y=R[a];Object.keys(B).forEach((function(t){var e=[o,s].indexOf(t)>=0?1:-1,i=[n,s].indexOf(t)>=0?"y":"x";B[t]+=Y[i]*e}))}return B}const bt={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,h=t.name;if(!e.modifiersData[h]._skip){for(var d=i.mainAxis,u=void 0===d||d,f=i.altAxis,p=void 0===f||f,_=i.fallbackPlacements,b=i.padding,v=i.boundary,y=i.rootBoundary,w=i.altBoundary,E=i.flipVariations,A=void 0===E||E,T=i.allowedAutoPlacements,C=e.options.placement,O=I(C),x=_||(O!==C&&A?function(t){if(I(t)===a)return[];var e=rt(t);return[lt(t),e,lt(e)]}(C):[rt(C)]),k=[C].concat(x).reduce((function(t,i){return t.concat(I(i)===a?function(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,c=i.allowedAutoPlacements,h=void 0===c?g:c,d=Z(n),u=d?a?m:m.filter((function(t){return Z(t)===d})):l,f=u.filter((function(t){return h.indexOf(t)>=0}));0===f.length&&(f=u);var p=f.reduce((function(e,i){return e[i]=_t(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[I(i)],e}),{});return Object.keys(p).sort((function(t,e){return p[t]-p[e]}))}(e,{placement:i,boundary:v,rootBoundary:y,padding:b,flipVariations:A,allowedAutoPlacements:T}):i)}),[]),L=e.rects.reference,S=e.rects.popper,D=new Map,$=!0,N=k[0],P=0;P=0,B=H?"width":"height",W=_t(e,{placement:M,boundary:v,rootBoundary:y,altBoundary:w,padding:b}),z=H?F?o:r:F?s:n;L[B]>S[B]&&(z=rt(z));var R=rt(z),q=[];if(u&&q.push(W[j]<=0),p&&q.push(W[z]<=0,W[R]<=0),q.every((function(t){return t}))){N=M,$=!1;break}D.set(M,q)}if($)for(var V=function(t){var e=k.find((function(e){var i=D.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return N=e,"break"},Y=A?3:1;Y>0&&"break"!==V(Y);Y--);e.placement!==N&&(e.modifiersData[h]._skip=!0,e.placement=N,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function vt(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 yt(t){return[n,o,s,r].some((function(e){return t[e]>=0}))}const wt={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=_t(e,{elementContext:"reference"}),a=_t(e,{altBoundary:!0}),l=vt(r,n),c=vt(a,s,o),h=yt(l),d=yt(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})}},Et={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,s=t.name,a=i.offset,l=void 0===a?[0,0]:a,c=g.reduce((function(t,i){return t[i]=function(t,e,i){var s=I(t),a=[r,n].indexOf(s)>=0?-1:1,l="function"==typeof i?i(Object.assign({},e,{placement:t})):i,c=l[0],h=l[1];return c=c||0,h=(h||0)*a,[r,o].indexOf(s)>=0?{x:h,y:c}:{x:c,y:h}}(i,e.rects,l),t}),{}),h=c[e.placement],d=h.x,u=h.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=d,e.modifiersData.popperOffsets.y+=u),e.modifiersData[s]=c}},At={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=gt({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},Tt={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,a=t.name,l=i.mainAxis,h=void 0===l||l,d=i.altAxis,u=void 0!==d&&d,f=i.boundary,p=i.rootBoundary,m=i.altBoundary,g=i.padding,_=i.tether,b=void 0===_||_,v=i.tetherOffset,y=void 0===v?0:v,w=_t(e,{boundary:f,rootBoundary:p,padding:g,altBoundary:m}),E=I(e.placement),A=Z(e.placement),T=!A,C=Q(E),O="x"===C?"y":"x",x=e.modifiersData.popperOffsets,k=e.rects.reference,L=e.rects.popper,S="function"==typeof y?y(Object.assign({},e.rects,{placement:e.placement})):y,D="number"==typeof S?{mainAxis:S,altAxis:S}:Object.assign({mainAxis:0,altAxis:0},S),$=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,M={x:0,y:0};if(x){if(h){var j,F="y"===C?n:r,H="y"===C?s:o,W="y"===C?"height":"width",z=x[C],R=z+w[F],q=z-w[H],V=b?-L[W]/2:0,Y=A===c?k[W]:L[W],U=A===c?-L[W]:-k[W],G=e.elements.arrow,J=b&&G?B(G):{width:0,height:0},tt=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},et=tt[F],it=tt[H],nt=X(0,k[W],J[W]),st=T?k[W]/2-V-nt-et-D.mainAxis:Y-nt-et-D.mainAxis,ot=T?-k[W]/2+V+nt+it+D.mainAxis:U+nt+it+D.mainAxis,rt=e.elements.arrow&&K(e.elements.arrow),at=rt?"y"===C?rt.clientTop||0:rt.clientLeft||0:0,lt=null!=(j=null==$?void 0:$[C])?j:0,ct=z+ot-lt,ht=X(b?P(R,z+st-lt-at):R,z,b?N(q,ct):q);x[C]=ht,M[C]=ht-z}if(u){var dt,ut="x"===C?n:r,ft="x"===C?s:o,pt=x[O],mt="y"===O?"height":"width",gt=pt+w[ut],bt=pt-w[ft],vt=-1!==[n,r].indexOf(E),yt=null!=(dt=null==$?void 0:$[O])?dt:0,wt=vt?gt:pt-k[mt]-L[mt]-yt+D.altAxis,Et=vt?pt+k[mt]+L[mt]-yt-D.altAxis:bt,At=b&&vt?function(t,e,i){var n=X(t,e,i);return n>i?i:n}(wt,pt,Et):X(b?wt:gt,pt,b?Et:bt);x[O]=At,M[O]=At-pt}e.modifiersData[a]=M}},requiresIfExists:["offset"]};function Ct(t,e,i){void 0===i&&(i=!1);var n,s,o=S(e),r=S(e)&&function(t){var e=t.getBoundingClientRect(),i=M(e.width)/t.offsetWidth||1,n=M(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=q(e),l=H(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==x(e)||dt(a))&&(c=(n=e)!==k(n)&&S(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:ct(n)),S(e)?((h=H(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=ht(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function Ot(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 xt={placement:"bottom",modifiers:[],strategy:"absolute"};function kt(){for(var t=arguments.length,e=new Array(t),i=0;iIt.has(t)&&It.get(t).get(e)||null,remove(t,e){if(!It.has(t))return;const i=It.get(t);i.delete(e),0===i.size&&It.delete(t)}},Pt="transitionend",Mt=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),jt=t=>{t.dispatchEvent(new Event(Pt))},Ft=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),Ht=t=>Ft(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(Mt(t)):null,Bt=t=>{if(!Ft(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},Wt=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),zt=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?zt(t.parentNode):null},Rt=()=>{},qt=t=>{t.offsetHeight},Vt=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,Yt=[],Kt=()=>"rtl"===document.documentElement.dir,Qt=t=>{var e;e=()=>{const e=Vt();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?(Yt.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of Yt)t()})),Yt.push(e)):e()},Xt=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,Ut=(t,e,i=!0)=>{if(!i)return void Xt(t);const n=(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 s=!1;const o=({target:i})=>{i===e&&(s=!0,e.removeEventListener(Pt,o),Xt(t))};e.addEventListener(Pt,o),setTimeout((()=>{s||jt(e)}),n)},Gt=(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))])},Jt=/[^.]*(?=\..*)\.|.*/,Zt=/\..*/,te=/::\d+$/,ee={};let ie=1;const ne={mouseenter:"mouseover",mouseleave:"mouseout"},se=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 oe(t,e){return e&&`${e}::${ie++}`||t.uidEvent||ie++}function re(t){const e=oe(t);return t.uidEvent=e,ee[e]=ee[e]||{},ee[e]}function ae(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function le(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=ue(t);return se.has(o)||(o=t),[n,s,o]}function ce(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=le(e,i,n);if(e in ne){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=re(t),c=l[a]||(l[a]={}),h=ae(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=oe(r,e.replace(Jt,"")),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 pe(s,{delegateTarget:r}),n.oneOff&&fe.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return pe(n,{delegateTarget:t}),i.oneOff&&fe.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 he(t,e,i,n,s){const o=ae(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function de(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&he(t,e,i,r.callable,r.delegationSelector)}function ue(t){return t=t.replace(Zt,""),ne[t]||t}const fe={on(t,e,i,n){ce(t,e,i,n,!1)},one(t,e,i,n){ce(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=le(e,i,n),a=r!==e,l=re(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))de(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(te,"");a&&!e.includes(s)||he(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;he(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=Vt();let s=null,o=!0,r=!0,a=!1;e!==ue(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=pe(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function pe(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 me(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 ge(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const _e={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${ge(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${ge(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]=me(t.dataset[n])}return e},getDataAttribute:(t,e)=>me(t.getAttribute(`data-bs-${ge(e)}`))};class be{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=Ft(e)?_e.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...Ft(e)?_e.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],o=Ft(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(o))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${o}" but expected type "${s}".`)}var i}}class ve extends be{constructor(t,e){super(),(t=Ht(t))&&(this._element=t,this._config=this._getConfig(e),Nt.set(this._element,this.constructor.DATA_KEY,this))}dispose(){Nt.remove(this._element,this.constructor.DATA_KEY),fe.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){Ut(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return Nt.get(Ht(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.3"}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 ye=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 e?e.split(",").map((t=>Mt(t))).join(","):null},we={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=>!Wt(t)&&Bt(t)))},getSelectorFromElement(t){const e=ye(t);return e&&we.findOne(e)?e:null},getElementFromSelector(t){const e=ye(t);return e?we.findOne(e):null},getMultipleElementsFromSelector(t){const e=ye(t);return e?we.find(e):[]}},Ee=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;fe.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),Wt(this))return;const s=we.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},Ae=".bs.alert",Te=`close${Ae}`,Ce=`closed${Ae}`;class Oe extends ve{static get NAME(){return"alert"}close(){if(fe.trigger(this._element,Te).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(),fe.trigger(this._element,Ce),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Oe.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)}}))}}Ee(Oe,"close"),Qt(Oe);const xe='[data-bs-toggle="button"]';class ke extends ve{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=ke.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}fe.on(document,"click.bs.button.data-api",xe,(t=>{t.preventDefault();const e=t.target.closest(xe);ke.getOrCreateInstance(e).toggle()})),Qt(ke);const Le=".bs.swipe",Se=`touchstart${Le}`,De=`touchmove${Le}`,$e=`touchend${Le}`,Ie=`pointerdown${Le}`,Ne=`pointerup${Le}`,Pe={endCallback:null,leftCallback:null,rightCallback:null},Me={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class je extends be{constructor(t,e){super(),this._element=t,t&&je.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return Pe}static get DefaultType(){return Me}static get NAME(){return"swipe"}dispose(){fe.off(this._element,Le)}_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(),Xt(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&&Xt(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(fe.on(this._element,Ie,(t=>this._start(t))),fe.on(this._element,Ne,(t=>this._end(t))),this._element.classList.add("pointer-event")):(fe.on(this._element,Se,(t=>this._start(t))),fe.on(this._element,De,(t=>this._move(t))),fe.on(this._element,$e,(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 Fe=".bs.carousel",He=".data-api",Be="ArrowLeft",We="ArrowRight",ze="next",Re="prev",qe="left",Ve="right",Ye=`slide${Fe}`,Ke=`slid${Fe}`,Qe=`keydown${Fe}`,Xe=`mouseenter${Fe}`,Ue=`mouseleave${Fe}`,Ge=`dragstart${Fe}`,Je=`load${Fe}${He}`,Ze=`click${Fe}${He}`,ti="carousel",ei="active",ii=".active",ni=".carousel-item",si=ii+ni,oi={[Be]:Ve,[We]:qe},ri={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},ai={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class li extends ve{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=we.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===ti&&this.cycle()}static get Default(){return ri}static get DefaultType(){return ai}static get NAME(){return"carousel"}next(){this._slide(ze)}nextWhenVisible(){!document.hidden&&Bt(this._element)&&this.next()}prev(){this._slide(Re)}pause(){this._isSliding&&jt(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?fe.one(this._element,Ke,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void fe.one(this._element,Ke,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?ze:Re;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&&fe.on(this._element,Qe,(t=>this._keydown(t))),"hover"===this._config.pause&&(fe.on(this._element,Xe,(()=>this.pause())),fe.on(this._element,Ue,(()=>this._maybeEnableCycle()))),this._config.touch&&je.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of we.find(".carousel-item img",this._element))fe.on(t,Ge,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(qe)),rightCallback:()=>this._slide(this._directionToOrder(Ve)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new je(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=oi[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=we.findOne(ii,this._indicatorsElement);e.classList.remove(ei),e.removeAttribute("aria-current");const i=we.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(ei),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===ze,s=e||Gt(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>fe.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(Ye).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),qt(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(ei),i.classList.remove(ei,c,l),this._isSliding=!1,r(Ke)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return we.findOne(si,this._element)}_getItems(){return we.find(ni,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return Kt()?t===qe?Re:ze:t===qe?ze:Re}_orderToDirection(t){return Kt()?t===Re?qe:Ve:t===Re?Ve:qe}static jQueryInterface(t){return this.each((function(){const e=li.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)}))}}fe.on(document,Ze,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=we.getElementFromSelector(this);if(!e||!e.classList.contains(ti))return;t.preventDefault();const i=li.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===_e.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),fe.on(window,Je,(()=>{const t=we.find('[data-bs-ride="carousel"]');for(const e of t)li.getOrCreateInstance(e)})),Qt(li);const ci=".bs.collapse",hi=`show${ci}`,di=`shown${ci}`,ui=`hide${ci}`,fi=`hidden${ci}`,pi=`click${ci}.data-api`,mi="show",gi="collapse",_i="collapsing",bi=`:scope .${gi} .${gi}`,vi='[data-bs-toggle="collapse"]',yi={parent:null,toggle:!0},wi={parent:"(null|element)",toggle:"boolean"};class Ei extends ve{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=we.find(vi);for(const t of i){const e=we.getSelectorFromElement(t),i=we.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 yi}static get DefaultType(){return wi}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=>Ei.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(fe.trigger(this._element,hi).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(gi),this._element.classList.add(_i),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(_i),this._element.classList.add(gi,mi),this._element.style[e]="",fe.trigger(this._element,di)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(fe.trigger(this._element,ui).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,qt(this._element),this._element.classList.add(_i),this._element.classList.remove(gi,mi);for(const t of this._triggerArray){const e=we.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(_i),this._element.classList.add(gi),fe.trigger(this._element,fi)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(mi)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=Ht(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(vi);for(const e of t){const t=we.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=we.find(bi,this._config.parent);return we.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=Ei.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}fe.on(document,pi,vi,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of we.getMultipleElementsFromSelector(this))Ei.getOrCreateInstance(t,{toggle:!1}).toggle()})),Qt(Ei);const Ai="dropdown",Ti=".bs.dropdown",Ci=".data-api",Oi="ArrowUp",xi="ArrowDown",ki=`hide${Ti}`,Li=`hidden${Ti}`,Si=`show${Ti}`,Di=`shown${Ti}`,$i=`click${Ti}${Ci}`,Ii=`keydown${Ti}${Ci}`,Ni=`keyup${Ti}${Ci}`,Pi="show",Mi='[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)',ji=`${Mi}.${Pi}`,Fi=".dropdown-menu",Hi=Kt()?"top-end":"top-start",Bi=Kt()?"top-start":"top-end",Wi=Kt()?"bottom-end":"bottom-start",zi=Kt()?"bottom-start":"bottom-end",Ri=Kt()?"left-start":"right-start",qi=Kt()?"right-start":"left-start",Vi={autoClose:!0,boundary:"clippingParents",display:"dynamic",offset:[0,2],popperConfig:null,reference:"toggle"},Yi={autoClose:"(boolean|string)",boundary:"(string|element)",display:"string",offset:"(array|string|function)",popperConfig:"(null|object|function)",reference:"(string|element|object)"};class Ki extends ve{constructor(t,e){super(t,e),this._popper=null,this._parent=this._element.parentNode,this._menu=we.next(this._element,Fi)[0]||we.prev(this._element,Fi)[0]||we.findOne(Fi,this._parent),this._inNavbar=this._detectNavbar()}static get Default(){return Vi}static get DefaultType(){return Yi}static get NAME(){return Ai}toggle(){return this._isShown()?this.hide():this.show()}show(){if(Wt(this._element)||this._isShown())return;const t={relatedTarget:this._element};if(!fe.trigger(this._element,Si,t).defaultPrevented){if(this._createPopper(),"ontouchstart"in document.documentElement&&!this._parent.closest(".navbar-nav"))for(const t of[].concat(...document.body.children))fe.on(t,"mouseover",Rt);this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Pi),this._element.classList.add(Pi),fe.trigger(this._element,Di,t)}}hide(){if(Wt(this._element)||!this._isShown())return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){if(!fe.trigger(this._element,ki,t).defaultPrevented){if("ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))fe.off(t,"mouseover",Rt);this._popper&&this._popper.destroy(),this._menu.classList.remove(Pi),this._element.classList.remove(Pi),this._element.setAttribute("aria-expanded","false"),_e.removeDataAttribute(this._menu,"popper"),fe.trigger(this._element,Li,t)}}_getConfig(t){if("object"==typeof(t=super._getConfig(t)).reference&&!Ft(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ai.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(){if(void 0===e)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let t=this._element;"parent"===this._config.reference?t=this._parent:Ft(this._config.reference)?t=Ht(this._config.reference):"object"==typeof this._config.reference&&(t=this._config.reference);const i=this._getPopperConfig();this._popper=Dt(t,this._menu,i)}_isShown(){return this._menu.classList.contains(Pi)}_getPlacement(){const t=this._parent;if(t.classList.contains("dropend"))return Ri;if(t.classList.contains("dropstart"))return qi;if(t.classList.contains("dropup-center"))return"top";if(t.classList.contains("dropdown-center"))return"bottom";const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?Bi:Hi:e?zi:Wi}_detectNavbar(){return null!==this._element.closest(".navbar")}_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}_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)&&(_e.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...Xt(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=we.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>Bt(t)));i.length&&Gt(i,e,t===xi,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=Ki.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=we.find(ji);for(const i of e){const e=Ki.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=[Oi,xi].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Mi)?this:we.prev(this,Mi)[0]||we.next(this,Mi)[0]||we.findOne(Mi,t.delegateTarget.parentNode),o=Ki.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}fe.on(document,Ii,Mi,Ki.dataApiKeydownHandler),fe.on(document,Ii,Fi,Ki.dataApiKeydownHandler),fe.on(document,$i,Ki.clearMenus),fe.on(document,Ni,Ki.clearMenus),fe.on(document,$i,Mi,(function(t){t.preventDefault(),Ki.getOrCreateInstance(this).toggle()})),Qt(Ki);const Qi="backdrop",Xi="show",Ui=`mousedown.bs.${Qi}`,Gi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Ji={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Zi extends be{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Gi}static get DefaultType(){return Ji}static get NAME(){return Qi}show(t){if(!this._config.isVisible)return void Xt(t);this._append();const e=this._getElement();this._config.isAnimated&&qt(e),e.classList.add(Xi),this._emulateAnimation((()=>{Xt(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Xi),this._emulateAnimation((()=>{this.dispose(),Xt(t)}))):Xt(t)}dispose(){this._isAppended&&(fe.off(this._element,Ui),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=Ht(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),fe.on(t,Ui,(()=>{Xt(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){Ut(t,this._getElement(),this._config.isAnimated)}}const tn=".bs.focustrap",en=`focusin${tn}`,nn=`keydown.tab${tn}`,sn="backward",on={autofocus:!0,trapElement:null},rn={autofocus:"boolean",trapElement:"element"};class an extends be{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return on}static get DefaultType(){return rn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),fe.off(document,tn),fe.on(document,en,(t=>this._handleFocusin(t))),fe.on(document,nn,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,fe.off(document,tn))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=we.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===sn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?sn:"forward")}}const ln=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",cn=".sticky-top",hn="padding-right",dn="margin-right";class un{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,hn,(e=>e+t)),this._setElementAttributes(ln,hn,(e=>e+t)),this._setElementAttributes(cn,dn,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,hn),this._resetElementAttributes(ln,hn),this._resetElementAttributes(cn,dn)}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&&_e.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=_e.getDataAttribute(t,e);null!==i?(_e.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(Ft(t))e(t);else for(const i of we.find(t,this._element))e(i)}}const fn=".bs.modal",pn=`hide${fn}`,mn=`hidePrevented${fn}`,gn=`hidden${fn}`,_n=`show${fn}`,bn=`shown${fn}`,vn=`resize${fn}`,yn=`click.dismiss${fn}`,wn=`mousedown.dismiss${fn}`,En=`keydown.dismiss${fn}`,An=`click${fn}.data-api`,Tn="modal-open",Cn="show",On="modal-static",xn={backdrop:!0,focus:!0,keyboard:!0},kn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class Ln extends ve{constructor(t,e){super(t,e),this._dialog=we.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new un,this._addEventListeners()}static get Default(){return xn}static get DefaultType(){return kn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||fe.trigger(this._element,_n,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(Tn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(fe.trigger(this._element,pn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(Cn),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){fe.off(window,fn),fe.off(this._dialog,fn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Zi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new an({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=we.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),qt(this._element),this._element.classList.add(Cn),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,fe.trigger(this._element,bn,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){fe.on(this._element,En,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),fe.on(window,vn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),fe.on(this._element,wn,(t=>{fe.one(this._element,yn,(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(Tn),this._resetAdjustments(),this._scrollBar.reset(),fe.trigger(this._element,gn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(fe.trigger(this._element,mn).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(On)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(On),this._queueCallback((()=>{this._element.classList.remove(On),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=Kt()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=Kt()?"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=Ln.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}fe.on(document,An,'[data-bs-toggle="modal"]',(function(t){const e=we.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),fe.one(e,_n,(t=>{t.defaultPrevented||fe.one(e,gn,(()=>{Bt(this)&&this.focus()}))}));const i=we.findOne(".modal.show");i&&Ln.getInstance(i).hide(),Ln.getOrCreateInstance(e).toggle(this)})),Ee(Ln),Qt(Ln);const Sn=".bs.offcanvas",Dn=".data-api",$n=`load${Sn}${Dn}`,In="show",Nn="showing",Pn="hiding",Mn=".offcanvas.show",jn=`show${Sn}`,Fn=`shown${Sn}`,Hn=`hide${Sn}`,Bn=`hidePrevented${Sn}`,Wn=`hidden${Sn}`,zn=`resize${Sn}`,Rn=`click${Sn}${Dn}`,qn=`keydown.dismiss${Sn}`,Vn={backdrop:!0,keyboard:!0,scroll:!1},Yn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class Kn extends ve{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return Vn}static get DefaultType(){return Yn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||fe.trigger(this._element,jn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new un).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Nn),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(In),this._element.classList.remove(Nn),fe.trigger(this._element,Fn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(fe.trigger(this._element,Hn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(Pn),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(In,Pn),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new un).reset(),fe.trigger(this._element,Wn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Zi({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():fe.trigger(this._element,Bn)}:null})}_initializeFocusTrap(){return new an({trapElement:this._element})}_addEventListeners(){fe.on(this._element,qn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():fe.trigger(this._element,Bn))}))}static jQueryInterface(t){return this.each((function(){const e=Kn.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)}}))}}fe.on(document,Rn,'[data-bs-toggle="offcanvas"]',(function(t){const e=we.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),Wt(this))return;fe.one(e,Wn,(()=>{Bt(this)&&this.focus()}));const i=we.findOne(Mn);i&&i!==e&&Kn.getInstance(i).hide(),Kn.getOrCreateInstance(e).toggle(this)})),fe.on(window,$n,(()=>{for(const t of we.find(Mn))Kn.getOrCreateInstance(t).show()})),fe.on(window,zn,(()=>{for(const t of we.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&Kn.getOrCreateInstance(t).hide()})),Ee(Kn),Qt(Kn);const Qn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],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:[]},Xn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Un=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Gn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Xn.has(i)||Boolean(Un.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Jn={allowList:Qn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},Zn={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},ts={entry:"(string|element|function|null)",selector:"(string|element)"};class es extends be{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Jn}static get DefaultType(){return Zn}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},ts)}_setContent(t,e,i){const n=we.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?Ft(e)?this._putElementInTemplate(Ht(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)Gn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return Xt(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const is=new Set(["sanitize","allowList","sanitizeFn"]),ns="fade",ss="show",os=".tooltip-inner",rs=".modal",as="hide.bs.modal",ls="hover",cs="focus",hs={AUTO:"auto",TOP:"top",RIGHT:Kt()?"left":"right",BOTTOM:"bottom",LEFT:Kt()?"right":"left"},ds={allowList:Qn,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"},us={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 fs extends ve{constructor(t,i){if(void 0===e)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,i),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 ds}static get DefaultType(){return us}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),fe.off(this._element.closest(rs),as,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=fe.trigger(this._element,this.constructor.eventName("show")),e=(zt(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),fe.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(ss),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))fe.on(t,"mouseover",Rt);this._queueCallback((()=>{fe.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!fe.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(ss),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))fe.off(t,"mouseover",Rt);this._activeTrigger.click=!1,this._activeTrigger[cs]=!1,this._activeTrigger[ls]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),fe.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(ns,ss),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(ns),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new es({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{[os]: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(ns)}_isShown(){return this.tip&&this.tip.classList.contains(ss)}_createPopper(t){const e=Xt(this._config.placement,[this,t,this._element]),i=hs[e.toUpperCase()];return Dt(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 Xt(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,...Xt(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)fe.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===ls?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ls?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");fe.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?cs:ls]=!0,e._enter()})),fe.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?cs:ls]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},fe.on(this._element.closest(rs),as,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=_e.getDataAttributes(this._element);for(const t of Object.keys(e))is.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:Ht(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=fs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}Qt(fs);const ps=".popover-header",ms=".popover-body",gs={...fs.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},_s={...fs.DefaultType,content:"(null|string|element|function)"};class bs extends fs{static get Default(){return gs}static get DefaultType(){return _s}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{[ps]:this._getTitle(),[ms]:this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=bs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}Qt(bs);const vs=".bs.scrollspy",ys=`activate${vs}`,ws=`click${vs}`,Es=`load${vs}.data-api`,As="active",Ts="[href]",Cs=".nav-link",Os=`${Cs}, .nav-item > ${Cs}, .list-group-item`,xs={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},ks={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Ls extends ve{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 xs}static get DefaultType(){return ks}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=Ht(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&&(fe.off(this._config.target,ws),fe.on(this._config.target,ws,Ts,(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=we.find(Ts,this._config.target);for(const e of t){if(!e.hash||Wt(e))continue;const t=we.findOne(decodeURI(e.hash),this._element);Bt(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(As),this._activateParents(t),fe.trigger(this._element,ys,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))we.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(As);else for(const e of we.parents(t,".nav, .list-group"))for(const t of we.prev(e,Os))t.classList.add(As)}_clearActiveClass(t){t.classList.remove(As);const e=we.find(`${Ts}.${As}`,t);for(const t of e)t.classList.remove(As)}static jQueryInterface(t){return this.each((function(){const e=Ls.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]()}}))}}fe.on(window,Es,(()=>{for(const t of we.find('[data-bs-spy="scroll"]'))Ls.getOrCreateInstance(t)})),Qt(Ls);const Ss=".bs.tab",Ds=`hide${Ss}`,$s=`hidden${Ss}`,Is=`show${Ss}`,Ns=`shown${Ss}`,Ps=`click${Ss}`,Ms=`keydown${Ss}`,js=`load${Ss}`,Fs="ArrowLeft",Hs="ArrowRight",Bs="ArrowUp",Ws="ArrowDown",zs="Home",Rs="End",qs="active",Vs="fade",Ys="show",Ks=".dropdown-toggle",Qs=`:not(${Ks})`,Xs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Us=`.nav-link${Qs}, .list-group-item${Qs}, [role="tab"]${Qs}, ${Xs}`,Gs=`.${qs}[data-bs-toggle="tab"], .${qs}[data-bs-toggle="pill"], .${qs}[data-bs-toggle="list"]`;class Js extends ve{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),fe.on(this._element,Ms,(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?fe.trigger(e,Ds,{relatedTarget:t}):null;fe.trigger(t,Is,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(qs),this._activate(we.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),fe.trigger(t,Ns,{relatedTarget:e})):t.classList.add(Ys)}),t,t.classList.contains(Vs)))}_deactivate(t,e){t&&(t.classList.remove(qs),t.blur(),this._deactivate(we.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),fe.trigger(t,$s,{relatedTarget:e})):t.classList.remove(Ys)}),t,t.classList.contains(Vs)))}_keydown(t){if(![Fs,Hs,Bs,Ws,zs,Rs].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!Wt(t)));let i;if([zs,Rs].includes(t.key))i=e[t.key===zs?0:e.length-1];else{const n=[Hs,Ws].includes(t.key);i=Gt(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Js.getOrCreateInstance(i).show())}_getChildren(){return we.find(Us,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=we.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=we.findOne(t,i);s&&s.classList.toggle(n,e)};n(Ks,qs),n(".dropdown-menu",Ys),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(qs)}_getInnerElement(t){return t.matches(Us)?t:we.findOne(Us,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Js.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}fe.on(document,Ps,Xs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),Wt(this)||Js.getOrCreateInstance(this).show()})),fe.on(window,js,(()=>{for(const t of we.find(Gs))Js.getOrCreateInstance(t)})),Qt(Js);const Zs=".bs.toast",to=`mouseover${Zs}`,eo=`mouseout${Zs}`,io=`focusin${Zs}`,no=`focusout${Zs}`,so=`hide${Zs}`,oo=`hidden${Zs}`,ro=`show${Zs}`,ao=`shown${Zs}`,lo="hide",co="show",ho="showing",uo={animation:"boolean",autohide:"boolean",delay:"number"},fo={animation:!0,autohide:!0,delay:5e3};class po extends ve{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return fo}static get DefaultType(){return uo}static get NAME(){return"toast"}show(){fe.trigger(this._element,ro).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(lo),qt(this._element),this._element.classList.add(co,ho),this._queueCallback((()=>{this._element.classList.remove(ho),fe.trigger(this._element,ao),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(fe.trigger(this._element,so).defaultPrevented||(this._element.classList.add(ho),this._queueCallback((()=>{this._element.classList.add(lo),this._element.classList.remove(ho,co),fe.trigger(this._element,oo)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(co),super.dispose()}isShown(){return this._element.classList.contains(co)}_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(){fe.on(this._element,to,(t=>this._onInteraction(t,!0))),fe.on(this._element,eo,(t=>this._onInteraction(t,!1))),fe.on(this._element,io,(t=>this._onInteraction(t,!0))),fe.on(this._element,no,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=po.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}function mo(t){"loading"!=document.readyState?t():document.addEventListener("DOMContentLoaded",t)}Ee(po),Qt(po),mo((function(){[].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')).map((function(t){return new fs(t,{delay:{show:500,hide:100}})}))})),mo((function(){document.getElementById("pst-back-to-top").addEventListener("click",(function(){document.body.scrollTop=0,document.documentElement.scrollTop=0}))})),mo((function(){var t=document.getElementById("pst-back-to-top"),e=document.getElementsByClassName("bd-header")[0].getBoundingClientRect();window.addEventListener("scroll",(function(){this.oldScroll>this.scrollY&&this.scrollY>e.bottom?t.style.display="block":t.style.display="none",this.oldScroll=this.scrollY}))})),window.bootstrap=i})(); +//# sourceMappingURL=bootstrap.js.map \ No newline at end of file diff --git a/0.7.5/_static/scripts/bootstrap.js.LICENSE.txt b/0.7.5/_static/scripts/bootstrap.js.LICENSE.txt new file mode 100644 index 00000000..28755c2c --- /dev/null +++ b/0.7.5/_static/scripts/bootstrap.js.LICENSE.txt @@ -0,0 +1,5 @@ +/*! + * Bootstrap v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ diff --git a/0.7.5/_static/scripts/bootstrap.js.map b/0.7.5/_static/scripts/bootstrap.js.map new file mode 100644 index 00000000..e9e81589 --- /dev/null +++ b/0.7.5/_static/scripts/bootstrap.js.map @@ -0,0 +1 @@ +{"version":3,"file":"scripts/bootstrap.js","mappings":"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","sources":["webpack://pydata_sphinx_theme/webpack/bootstrap","webpack://pydata_sphinx_theme/webpack/runtime/define property getters","webpack://pydata_sphinx_theme/webpack/runtime/hasOwnProperty shorthand","webpack://pydata_sphinx_theme/webpack/runtime/make namespace object","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/enums.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getNodeName.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getWindow.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/instanceOf.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/applyStyles.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/getBasePlacement.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/math.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/userAgent.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/isLayoutViewport.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getBoundingClientRect.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getLayoutRect.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/contains.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getComputedStyle.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/isTableElement.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getDocumentElement.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getParentNode.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getOffsetParent.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/getMainAxisFromPlacement.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/within.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/mergePaddingObject.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/getFreshSideObject.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/expandToHashMap.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/arrow.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/getVariation.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/computeStyles.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/eventListeners.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/getOppositePlacement.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/getOppositeVariationPlacement.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getWindowScroll.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getWindowScrollBarX.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/isScrollParent.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getScrollParent.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/listScrollParents.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/rectToClientRect.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getClippingRect.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getViewportRect.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getDocumentRect.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/computeOffsets.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/detectOverflow.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/flip.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/computeAutoPlacement.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/hide.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/offset.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/popperOffsets.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/preventOverflow.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/getAltAxis.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getCompositeRect.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getNodeScroll.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getHTMLElementScroll.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/orderModifiers.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/createPopper.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/debounce.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/mergeByName.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/popper.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/popper-lite.js","webpack://pydata_sphinx_theme/./node_modules/bootstrap/dist/js/bootstrap.esm.js","webpack://pydata_sphinx_theme/./src/pydata_sphinx_theme/assets/scripts/mixin.js","webpack://pydata_sphinx_theme/./src/pydata_sphinx_theme/assets/scripts/bootstrap.js"],"sourcesContent":["// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","export var top = 'top';\nexport var bottom = 'bottom';\nexport var right = 'right';\nexport var left = 'left';\nexport var auto = 'auto';\nexport var basePlacements = [top, bottom, right, left];\nexport var start = 'start';\nexport var end = 'end';\nexport var clippingParents = 'clippingParents';\nexport var viewport = 'viewport';\nexport var popper = 'popper';\nexport var reference = 'reference';\nexport var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {\n return acc.concat([placement + \"-\" + start, placement + \"-\" + end]);\n}, []);\nexport var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {\n return acc.concat([placement, placement + \"-\" + start, placement + \"-\" + end]);\n}, []); // modifiers that need to read the DOM\n\nexport var beforeRead = 'beforeRead';\nexport var read = 'read';\nexport var afterRead = 'afterRead'; // pure-logic modifiers\n\nexport var beforeMain = 'beforeMain';\nexport var main = 'main';\nexport var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)\n\nexport var beforeWrite = 'beforeWrite';\nexport var write = 'write';\nexport var afterWrite = 'afterWrite';\nexport var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];","export default function getNodeName(element) {\n return element ? (element.nodeName || '').toLowerCase() : null;\n}","export default function getWindow(node) {\n if (node == null) {\n return window;\n }\n\n if (node.toString() !== '[object Window]') {\n var ownerDocument = node.ownerDocument;\n return ownerDocument ? ownerDocument.defaultView || window : window;\n }\n\n return node;\n}","import getWindow from \"./getWindow.js\";\n\nfunction isElement(node) {\n var OwnElement = getWindow(node).Element;\n return node instanceof OwnElement || node instanceof Element;\n}\n\nfunction isHTMLElement(node) {\n var OwnElement = getWindow(node).HTMLElement;\n return node instanceof OwnElement || node instanceof HTMLElement;\n}\n\nfunction isShadowRoot(node) {\n // IE 11 has no ShadowRoot\n if (typeof ShadowRoot === 'undefined') {\n return false;\n }\n\n var OwnElement = getWindow(node).ShadowRoot;\n return node instanceof OwnElement || node instanceof ShadowRoot;\n}\n\nexport { isElement, isHTMLElement, isShadowRoot };","import getNodeName from \"../dom-utils/getNodeName.js\";\nimport { isHTMLElement } from \"../dom-utils/instanceOf.js\"; // This modifier takes the styles prepared by the `computeStyles` modifier\n// and applies them to the HTMLElements such as popper and arrow\n\nfunction applyStyles(_ref) {\n var state = _ref.state;\n Object.keys(state.elements).forEach(function (name) {\n var style = state.styles[name] || {};\n var attributes = state.attributes[name] || {};\n var element = state.elements[name]; // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n } // Flow doesn't support to extend this property, but it's the most\n // effective way to apply styles to an HTMLElement\n // $FlowFixMe[cannot-write]\n\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (name) {\n var value = attributes[name];\n\n if (value === false) {\n element.removeAttribute(name);\n } else {\n element.setAttribute(name, value === true ? '' : value);\n }\n });\n });\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state;\n var initialStyles = {\n popper: {\n position: state.options.strategy,\n left: '0',\n top: '0',\n margin: '0'\n },\n arrow: {\n position: 'absolute'\n },\n reference: {}\n };\n Object.assign(state.elements.popper.style, initialStyles.popper);\n state.styles = initialStyles;\n\n if (state.elements.arrow) {\n Object.assign(state.elements.arrow.style, initialStyles.arrow);\n }\n\n return function () {\n Object.keys(state.elements).forEach(function (name) {\n var element = state.elements[name];\n var attributes = state.attributes[name] || {};\n var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them\n\n var style = styleProperties.reduce(function (style, property) {\n style[property] = '';\n return style;\n }, {}); // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n }\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (attribute) {\n element.removeAttribute(attribute);\n });\n });\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'applyStyles',\n enabled: true,\n phase: 'write',\n fn: applyStyles,\n effect: effect,\n requires: ['computeStyles']\n};","import { auto } from \"../enums.js\";\nexport default function getBasePlacement(placement) {\n return placement.split('-')[0];\n}","export var max = Math.max;\nexport var min = Math.min;\nexport var round = Math.round;","export default function getUAString() {\n var uaData = navigator.userAgentData;\n\n if (uaData != null && uaData.brands && Array.isArray(uaData.brands)) {\n return uaData.brands.map(function (item) {\n return item.brand + \"/\" + item.version;\n }).join(' ');\n }\n\n return navigator.userAgent;\n}","import getUAString from \"../utils/userAgent.js\";\nexport default function isLayoutViewport() {\n return !/^((?!chrome|android).)*safari/i.test(getUAString());\n}","import { isElement, isHTMLElement } from \"./instanceOf.js\";\nimport { round } from \"../utils/math.js\";\nimport getWindow from \"./getWindow.js\";\nimport isLayoutViewport from \"./isLayoutViewport.js\";\nexport default function getBoundingClientRect(element, includeScale, isFixedStrategy) {\n if (includeScale === void 0) {\n includeScale = false;\n }\n\n if (isFixedStrategy === void 0) {\n isFixedStrategy = false;\n }\n\n var clientRect = element.getBoundingClientRect();\n var scaleX = 1;\n var scaleY = 1;\n\n if (includeScale && isHTMLElement(element)) {\n scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1;\n scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1;\n }\n\n var _ref = isElement(element) ? getWindow(element) : window,\n visualViewport = _ref.visualViewport;\n\n var addVisualOffsets = !isLayoutViewport() && isFixedStrategy;\n var x = (clientRect.left + (addVisualOffsets && visualViewport ? visualViewport.offsetLeft : 0)) / scaleX;\n var y = (clientRect.top + (addVisualOffsets && visualViewport ? visualViewport.offsetTop : 0)) / scaleY;\n var width = clientRect.width / scaleX;\n var height = clientRect.height / scaleY;\n return {\n width: width,\n height: height,\n top: y,\n right: x + width,\n bottom: y + height,\n left: x,\n x: x,\n y: y\n };\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\"; // Returns the layout rect of an element relative to its offsetParent. Layout\n// means it doesn't take into account transforms.\n\nexport default function getLayoutRect(element) {\n var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.\n // Fixes https://github.com/popperjs/popper-core/issues/1223\n\n var width = element.offsetWidth;\n var height = element.offsetHeight;\n\n if (Math.abs(clientRect.width - width) <= 1) {\n width = clientRect.width;\n }\n\n if (Math.abs(clientRect.height - height) <= 1) {\n height = clientRect.height;\n }\n\n return {\n x: element.offsetLeft,\n y: element.offsetTop,\n width: width,\n height: height\n };\n}","import { isShadowRoot } from \"./instanceOf.js\";\nexport default function contains(parent, child) {\n var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method\n\n if (parent.contains(child)) {\n return true;\n } // then fallback to custom implementation with Shadow DOM support\n else if (rootNode && isShadowRoot(rootNode)) {\n var next = child;\n\n do {\n if (next && parent.isSameNode(next)) {\n return true;\n } // $FlowFixMe[prop-missing]: need a better way to handle this...\n\n\n next = next.parentNode || next.host;\n } while (next);\n } // Give up, the result is false\n\n\n return false;\n}","import getWindow from \"./getWindow.js\";\nexport default function getComputedStyle(element) {\n return getWindow(element).getComputedStyle(element);\n}","import getNodeName from \"./getNodeName.js\";\nexport default function isTableElement(element) {\n return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;\n}","import { isElement } from \"./instanceOf.js\";\nexport default function getDocumentElement(element) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]\n element.document) || window.document).documentElement;\n}","import getNodeName from \"./getNodeName.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport { isShadowRoot } from \"./instanceOf.js\";\nexport default function getParentNode(element) {\n if (getNodeName(element) === 'html') {\n return element;\n }\n\n return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle\n // $FlowFixMe[incompatible-return]\n // $FlowFixMe[prop-missing]\n element.assignedSlot || // step into the shadow DOM of the parent of a slotted node\n element.parentNode || ( // DOM Element detected\n isShadowRoot(element) ? element.host : null) || // ShadowRoot detected\n // $FlowFixMe[incompatible-call]: HTMLElement is a Node\n getDocumentElement(element) // fallback\n\n );\n}","import getWindow from \"./getWindow.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport { isHTMLElement, isShadowRoot } from \"./instanceOf.js\";\nimport isTableElement from \"./isTableElement.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport getUAString from \"../utils/userAgent.js\";\n\nfunction getTrueOffsetParent(element) {\n if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837\n getComputedStyle(element).position === 'fixed') {\n return null;\n }\n\n return element.offsetParent;\n} // `.offsetParent` reports `null` for fixed elements, while absolute elements\n// return the containing block\n\n\nfunction getContainingBlock(element) {\n var isFirefox = /firefox/i.test(getUAString());\n var isIE = /Trident/i.test(getUAString());\n\n if (isIE && isHTMLElement(element)) {\n // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport\n var elementCss = getComputedStyle(element);\n\n if (elementCss.position === 'fixed') {\n return null;\n }\n }\n\n var currentNode = getParentNode(element);\n\n if (isShadowRoot(currentNode)) {\n currentNode = currentNode.host;\n }\n\n while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {\n var css = getComputedStyle(currentNode); // This is non-exhaustive but covers the most common CSS properties that\n // create a containing block.\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n\n if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {\n return currentNode;\n } else {\n currentNode = currentNode.parentNode;\n }\n }\n\n return null;\n} // Gets the closest ancestor positioned element. Handles some edge cases,\n// such as table ancestors and cross browser bugs.\n\n\nexport default function getOffsetParent(element) {\n var window = getWindow(element);\n var offsetParent = getTrueOffsetParent(element);\n\n while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === 'static') {\n offsetParent = getTrueOffsetParent(offsetParent);\n }\n\n if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static')) {\n return window;\n }\n\n return offsetParent || getContainingBlock(element) || window;\n}","export default function getMainAxisFromPlacement(placement) {\n return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';\n}","import { max as mathMax, min as mathMin } from \"./math.js\";\nexport function within(min, value, max) {\n return mathMax(min, mathMin(value, max));\n}\nexport function withinMaxClamp(min, value, max) {\n var v = within(min, value, max);\n return v > max ? max : v;\n}","import getFreshSideObject from \"./getFreshSideObject.js\";\nexport default function mergePaddingObject(paddingObject) {\n return Object.assign({}, getFreshSideObject(), paddingObject);\n}","export default function getFreshSideObject() {\n return {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0\n };\n}","export default function expandToHashMap(value, keys) {\n return keys.reduce(function (hashMap, key) {\n hashMap[key] = value;\n return hashMap;\n }, {});\n}","import getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getLayoutRect from \"../dom-utils/getLayoutRect.js\";\nimport contains from \"../dom-utils/contains.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport getMainAxisFromPlacement from \"../utils/getMainAxisFromPlacement.js\";\nimport { within } from \"../utils/within.js\";\nimport mergePaddingObject from \"../utils/mergePaddingObject.js\";\nimport expandToHashMap from \"../utils/expandToHashMap.js\";\nimport { left, right, basePlacements, top, bottom } from \"../enums.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar toPaddingObject = function toPaddingObject(padding, state) {\n padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {\n placement: state.placement\n })) : padding;\n return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n};\n\nfunction arrow(_ref) {\n var _state$modifiersData$;\n\n var state = _ref.state,\n name = _ref.name,\n options = _ref.options;\n var arrowElement = state.elements.arrow;\n var popperOffsets = state.modifiersData.popperOffsets;\n var basePlacement = getBasePlacement(state.placement);\n var axis = getMainAxisFromPlacement(basePlacement);\n var isVertical = [left, right].indexOf(basePlacement) >= 0;\n var len = isVertical ? 'height' : 'width';\n\n if (!arrowElement || !popperOffsets) {\n return;\n }\n\n var paddingObject = toPaddingObject(options.padding, state);\n var arrowRect = getLayoutRect(arrowElement);\n var minProp = axis === 'y' ? top : left;\n var maxProp = axis === 'y' ? bottom : right;\n var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];\n var startDiff = popperOffsets[axis] - state.rects.reference[axis];\n var arrowOffsetParent = getOffsetParent(arrowElement);\n var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;\n var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is\n // outside of the popper bounds\n\n var min = paddingObject[minProp];\n var max = clientSize - arrowRect[len] - paddingObject[maxProp];\n var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;\n var offset = within(min, center, max); // Prevents breaking syntax highlighting...\n\n var axisProp = axis;\n state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state,\n options = _ref2.options;\n var _options$element = options.element,\n arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element;\n\n if (arrowElement == null) {\n return;\n } // CSS selector\n\n\n if (typeof arrowElement === 'string') {\n arrowElement = state.elements.popper.querySelector(arrowElement);\n\n if (!arrowElement) {\n return;\n }\n }\n\n if (!contains(state.elements.popper, arrowElement)) {\n return;\n }\n\n state.elements.arrow = arrowElement;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'arrow',\n enabled: true,\n phase: 'main',\n fn: arrow,\n effect: effect,\n requires: ['popperOffsets'],\n requiresIfExists: ['preventOverflow']\n};","export default function getVariation(placement) {\n return placement.split('-')[1];\n}","import { top, left, right, bottom, end } from \"../enums.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport getWindow from \"../dom-utils/getWindow.js\";\nimport getDocumentElement from \"../dom-utils/getDocumentElement.js\";\nimport getComputedStyle from \"../dom-utils/getComputedStyle.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getVariation from \"../utils/getVariation.js\";\nimport { round } from \"../utils/math.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar unsetSides = {\n top: 'auto',\n right: 'auto',\n bottom: 'auto',\n left: 'auto'\n}; // Round the offsets to the nearest suitable subpixel based on the DPR.\n// Zooming can change the DPR, but it seems to report a value that will\n// cleanly divide the values into the appropriate subpixels.\n\nfunction roundOffsetsByDPR(_ref, win) {\n var x = _ref.x,\n y = _ref.y;\n var dpr = win.devicePixelRatio || 1;\n return {\n x: round(x * dpr) / dpr || 0,\n y: round(y * dpr) / dpr || 0\n };\n}\n\nexport function mapToStyles(_ref2) {\n var _Object$assign2;\n\n var popper = _ref2.popper,\n popperRect = _ref2.popperRect,\n placement = _ref2.placement,\n variation = _ref2.variation,\n offsets = _ref2.offsets,\n position = _ref2.position,\n gpuAcceleration = _ref2.gpuAcceleration,\n adaptive = _ref2.adaptive,\n roundOffsets = _ref2.roundOffsets,\n isFixed = _ref2.isFixed;\n var _offsets$x = offsets.x,\n x = _offsets$x === void 0 ? 0 : _offsets$x,\n _offsets$y = offsets.y,\n y = _offsets$y === void 0 ? 0 : _offsets$y;\n\n var _ref3 = typeof roundOffsets === 'function' ? roundOffsets({\n x: x,\n y: y\n }) : {\n x: x,\n y: y\n };\n\n x = _ref3.x;\n y = _ref3.y;\n var hasX = offsets.hasOwnProperty('x');\n var hasY = offsets.hasOwnProperty('y');\n var sideX = left;\n var sideY = top;\n var win = window;\n\n if (adaptive) {\n var offsetParent = getOffsetParent(popper);\n var heightProp = 'clientHeight';\n var widthProp = 'clientWidth';\n\n if (offsetParent === getWindow(popper)) {\n offsetParent = getDocumentElement(popper);\n\n if (getComputedStyle(offsetParent).position !== 'static' && position === 'absolute') {\n heightProp = 'scrollHeight';\n widthProp = 'scrollWidth';\n }\n } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it\n\n\n offsetParent = offsetParent;\n\n if (placement === top || (placement === left || placement === right) && variation === end) {\n sideY = bottom;\n var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing]\n offsetParent[heightProp];\n y -= offsetY - popperRect.height;\n y *= gpuAcceleration ? 1 : -1;\n }\n\n if (placement === left || (placement === top || placement === bottom) && variation === end) {\n sideX = right;\n var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing]\n offsetParent[widthProp];\n x -= offsetX - popperRect.width;\n x *= gpuAcceleration ? 1 : -1;\n }\n }\n\n var commonStyles = Object.assign({\n position: position\n }, adaptive && unsetSides);\n\n var _ref4 = roundOffsets === true ? roundOffsetsByDPR({\n x: x,\n y: y\n }, getWindow(popper)) : {\n x: x,\n y: y\n };\n\n x = _ref4.x;\n y = _ref4.y;\n\n if (gpuAcceleration) {\n var _Object$assign;\n\n return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? \"translate(\" + x + \"px, \" + y + \"px)\" : \"translate3d(\" + x + \"px, \" + y + \"px, 0)\", _Object$assign));\n }\n\n return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + \"px\" : '', _Object$assign2[sideX] = hasX ? x + \"px\" : '', _Object$assign2.transform = '', _Object$assign2));\n}\n\nfunction computeStyles(_ref5) {\n var state = _ref5.state,\n options = _ref5.options;\n var _options$gpuAccelerat = options.gpuAcceleration,\n gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,\n _options$adaptive = options.adaptive,\n adaptive = _options$adaptive === void 0 ? true : _options$adaptive,\n _options$roundOffsets = options.roundOffsets,\n roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;\n var commonStyles = {\n placement: getBasePlacement(state.placement),\n variation: getVariation(state.placement),\n popper: state.elements.popper,\n popperRect: state.rects.popper,\n gpuAcceleration: gpuAcceleration,\n isFixed: state.options.strategy === 'fixed'\n };\n\n if (state.modifiersData.popperOffsets != null) {\n state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.popperOffsets,\n position: state.options.strategy,\n adaptive: adaptive,\n roundOffsets: roundOffsets\n })));\n }\n\n if (state.modifiersData.arrow != null) {\n state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.arrow,\n position: 'absolute',\n adaptive: false,\n roundOffsets: roundOffsets\n })));\n }\n\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-placement': state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'computeStyles',\n enabled: true,\n phase: 'beforeWrite',\n fn: computeStyles,\n data: {}\n};","import getWindow from \"../dom-utils/getWindow.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar passive = {\n passive: true\n};\n\nfunction effect(_ref) {\n var state = _ref.state,\n instance = _ref.instance,\n options = _ref.options;\n var _options$scroll = options.scroll,\n scroll = _options$scroll === void 0 ? true : _options$scroll,\n _options$resize = options.resize,\n resize = _options$resize === void 0 ? true : _options$resize;\n var window = getWindow(state.elements.popper);\n var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);\n\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.addEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.addEventListener('resize', instance.update, passive);\n }\n\n return function () {\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.removeEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.removeEventListener('resize', instance.update, passive);\n }\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'eventListeners',\n enabled: true,\n phase: 'write',\n fn: function fn() {},\n effect: effect,\n data: {}\n};","var hash = {\n left: 'right',\n right: 'left',\n bottom: 'top',\n top: 'bottom'\n};\nexport default function getOppositePlacement(placement) {\n return placement.replace(/left|right|bottom|top/g, function (matched) {\n return hash[matched];\n });\n}","var hash = {\n start: 'end',\n end: 'start'\n};\nexport default function getOppositeVariationPlacement(placement) {\n return placement.replace(/start|end/g, function (matched) {\n return hash[matched];\n });\n}","import getWindow from \"./getWindow.js\";\nexport default function getWindowScroll(node) {\n var win = getWindow(node);\n var scrollLeft = win.pageXOffset;\n var scrollTop = win.pageYOffset;\n return {\n scrollLeft: scrollLeft,\n scrollTop: scrollTop\n };\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getWindowScroll from \"./getWindowScroll.js\";\nexport default function getWindowScrollBarX(element) {\n // If has a CSS width greater than the viewport, then this will be\n // incorrect for RTL.\n // Popper 1 is broken in this case and never had a bug report so let's assume\n // it's not an issue. I don't think anyone ever specifies width on \n // anyway.\n // Browsers where the left scrollbar doesn't cause an issue report `0` for\n // this (e.g. Edge 2019, IE11, Safari)\n return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;\n}","import getComputedStyle from \"./getComputedStyle.js\";\nexport default function isScrollParent(element) {\n // Firefox wants us to check `-x` and `-y` variations as well\n var _getComputedStyle = getComputedStyle(element),\n overflow = _getComputedStyle.overflow,\n overflowX = _getComputedStyle.overflowX,\n overflowY = _getComputedStyle.overflowY;\n\n return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);\n}","import getParentNode from \"./getParentNode.js\";\nimport isScrollParent from \"./isScrollParent.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nexport default function getScrollParent(node) {\n if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return node.ownerDocument.body;\n }\n\n if (isHTMLElement(node) && isScrollParent(node)) {\n return node;\n }\n\n return getScrollParent(getParentNode(node));\n}","import getScrollParent from \"./getScrollParent.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport getWindow from \"./getWindow.js\";\nimport isScrollParent from \"./isScrollParent.js\";\n/*\ngiven a DOM element, return the list of all scroll parents, up the list of ancesors\nuntil we get to the top window object. This list is what we attach scroll listeners\nto, because if any of these parent elements scroll, we'll need to re-calculate the\nreference element's position.\n*/\n\nexport default function listScrollParents(element, list) {\n var _element$ownerDocumen;\n\n if (list === void 0) {\n list = [];\n }\n\n var scrollParent = getScrollParent(element);\n var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);\n var win = getWindow(scrollParent);\n var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;\n var updatedList = list.concat(target);\n return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here\n updatedList.concat(listScrollParents(getParentNode(target)));\n}","export default function rectToClientRect(rect) {\n return Object.assign({}, rect, {\n left: rect.x,\n top: rect.y,\n right: rect.x + rect.width,\n bottom: rect.y + rect.height\n });\n}","import { viewport } from \"../enums.js\";\nimport getViewportRect from \"./getViewportRect.js\";\nimport getDocumentRect from \"./getDocumentRect.js\";\nimport listScrollParents from \"./listScrollParents.js\";\nimport getOffsetParent from \"./getOffsetParent.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport { isElement, isHTMLElement } from \"./instanceOf.js\";\nimport getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport contains from \"./contains.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport rectToClientRect from \"../utils/rectToClientRect.js\";\nimport { max, min } from \"../utils/math.js\";\n\nfunction getInnerBoundingClientRect(element, strategy) {\n var rect = getBoundingClientRect(element, false, strategy === 'fixed');\n rect.top = rect.top + element.clientTop;\n rect.left = rect.left + element.clientLeft;\n rect.bottom = rect.top + element.clientHeight;\n rect.right = rect.left + element.clientWidth;\n rect.width = element.clientWidth;\n rect.height = element.clientHeight;\n rect.x = rect.left;\n rect.y = rect.top;\n return rect;\n}\n\nfunction getClientRectFromMixedType(element, clippingParent, strategy) {\n return clippingParent === viewport ? rectToClientRect(getViewportRect(element, strategy)) : isElement(clippingParent) ? getInnerBoundingClientRect(clippingParent, strategy) : rectToClientRect(getDocumentRect(getDocumentElement(element)));\n} // A \"clipping parent\" is an overflowable container with the characteristic of\n// clipping (or hiding) overflowing elements with a position different from\n// `initial`\n\n\nfunction getClippingParents(element) {\n var clippingParents = listScrollParents(getParentNode(element));\n var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle(element).position) >= 0;\n var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;\n\n if (!isElement(clipperElement)) {\n return [];\n } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414\n\n\n return clippingParents.filter(function (clippingParent) {\n return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';\n });\n} // Gets the maximum area that the element is visible in due to any number of\n// clipping parents\n\n\nexport default function getClippingRect(element, boundary, rootBoundary, strategy) {\n var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);\n var clippingParents = [].concat(mainClippingParents, [rootBoundary]);\n var firstClippingParent = clippingParents[0];\n var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {\n var rect = getClientRectFromMixedType(element, clippingParent, strategy);\n accRect.top = max(rect.top, accRect.top);\n accRect.right = min(rect.right, accRect.right);\n accRect.bottom = min(rect.bottom, accRect.bottom);\n accRect.left = max(rect.left, accRect.left);\n return accRect;\n }, getClientRectFromMixedType(element, firstClippingParent, strategy));\n clippingRect.width = clippingRect.right - clippingRect.left;\n clippingRect.height = clippingRect.bottom - clippingRect.top;\n clippingRect.x = clippingRect.left;\n clippingRect.y = clippingRect.top;\n return clippingRect;\n}","import getWindow from \"./getWindow.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport isLayoutViewport from \"./isLayoutViewport.js\";\nexport default function getViewportRect(element, strategy) {\n var win = getWindow(element);\n var html = getDocumentElement(element);\n var visualViewport = win.visualViewport;\n var width = html.clientWidth;\n var height = html.clientHeight;\n var x = 0;\n var y = 0;\n\n if (visualViewport) {\n width = visualViewport.width;\n height = visualViewport.height;\n var layoutViewport = isLayoutViewport();\n\n if (layoutViewport || !layoutViewport && strategy === 'fixed') {\n x = visualViewport.offsetLeft;\n y = visualViewport.offsetTop;\n }\n }\n\n return {\n width: width,\n height: height,\n x: x + getWindowScrollBarX(element),\n y: y\n };\n}","import getDocumentElement from \"./getDocumentElement.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport getWindowScroll from \"./getWindowScroll.js\";\nimport { max } from \"../utils/math.js\"; // Gets the entire size of the scrollable document area, even extending outside\n// of the `` and `` rect bounds if horizontally scrollable\n\nexport default function getDocumentRect(element) {\n var _element$ownerDocumen;\n\n var html = getDocumentElement(element);\n var winScroll = getWindowScroll(element);\n var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;\n var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);\n var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);\n var x = -winScroll.scrollLeft + getWindowScrollBarX(element);\n var y = -winScroll.scrollTop;\n\n if (getComputedStyle(body || html).direction === 'rtl') {\n x += max(html.clientWidth, body ? body.clientWidth : 0) - width;\n }\n\n return {\n width: width,\n height: height,\n x: x,\n y: y\n };\n}","import getBasePlacement from \"./getBasePlacement.js\";\nimport getVariation from \"./getVariation.js\";\nimport getMainAxisFromPlacement from \"./getMainAxisFromPlacement.js\";\nimport { top, right, bottom, left, start, end } from \"../enums.js\";\nexport default function computeOffsets(_ref) {\n var reference = _ref.reference,\n element = _ref.element,\n placement = _ref.placement;\n var basePlacement = placement ? getBasePlacement(placement) : null;\n var variation = placement ? getVariation(placement) : null;\n var commonX = reference.x + reference.width / 2 - element.width / 2;\n var commonY = reference.y + reference.height / 2 - element.height / 2;\n var offsets;\n\n switch (basePlacement) {\n case top:\n offsets = {\n x: commonX,\n y: reference.y - element.height\n };\n break;\n\n case bottom:\n offsets = {\n x: commonX,\n y: reference.y + reference.height\n };\n break;\n\n case right:\n offsets = {\n x: reference.x + reference.width,\n y: commonY\n };\n break;\n\n case left:\n offsets = {\n x: reference.x - element.width,\n y: commonY\n };\n break;\n\n default:\n offsets = {\n x: reference.x,\n y: reference.y\n };\n }\n\n var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;\n\n if (mainAxis != null) {\n var len = mainAxis === 'y' ? 'height' : 'width';\n\n switch (variation) {\n case start:\n offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);\n break;\n\n case end:\n offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);\n break;\n\n default:\n }\n }\n\n return offsets;\n}","import getClippingRect from \"../dom-utils/getClippingRect.js\";\nimport getDocumentElement from \"../dom-utils/getDocumentElement.js\";\nimport getBoundingClientRect from \"../dom-utils/getBoundingClientRect.js\";\nimport computeOffsets from \"./computeOffsets.js\";\nimport rectToClientRect from \"./rectToClientRect.js\";\nimport { clippingParents, reference, popper, bottom, top, right, basePlacements, viewport } from \"../enums.js\";\nimport { isElement } from \"../dom-utils/instanceOf.js\";\nimport mergePaddingObject from \"./mergePaddingObject.js\";\nimport expandToHashMap from \"./expandToHashMap.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport default function detectOverflow(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n _options$placement = _options.placement,\n placement = _options$placement === void 0 ? state.placement : _options$placement,\n _options$strategy = _options.strategy,\n strategy = _options$strategy === void 0 ? state.strategy : _options$strategy,\n _options$boundary = _options.boundary,\n boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,\n _options$rootBoundary = _options.rootBoundary,\n rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,\n _options$elementConte = _options.elementContext,\n elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,\n _options$altBoundary = _options.altBoundary,\n altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,\n _options$padding = _options.padding,\n padding = _options$padding === void 0 ? 0 : _options$padding;\n var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n var altContext = elementContext === popper ? reference : popper;\n var popperRect = state.rects.popper;\n var element = state.elements[altBoundary ? altContext : elementContext];\n var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary, strategy);\n var referenceClientRect = getBoundingClientRect(state.elements.reference);\n var popperOffsets = computeOffsets({\n reference: referenceClientRect,\n element: popperRect,\n strategy: 'absolute',\n placement: placement\n });\n var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));\n var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect\n // 0 or negative = within the clipping rect\n\n var overflowOffsets = {\n top: clippingClientRect.top - elementClientRect.top + paddingObject.top,\n bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,\n left: clippingClientRect.left - elementClientRect.left + paddingObject.left,\n right: elementClientRect.right - clippingClientRect.right + paddingObject.right\n };\n var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element\n\n if (elementContext === popper && offsetData) {\n var offset = offsetData[placement];\n Object.keys(overflowOffsets).forEach(function (key) {\n var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;\n var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';\n overflowOffsets[key] += offset[axis] * multiply;\n });\n }\n\n return overflowOffsets;\n}","import getOppositePlacement from \"../utils/getOppositePlacement.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getOppositeVariationPlacement from \"../utils/getOppositeVariationPlacement.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\nimport computeAutoPlacement from \"../utils/computeAutoPlacement.js\";\nimport { bottom, top, start, right, left, auto } from \"../enums.js\";\nimport getVariation from \"../utils/getVariation.js\"; // eslint-disable-next-line import/no-unused-modules\n\nfunction getExpandedFallbackPlacements(placement) {\n if (getBasePlacement(placement) === auto) {\n return [];\n }\n\n var oppositePlacement = getOppositePlacement(placement);\n return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];\n}\n\nfunction flip(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n\n if (state.modifiersData[name]._skip) {\n return;\n }\n\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,\n specifiedFallbackPlacements = options.fallbackPlacements,\n padding = options.padding,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n _options$flipVariatio = options.flipVariations,\n flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,\n allowedAutoPlacements = options.allowedAutoPlacements;\n var preferredPlacement = state.options.placement;\n var basePlacement = getBasePlacement(preferredPlacement);\n var isBasePlacement = basePlacement === preferredPlacement;\n var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));\n var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {\n return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n flipVariations: flipVariations,\n allowedAutoPlacements: allowedAutoPlacements\n }) : placement);\n }, []);\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var checksMap = new Map();\n var makeFallbackChecks = true;\n var firstFittingPlacement = placements[0];\n\n for (var i = 0; i < placements.length; i++) {\n var placement = placements[i];\n\n var _basePlacement = getBasePlacement(placement);\n\n var isStartVariation = getVariation(placement) === start;\n var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;\n var len = isVertical ? 'width' : 'height';\n var overflow = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n altBoundary: altBoundary,\n padding: padding\n });\n var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;\n\n if (referenceRect[len] > popperRect[len]) {\n mainVariationSide = getOppositePlacement(mainVariationSide);\n }\n\n var altVariationSide = getOppositePlacement(mainVariationSide);\n var checks = [];\n\n if (checkMainAxis) {\n checks.push(overflow[_basePlacement] <= 0);\n }\n\n if (checkAltAxis) {\n checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);\n }\n\n if (checks.every(function (check) {\n return check;\n })) {\n firstFittingPlacement = placement;\n makeFallbackChecks = false;\n break;\n }\n\n checksMap.set(placement, checks);\n }\n\n if (makeFallbackChecks) {\n // `2` may be desired in some cases – research later\n var numberOfChecks = flipVariations ? 3 : 1;\n\n var _loop = function _loop(_i) {\n var fittingPlacement = placements.find(function (placement) {\n var checks = checksMap.get(placement);\n\n if (checks) {\n return checks.slice(0, _i).every(function (check) {\n return check;\n });\n }\n });\n\n if (fittingPlacement) {\n firstFittingPlacement = fittingPlacement;\n return \"break\";\n }\n };\n\n for (var _i = numberOfChecks; _i > 0; _i--) {\n var _ret = _loop(_i);\n\n if (_ret === \"break\") break;\n }\n }\n\n if (state.placement !== firstFittingPlacement) {\n state.modifiersData[name]._skip = true;\n state.placement = firstFittingPlacement;\n state.reset = true;\n }\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'flip',\n enabled: true,\n phase: 'main',\n fn: flip,\n requiresIfExists: ['offset'],\n data: {\n _skip: false\n }\n};","import getVariation from \"./getVariation.js\";\nimport { variationPlacements, basePlacements, placements as allPlacements } from \"../enums.js\";\nimport detectOverflow from \"./detectOverflow.js\";\nimport getBasePlacement from \"./getBasePlacement.js\";\nexport default function computeAutoPlacement(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n placement = _options.placement,\n boundary = _options.boundary,\n rootBoundary = _options.rootBoundary,\n padding = _options.padding,\n flipVariations = _options.flipVariations,\n _options$allowedAutoP = _options.allowedAutoPlacements,\n allowedAutoPlacements = _options$allowedAutoP === void 0 ? allPlacements : _options$allowedAutoP;\n var variation = getVariation(placement);\n var placements = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {\n return getVariation(placement) === variation;\n }) : basePlacements;\n var allowedPlacements = placements.filter(function (placement) {\n return allowedAutoPlacements.indexOf(placement) >= 0;\n });\n\n if (allowedPlacements.length === 0) {\n allowedPlacements = placements;\n } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...\n\n\n var overflows = allowedPlacements.reduce(function (acc, placement) {\n acc[placement] = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding\n })[getBasePlacement(placement)];\n return acc;\n }, {});\n return Object.keys(overflows).sort(function (a, b) {\n return overflows[a] - overflows[b];\n });\n}","import { top, bottom, left, right } from \"../enums.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\n\nfunction getSideOffsets(overflow, rect, preventedOffsets) {\n if (preventedOffsets === void 0) {\n preventedOffsets = {\n x: 0,\n y: 0\n };\n }\n\n return {\n top: overflow.top - rect.height - preventedOffsets.y,\n right: overflow.right - rect.width + preventedOffsets.x,\n bottom: overflow.bottom - rect.height + preventedOffsets.y,\n left: overflow.left - rect.width - preventedOffsets.x\n };\n}\n\nfunction isAnySideFullyClipped(overflow) {\n return [top, right, bottom, left].some(function (side) {\n return overflow[side] >= 0;\n });\n}\n\nfunction hide(_ref) {\n var state = _ref.state,\n name = _ref.name;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var preventedOffsets = state.modifiersData.preventOverflow;\n var referenceOverflow = detectOverflow(state, {\n elementContext: 'reference'\n });\n var popperAltOverflow = detectOverflow(state, {\n altBoundary: true\n });\n var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);\n var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);\n var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);\n var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);\n state.modifiersData[name] = {\n referenceClippingOffsets: referenceClippingOffsets,\n popperEscapeOffsets: popperEscapeOffsets,\n isReferenceHidden: isReferenceHidden,\n hasPopperEscaped: hasPopperEscaped\n };\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-reference-hidden': isReferenceHidden,\n 'data-popper-escaped': hasPopperEscaped\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'hide',\n enabled: true,\n phase: 'main',\n requiresIfExists: ['preventOverflow'],\n fn: hide\n};","import getBasePlacement from \"../utils/getBasePlacement.js\";\nimport { top, left, right, placements } from \"../enums.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport function distanceAndSkiddingToXY(placement, rects, offset) {\n var basePlacement = getBasePlacement(placement);\n var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;\n\n var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {\n placement: placement\n })) : offset,\n skidding = _ref[0],\n distance = _ref[1];\n\n skidding = skidding || 0;\n distance = (distance || 0) * invertDistance;\n return [left, right].indexOf(basePlacement) >= 0 ? {\n x: distance,\n y: skidding\n } : {\n x: skidding,\n y: distance\n };\n}\n\nfunction offset(_ref2) {\n var state = _ref2.state,\n options = _ref2.options,\n name = _ref2.name;\n var _options$offset = options.offset,\n offset = _options$offset === void 0 ? [0, 0] : _options$offset;\n var data = placements.reduce(function (acc, placement) {\n acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);\n return acc;\n }, {});\n var _data$state$placement = data[state.placement],\n x = _data$state$placement.x,\n y = _data$state$placement.y;\n\n if (state.modifiersData.popperOffsets != null) {\n state.modifiersData.popperOffsets.x += x;\n state.modifiersData.popperOffsets.y += y;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'offset',\n enabled: true,\n phase: 'main',\n requires: ['popperOffsets'],\n fn: offset\n};","import computeOffsets from \"../utils/computeOffsets.js\";\n\nfunction popperOffsets(_ref) {\n var state = _ref.state,\n name = _ref.name;\n // Offsets are the actual position the popper needs to have to be\n // properly positioned near its reference element\n // This is the most basic placement, and will be adjusted by\n // the modifiers in the next step\n state.modifiersData[name] = computeOffsets({\n reference: state.rects.reference,\n element: state.rects.popper,\n strategy: 'absolute',\n placement: state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'popperOffsets',\n enabled: true,\n phase: 'read',\n fn: popperOffsets,\n data: {}\n};","import { top, left, right, bottom, start } from \"../enums.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getMainAxisFromPlacement from \"../utils/getMainAxisFromPlacement.js\";\nimport getAltAxis from \"../utils/getAltAxis.js\";\nimport { within, withinMaxClamp } from \"../utils/within.js\";\nimport getLayoutRect from \"../dom-utils/getLayoutRect.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\nimport getVariation from \"../utils/getVariation.js\";\nimport getFreshSideObject from \"../utils/getFreshSideObject.js\";\nimport { min as mathMin, max as mathMax } from \"../utils/math.js\";\n\nfunction preventOverflow(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n padding = options.padding,\n _options$tether = options.tether,\n tether = _options$tether === void 0 ? true : _options$tether,\n _options$tetherOffset = options.tetherOffset,\n tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;\n var overflow = detectOverflow(state, {\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n altBoundary: altBoundary\n });\n var basePlacement = getBasePlacement(state.placement);\n var variation = getVariation(state.placement);\n var isBasePlacement = !variation;\n var mainAxis = getMainAxisFromPlacement(basePlacement);\n var altAxis = getAltAxis(mainAxis);\n var popperOffsets = state.modifiersData.popperOffsets;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {\n placement: state.placement\n })) : tetherOffset;\n var normalizedTetherOffsetValue = typeof tetherOffsetValue === 'number' ? {\n mainAxis: tetherOffsetValue,\n altAxis: tetherOffsetValue\n } : Object.assign({\n mainAxis: 0,\n altAxis: 0\n }, tetherOffsetValue);\n var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null;\n var data = {\n x: 0,\n y: 0\n };\n\n if (!popperOffsets) {\n return;\n }\n\n if (checkMainAxis) {\n var _offsetModifierState$;\n\n var mainSide = mainAxis === 'y' ? top : left;\n var altSide = mainAxis === 'y' ? bottom : right;\n var len = mainAxis === 'y' ? 'height' : 'width';\n var offset = popperOffsets[mainAxis];\n var min = offset + overflow[mainSide];\n var max = offset - overflow[altSide];\n var additive = tether ? -popperRect[len] / 2 : 0;\n var minLen = variation === start ? referenceRect[len] : popperRect[len];\n var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go\n // outside the reference bounds\n\n var arrowElement = state.elements.arrow;\n var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {\n width: 0,\n height: 0\n };\n var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();\n var arrowPaddingMin = arrowPaddingObject[mainSide];\n var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want\n // to include its full size in the calculation. If the reference is small\n // and near the edge of a boundary, the popper can overflow even if the\n // reference is not overflowing as well (e.g. virtual elements with no\n // width or height)\n\n var arrowLen = within(0, referenceRect[len], arrowRect[len]);\n var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis;\n var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis;\n var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);\n var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;\n var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0;\n var tetherMin = offset + minOffset - offsetModifierValue - clientOffset;\n var tetherMax = offset + maxOffset - offsetModifierValue;\n var preventedOffset = within(tether ? mathMin(min, tetherMin) : min, offset, tether ? mathMax(max, tetherMax) : max);\n popperOffsets[mainAxis] = preventedOffset;\n data[mainAxis] = preventedOffset - offset;\n }\n\n if (checkAltAxis) {\n var _offsetModifierState$2;\n\n var _mainSide = mainAxis === 'x' ? top : left;\n\n var _altSide = mainAxis === 'x' ? bottom : right;\n\n var _offset = popperOffsets[altAxis];\n\n var _len = altAxis === 'y' ? 'height' : 'width';\n\n var _min = _offset + overflow[_mainSide];\n\n var _max = _offset - overflow[_altSide];\n\n var isOriginSide = [top, left].indexOf(basePlacement) !== -1;\n\n var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0;\n\n var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis;\n\n var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max;\n\n var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max);\n\n popperOffsets[altAxis] = _preventedOffset;\n data[altAxis] = _preventedOffset - _offset;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'preventOverflow',\n enabled: true,\n phase: 'main',\n fn: preventOverflow,\n requiresIfExists: ['offset']\n};","export default function getAltAxis(axis) {\n return axis === 'x' ? 'y' : 'x';\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getNodeScroll from \"./getNodeScroll.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport isScrollParent from \"./isScrollParent.js\";\nimport { round } from \"../utils/math.js\";\n\nfunction isElementScaled(element) {\n var rect = element.getBoundingClientRect();\n var scaleX = round(rect.width) / element.offsetWidth || 1;\n var scaleY = round(rect.height) / element.offsetHeight || 1;\n return scaleX !== 1 || scaleY !== 1;\n} // Returns the composite rect of an element relative to its offsetParent.\n// Composite means it takes into account transforms as well as layout.\n\n\nexport default function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {\n if (isFixed === void 0) {\n isFixed = false;\n }\n\n var isOffsetParentAnElement = isHTMLElement(offsetParent);\n var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);\n var documentElement = getDocumentElement(offsetParent);\n var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed);\n var scroll = {\n scrollLeft: 0,\n scrollTop: 0\n };\n var offsets = {\n x: 0,\n y: 0\n };\n\n if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {\n if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078\n isScrollParent(documentElement)) {\n scroll = getNodeScroll(offsetParent);\n }\n\n if (isHTMLElement(offsetParent)) {\n offsets = getBoundingClientRect(offsetParent, true);\n offsets.x += offsetParent.clientLeft;\n offsets.y += offsetParent.clientTop;\n } else if (documentElement) {\n offsets.x = getWindowScrollBarX(documentElement);\n }\n }\n\n return {\n x: rect.left + scroll.scrollLeft - offsets.x,\n y: rect.top + scroll.scrollTop - offsets.y,\n width: rect.width,\n height: rect.height\n };\n}","import getWindowScroll from \"./getWindowScroll.js\";\nimport getWindow from \"./getWindow.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport getHTMLElementScroll from \"./getHTMLElementScroll.js\";\nexport default function getNodeScroll(node) {\n if (node === getWindow(node) || !isHTMLElement(node)) {\n return getWindowScroll(node);\n } else {\n return getHTMLElementScroll(node);\n }\n}","export default function getHTMLElementScroll(element) {\n return {\n scrollLeft: element.scrollLeft,\n scrollTop: element.scrollTop\n };\n}","import { modifierPhases } from \"../enums.js\"; // source: https://stackoverflow.com/questions/49875255\n\nfunction order(modifiers) {\n var map = new Map();\n var visited = new Set();\n var result = [];\n modifiers.forEach(function (modifier) {\n map.set(modifier.name, modifier);\n }); // On visiting object, check for its dependencies and visit them recursively\n\n function sort(modifier) {\n visited.add(modifier.name);\n var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);\n requires.forEach(function (dep) {\n if (!visited.has(dep)) {\n var depModifier = map.get(dep);\n\n if (depModifier) {\n sort(depModifier);\n }\n }\n });\n result.push(modifier);\n }\n\n modifiers.forEach(function (modifier) {\n if (!visited.has(modifier.name)) {\n // check for visited object\n sort(modifier);\n }\n });\n return result;\n}\n\nexport default function orderModifiers(modifiers) {\n // order based on dependencies\n var orderedModifiers = order(modifiers); // order based on phase\n\n return modifierPhases.reduce(function (acc, phase) {\n return acc.concat(orderedModifiers.filter(function (modifier) {\n return modifier.phase === phase;\n }));\n }, []);\n}","import getCompositeRect from \"./dom-utils/getCompositeRect.js\";\nimport getLayoutRect from \"./dom-utils/getLayoutRect.js\";\nimport listScrollParents from \"./dom-utils/listScrollParents.js\";\nimport getOffsetParent from \"./dom-utils/getOffsetParent.js\";\nimport orderModifiers from \"./utils/orderModifiers.js\";\nimport debounce from \"./utils/debounce.js\";\nimport mergeByName from \"./utils/mergeByName.js\";\nimport detectOverflow from \"./utils/detectOverflow.js\";\nimport { isElement } from \"./dom-utils/instanceOf.js\";\nvar DEFAULT_OPTIONS = {\n placement: 'bottom',\n modifiers: [],\n strategy: 'absolute'\n};\n\nfunction areValidElements() {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n return !args.some(function (element) {\n return !(element && typeof element.getBoundingClientRect === 'function');\n });\n}\n\nexport function popperGenerator(generatorOptions) {\n if (generatorOptions === void 0) {\n generatorOptions = {};\n }\n\n var _generatorOptions = generatorOptions,\n _generatorOptions$def = _generatorOptions.defaultModifiers,\n defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,\n _generatorOptions$def2 = _generatorOptions.defaultOptions,\n defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;\n return function createPopper(reference, popper, options) {\n if (options === void 0) {\n options = defaultOptions;\n }\n\n var state = {\n placement: 'bottom',\n orderedModifiers: [],\n options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),\n modifiersData: {},\n elements: {\n reference: reference,\n popper: popper\n },\n attributes: {},\n styles: {}\n };\n var effectCleanupFns = [];\n var isDestroyed = false;\n var instance = {\n state: state,\n setOptions: function setOptions(setOptionsAction) {\n var options = typeof setOptionsAction === 'function' ? setOptionsAction(state.options) : setOptionsAction;\n cleanupModifierEffects();\n state.options = Object.assign({}, defaultOptions, state.options, options);\n state.scrollParents = {\n reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],\n popper: listScrollParents(popper)\n }; // Orders the modifiers based on their dependencies and `phase`\n // properties\n\n var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers\n\n state.orderedModifiers = orderedModifiers.filter(function (m) {\n return m.enabled;\n });\n runModifierEffects();\n return instance.update();\n },\n // Sync update – it will always be executed, even if not necessary. This\n // is useful for low frequency updates where sync behavior simplifies the\n // logic.\n // For high frequency updates (e.g. `resize` and `scroll` events), always\n // prefer the async Popper#update method\n forceUpdate: function forceUpdate() {\n if (isDestroyed) {\n return;\n }\n\n var _state$elements = state.elements,\n reference = _state$elements.reference,\n popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements\n // anymore\n\n if (!areValidElements(reference, popper)) {\n return;\n } // Store the reference and popper rects to be read by modifiers\n\n\n state.rects = {\n reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),\n popper: getLayoutRect(popper)\n }; // Modifiers have the ability to reset the current update cycle. The\n // most common use case for this is the `flip` modifier changing the\n // placement, which then needs to re-run all the modifiers, because the\n // logic was previously ran for the previous placement and is therefore\n // stale/incorrect\n\n state.reset = false;\n state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier\n // is filled with the initial data specified by the modifier. This means\n // it doesn't persist and is fresh on each update.\n // To ensure persistent data, use `${name}#persistent`\n\n state.orderedModifiers.forEach(function (modifier) {\n return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);\n });\n\n for (var index = 0; index < state.orderedModifiers.length; index++) {\n if (state.reset === true) {\n state.reset = false;\n index = -1;\n continue;\n }\n\n var _state$orderedModifie = state.orderedModifiers[index],\n fn = _state$orderedModifie.fn,\n _state$orderedModifie2 = _state$orderedModifie.options,\n _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,\n name = _state$orderedModifie.name;\n\n if (typeof fn === 'function') {\n state = fn({\n state: state,\n options: _options,\n name: name,\n instance: instance\n }) || state;\n }\n }\n },\n // Async and optimistically optimized update – it will not be executed if\n // not necessary (debounced to run at most once-per-tick)\n update: debounce(function () {\n return new Promise(function (resolve) {\n instance.forceUpdate();\n resolve(state);\n });\n }),\n destroy: function destroy() {\n cleanupModifierEffects();\n isDestroyed = true;\n }\n };\n\n if (!areValidElements(reference, popper)) {\n return instance;\n }\n\n instance.setOptions(options).then(function (state) {\n if (!isDestroyed && options.onFirstUpdate) {\n options.onFirstUpdate(state);\n }\n }); // Modifiers have the ability to execute arbitrary code before the first\n // update cycle runs. They will be executed in the same order as the update\n // cycle. This is useful when a modifier adds some persistent data that\n // other modifiers need to use, but the modifier is run after the dependent\n // one.\n\n function runModifierEffects() {\n state.orderedModifiers.forEach(function (_ref) {\n var name = _ref.name,\n _ref$options = _ref.options,\n options = _ref$options === void 0 ? {} : _ref$options,\n effect = _ref.effect;\n\n if (typeof effect === 'function') {\n var cleanupFn = effect({\n state: state,\n name: name,\n instance: instance,\n options: options\n });\n\n var noopFn = function noopFn() {};\n\n effectCleanupFns.push(cleanupFn || noopFn);\n }\n });\n }\n\n function cleanupModifierEffects() {\n effectCleanupFns.forEach(function (fn) {\n return fn();\n });\n effectCleanupFns = [];\n }\n\n return instance;\n };\n}\nexport var createPopper = /*#__PURE__*/popperGenerator(); // eslint-disable-next-line import/no-unused-modules\n\nexport { detectOverflow };","export default function debounce(fn) {\n var pending;\n return function () {\n if (!pending) {\n pending = new Promise(function (resolve) {\n Promise.resolve().then(function () {\n pending = undefined;\n resolve(fn());\n });\n });\n }\n\n return pending;\n };\n}","export default function mergeByName(modifiers) {\n var merged = modifiers.reduce(function (merged, current) {\n var existing = merged[current.name];\n merged[current.name] = existing ? Object.assign({}, existing, current, {\n options: Object.assign({}, existing.options, current.options),\n data: Object.assign({}, existing.data, current.data)\n }) : current;\n return merged;\n }, {}); // IE11 does not support Object.values\n\n return Object.keys(merged).map(function (key) {\n return merged[key];\n });\n}","import { popperGenerator, detectOverflow } from \"./createPopper.js\";\nimport eventListeners from \"./modifiers/eventListeners.js\";\nimport popperOffsets from \"./modifiers/popperOffsets.js\";\nimport computeStyles from \"./modifiers/computeStyles.js\";\nimport applyStyles from \"./modifiers/applyStyles.js\";\nimport offset from \"./modifiers/offset.js\";\nimport flip from \"./modifiers/flip.js\";\nimport preventOverflow from \"./modifiers/preventOverflow.js\";\nimport arrow from \"./modifiers/arrow.js\";\nimport hide from \"./modifiers/hide.js\";\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles, offset, flip, preventOverflow, arrow, hide];\nvar createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow }; // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper as createPopperLite } from \"./popper-lite.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport * from \"./modifiers/index.js\";","import { popperGenerator, detectOverflow } from \"./createPopper.js\";\nimport eventListeners from \"./modifiers/eventListeners.js\";\nimport popperOffsets from \"./modifiers/popperOffsets.js\";\nimport computeStyles from \"./modifiers/computeStyles.js\";\nimport applyStyles from \"./modifiers/applyStyles.js\";\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles];\nvar createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow };","/*!\n * Bootstrap v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\nimport * as Popper from '@popperjs/core';\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map();\nconst Data = {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map());\n }\n const instanceMap = elementMap.get(element);\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`);\n return;\n }\n instanceMap.set(key, instance);\n },\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null;\n }\n return null;\n },\n remove(element, key) {\n if (!elementMap.has(element)) {\n return;\n }\n const instanceMap = elementMap.get(element);\n instanceMap.delete(key);\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element);\n }\n }\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1000000;\nconst MILLISECONDS_MULTIPLIER = 1000;\nconst TRANSITION_END = 'transitionend';\n\n/**\n * Properly escape IDs selectors to handle weird IDs\n * @param {string} selector\n * @returns {string}\n */\nconst parseSelector = selector => {\n if (selector && window.CSS && window.CSS.escape) {\n // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\n selector = selector.replace(/#([^\\s\"#']+)/g, (match, id) => `#${CSS.escape(id)}`);\n }\n return selector;\n};\n\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\nconst toType = object => {\n if (object === null || object === undefined) {\n return `${object}`;\n }\n return Object.prototype.toString.call(object).match(/\\s([a-z]+)/i)[1].toLowerCase();\n};\n\n/**\n * Public Util API\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID);\n } while (document.getElementById(prefix));\n return prefix;\n};\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0;\n }\n\n // Get transition-duration of the element\n let {\n transitionDuration,\n transitionDelay\n } = window.getComputedStyle(element);\n const floatTransitionDuration = Number.parseFloat(transitionDuration);\n const floatTransitionDelay = Number.parseFloat(transitionDelay);\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0;\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0];\n transitionDelay = transitionDelay.split(',')[0];\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;\n};\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END));\n};\nconst isElement = object => {\n if (!object || typeof object !== 'object') {\n return false;\n }\n if (typeof object.jquery !== 'undefined') {\n object = object[0];\n }\n return typeof object.nodeType !== 'undefined';\n};\nconst getElement = object => {\n // it's a jQuery object or a node element\n if (isElement(object)) {\n return object.jquery ? object[0] : object;\n }\n if (typeof object === 'string' && object.length > 0) {\n return document.querySelector(parseSelector(object));\n }\n return null;\n};\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false;\n }\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible';\n // Handle `details` element as its content may falsie appear visible when it is closed\n const closedDetails = element.closest('details:not([open])');\n if (!closedDetails) {\n return elementIsVisible;\n }\n if (closedDetails !== element) {\n const summary = element.closest('summary');\n if (summary && summary.parentNode !== closedDetails) {\n return false;\n }\n if (summary === null) {\n return false;\n }\n }\n return elementIsVisible;\n};\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true;\n }\n if (element.classList.contains('disabled')) {\n return true;\n }\n if (typeof element.disabled !== 'undefined') {\n return element.disabled;\n }\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';\n};\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null;\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode();\n return root instanceof ShadowRoot ? root : null;\n }\n if (element instanceof ShadowRoot) {\n return element;\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null;\n }\n return findShadowRoot(element.parentNode);\n};\nconst noop = () => {};\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n element.offsetHeight; // eslint-disable-line no-unused-expressions\n};\nconst getjQuery = () => {\n if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return window.jQuery;\n }\n return null;\n};\nconst DOMContentLoadedCallbacks = [];\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n for (const callback of DOMContentLoadedCallbacks) {\n callback();\n }\n });\n }\n DOMContentLoadedCallbacks.push(callback);\n } else {\n callback();\n }\n};\nconst isRTL = () => document.documentElement.dir === 'rtl';\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery();\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME;\n const JQUERY_NO_CONFLICT = $.fn[name];\n $.fn[name] = plugin.jQueryInterface;\n $.fn[name].Constructor = plugin;\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT;\n return plugin.jQueryInterface;\n };\n }\n });\n};\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\n return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue;\n};\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback);\n return;\n }\n const durationPadding = 5;\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding;\n let called = false;\n const handler = ({\n target\n }) => {\n if (target !== transitionElement) {\n return;\n }\n called = true;\n transitionElement.removeEventListener(TRANSITION_END, handler);\n execute(callback);\n };\n transitionElement.addEventListener(TRANSITION_END, handler);\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement);\n }\n }, emulatedDuration);\n};\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n const listLength = list.length;\n let index = list.indexOf(activeElement);\n\n // if the element does not exist in the list return an element\n // depending on the direction and if cycle is allowed\n if (index === -1) {\n return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0];\n }\n index += shouldGetNext ? 1 : -1;\n if (isCycleAllowed) {\n index = (index + listLength) % listLength;\n }\n return list[Math.max(0, Math.min(index, listLength - 1))];\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/;\nconst stripNameRegex = /\\..*/;\nconst stripUidRegex = /::\\d+$/;\nconst eventRegistry = {}; // Events storage\nlet uidEvent = 1;\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n};\nconst nativeEvents = 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']);\n\n/**\n * Private methods\n */\n\nfunction makeEventUid(element, uid) {\n return uid && `${uid}::${uidEvent++}` || element.uidEvent || uidEvent++;\n}\nfunction getElementEvents(element) {\n const uid = makeEventUid(element);\n element.uidEvent = uid;\n eventRegistry[uid] = eventRegistry[uid] || {};\n return eventRegistry[uid];\n}\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n hydrateObj(event, {\n delegateTarget: element\n });\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn);\n }\n return fn.apply(element, [event]);\n };\n}\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector);\n for (let {\n target\n } = event; target && target !== this; target = target.parentNode) {\n for (const domElement of domElements) {\n if (domElement !== target) {\n continue;\n }\n hydrateObj(event, {\n delegateTarget: target\n });\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn);\n }\n return fn.apply(target, [event]);\n }\n }\n };\n}\nfunction findHandler(events, callable, delegationSelector = null) {\n return Object.values(events).find(event => event.callable === callable && event.delegationSelector === delegationSelector);\n}\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\n const isDelegated = typeof handler === 'string';\n // TODO: tooltip passes `false` instead of selector, so we need to check\n const callable = isDelegated ? delegationFunction : handler || delegationFunction;\n let typeEvent = getTypeEvent(originalTypeEvent);\n if (!nativeEvents.has(typeEvent)) {\n typeEvent = originalTypeEvent;\n }\n return [isDelegated, callable, typeEvent];\n}\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return;\n }\n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction);\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (originalTypeEvent in customEvents) {\n const wrapFunction = fn => {\n return function (event) {\n if (!event.relatedTarget || event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget)) {\n return fn.call(this, event);\n }\n };\n };\n callable = wrapFunction(callable);\n }\n const events = getElementEvents(element);\n const handlers = events[typeEvent] || (events[typeEvent] = {});\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null);\n if (previousFunction) {\n previousFunction.oneOff = previousFunction.oneOff && oneOff;\n return;\n }\n const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''));\n const fn = isDelegated ? bootstrapDelegationHandler(element, handler, callable) : bootstrapHandler(element, callable);\n fn.delegationSelector = isDelegated ? handler : null;\n fn.callable = callable;\n fn.oneOff = oneOff;\n fn.uidEvent = uid;\n handlers[uid] = fn;\n element.addEventListener(typeEvent, fn, isDelegated);\n}\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector);\n if (!fn) {\n return;\n }\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector));\n delete events[typeEvent][fn.uidEvent];\n}\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {};\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);\n }\n }\n}\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '');\n return customEvents[event] || event;\n}\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false);\n },\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true);\n },\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return;\n }\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction);\n const inNamespace = typeEvent !== originalTypeEvent;\n const events = getElementEvents(element);\n const storeElementEvent = events[typeEvent] || {};\n const isNamespace = originalTypeEvent.startsWith('.');\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return;\n }\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null);\n return;\n }\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1));\n }\n }\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '');\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);\n }\n }\n },\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null;\n }\n const $ = getjQuery();\n const typeEvent = getTypeEvent(event);\n const inNamespace = event !== typeEvent;\n let jQueryEvent = null;\n let bubbles = true;\n let nativeDispatch = true;\n let defaultPrevented = false;\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args);\n $(element).trigger(jQueryEvent);\n bubbles = !jQueryEvent.isPropagationStopped();\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped();\n defaultPrevented = jQueryEvent.isDefaultPrevented();\n }\n const evt = hydrateObj(new Event(event, {\n bubbles,\n cancelable: true\n }), args);\n if (defaultPrevented) {\n evt.preventDefault();\n }\n if (nativeDispatch) {\n element.dispatchEvent(evt);\n }\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault();\n }\n return evt;\n }\n};\nfunction hydrateObj(obj, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value;\n } catch (_unused) {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value;\n }\n });\n }\n }\n return obj;\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true;\n }\n if (value === 'false') {\n return false;\n }\n if (value === Number(value).toString()) {\n return Number(value);\n }\n if (value === '' || value === 'null') {\n return null;\n }\n if (typeof value !== 'string') {\n return value;\n }\n try {\n return JSON.parse(decodeURIComponent(value));\n } catch (_unused) {\n return value;\n }\n}\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`);\n}\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value);\n },\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`);\n },\n getDataAttributes(element) {\n if (!element) {\n return {};\n }\n const attributes = {};\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'));\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '');\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length);\n attributes[pureKey] = normalizeData(element.dataset[key]);\n }\n return attributes;\n },\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`));\n }\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Class definition\n */\n\nclass Config {\n // Getters\n static get Default() {\n return {};\n }\n static get DefaultType() {\n return {};\n }\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!');\n }\n _getConfig(config) {\n config = this._mergeConfigObj(config);\n config = this._configAfterMerge(config);\n this._typeCheckConfig(config);\n return config;\n }\n _configAfterMerge(config) {\n return config;\n }\n _mergeConfigObj(config, element) {\n const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {}; // try to parse\n\n return {\n ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n };\n }\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const [property, expectedTypes] of Object.entries(configTypes)) {\n const value = config[property];\n const valueType = isElement(value) ? 'element' : toType(value);\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`);\n }\n }\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.3';\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super();\n element = getElement(element);\n if (!element) {\n return;\n }\n this._element = element;\n this._config = this._getConfig(config);\n Data.set(this._element, this.constructor.DATA_KEY, this);\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY);\n EventHandler.off(this._element, this.constructor.EVENT_KEY);\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null;\n }\n }\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated);\n }\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element);\n config = this._configAfterMerge(config);\n this._typeCheckConfig(config);\n return config;\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY);\n }\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null);\n }\n static get VERSION() {\n return VERSION;\n }\n static get DATA_KEY() {\n return `bs.${this.NAME}`;\n }\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`;\n }\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`;\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target');\n if (!selector || selector === '#') {\n let hrefAttribute = element.getAttribute('href');\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttribute || !hrefAttribute.includes('#') && !hrefAttribute.startsWith('.')) {\n return null;\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\n hrefAttribute = `#${hrefAttribute.split('#')[1]}`;\n }\n selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null;\n }\n return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null;\n};\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector));\n },\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector);\n },\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector));\n },\n parents(element, selector) {\n const parents = [];\n let ancestor = element.parentNode.closest(selector);\n while (ancestor) {\n parents.push(ancestor);\n ancestor = ancestor.parentNode.closest(selector);\n }\n return parents;\n },\n prev(element, selector) {\n let previous = element.previousElementSibling;\n while (previous) {\n if (previous.matches(selector)) {\n return [previous];\n }\n previous = previous.previousElementSibling;\n }\n return [];\n },\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling;\n while (next) {\n if (next.matches(selector)) {\n return [next];\n }\n next = next.nextElementSibling;\n }\n return [];\n },\n focusableChildren(element) {\n const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable=\"true\"]'].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',');\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el));\n },\n getSelectorFromElement(element) {\n const selector = getSelector(element);\n if (selector) {\n return SelectorEngine.findOne(selector) ? selector : null;\n }\n return null;\n },\n getElementFromSelector(element) {\n const selector = getSelector(element);\n return selector ? SelectorEngine.findOne(selector) : null;\n },\n getMultipleElementsFromSelector(element) {\n const selector = getSelector(element);\n return selector ? SelectorEngine.find(selector) : [];\n }\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`;\n const name = component.NAME;\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault();\n }\n if (isDisabled(this)) {\n return;\n }\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`);\n const instance = component.getOrCreateInstance(target);\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]();\n });\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$f = 'alert';\nconst DATA_KEY$a = 'bs.alert';\nconst EVENT_KEY$b = `.${DATA_KEY$a}`;\nconst EVENT_CLOSE = `close${EVENT_KEY$b}`;\nconst EVENT_CLOSED = `closed${EVENT_KEY$b}`;\nconst CLASS_NAME_FADE$5 = 'fade';\nconst CLASS_NAME_SHOW$8 = 'show';\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME$f;\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE);\n if (closeEvent.defaultPrevented) {\n return;\n }\n this._element.classList.remove(CLASS_NAME_SHOW$8);\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE$5);\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated);\n }\n\n // Private\n _destroyElement() {\n this._element.remove();\n EventHandler.trigger(this._element, EVENT_CLOSED);\n this.dispose();\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this);\n if (typeof config !== 'string') {\n return;\n }\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config](this);\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close');\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$e = 'button';\nconst DATA_KEY$9 = 'bs.button';\nconst EVENT_KEY$a = `.${DATA_KEY$9}`;\nconst DATA_API_KEY$6 = '.data-api';\nconst CLASS_NAME_ACTIVE$3 = 'active';\nconst SELECTOR_DATA_TOGGLE$5 = '[data-bs-toggle=\"button\"]';\nconst EVENT_CLICK_DATA_API$6 = `click${EVENT_KEY$a}${DATA_API_KEY$6}`;\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME$e;\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE$3));\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this);\n if (config === 'toggle') {\n data[config]();\n }\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$6, SELECTOR_DATA_TOGGLE$5, event => {\n event.preventDefault();\n const button = event.target.closest(SELECTOR_DATA_TOGGLE$5);\n const data = Button.getOrCreateInstance(button);\n data.toggle();\n});\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$d = 'swipe';\nconst EVENT_KEY$9 = '.bs.swipe';\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY$9}`;\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY$9}`;\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY$9}`;\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY$9}`;\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY$9}`;\nconst POINTER_TYPE_TOUCH = 'touch';\nconst POINTER_TYPE_PEN = 'pen';\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event';\nconst SWIPE_THRESHOLD = 40;\nconst Default$c = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n};\nconst DefaultType$c = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n};\n\n/**\n * Class definition\n */\n\nclass Swipe extends Config {\n constructor(element, config) {\n super();\n this._element = element;\n if (!element || !Swipe.isSupported()) {\n return;\n }\n this._config = this._getConfig(config);\n this._deltaX = 0;\n this._supportPointerEvents = Boolean(window.PointerEvent);\n this._initEvents();\n }\n\n // Getters\n static get Default() {\n return Default$c;\n }\n static get DefaultType() {\n return DefaultType$c;\n }\n static get NAME() {\n return NAME$d;\n }\n\n // Public\n dispose() {\n EventHandler.off(this._element, EVENT_KEY$9);\n }\n\n // Private\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX;\n return;\n }\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX;\n }\n }\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX;\n }\n this._handleSwipe();\n execute(this._config.endCallback);\n }\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this._deltaX;\n }\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX);\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return;\n }\n const direction = absDeltaX / this._deltaX;\n this._deltaX = 0;\n if (!direction) {\n return;\n }\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback);\n }\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event));\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event));\n this._element.classList.add(CLASS_NAME_POINTER_EVENT);\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event));\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event));\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event));\n }\n }\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH);\n }\n\n // Static\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$c = 'carousel';\nconst DATA_KEY$8 = 'bs.carousel';\nconst EVENT_KEY$8 = `.${DATA_KEY$8}`;\nconst DATA_API_KEY$5 = '.data-api';\nconst ARROW_LEFT_KEY$1 = 'ArrowLeft';\nconst ARROW_RIGHT_KEY$1 = 'ArrowRight';\nconst TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next';\nconst ORDER_PREV = 'prev';\nconst DIRECTION_LEFT = 'left';\nconst DIRECTION_RIGHT = 'right';\nconst EVENT_SLIDE = `slide${EVENT_KEY$8}`;\nconst EVENT_SLID = `slid${EVENT_KEY$8}`;\nconst EVENT_KEYDOWN$1 = `keydown${EVENT_KEY$8}`;\nconst EVENT_MOUSEENTER$1 = `mouseenter${EVENT_KEY$8}`;\nconst EVENT_MOUSELEAVE$1 = `mouseleave${EVENT_KEY$8}`;\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY$8}`;\nconst EVENT_LOAD_DATA_API$3 = `load${EVENT_KEY$8}${DATA_API_KEY$5}`;\nconst EVENT_CLICK_DATA_API$5 = `click${EVENT_KEY$8}${DATA_API_KEY$5}`;\nconst CLASS_NAME_CAROUSEL = 'carousel';\nconst CLASS_NAME_ACTIVE$2 = 'active';\nconst CLASS_NAME_SLIDE = 'slide';\nconst CLASS_NAME_END = 'carousel-item-end';\nconst CLASS_NAME_START = 'carousel-item-start';\nconst CLASS_NAME_NEXT = 'carousel-item-next';\nconst CLASS_NAME_PREV = 'carousel-item-prev';\nconst SELECTOR_ACTIVE = '.active';\nconst SELECTOR_ITEM = '.carousel-item';\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM;\nconst SELECTOR_ITEM_IMG = '.carousel-item img';\nconst SELECTOR_INDICATORS = '.carousel-indicators';\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]';\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]';\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY$1]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY$1]: DIRECTION_LEFT\n};\nconst Default$b = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n};\nconst DefaultType$b = {\n interval: '(number|boolean)',\n // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n};\n\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._interval = null;\n this._activeElement = null;\n this._isSliding = false;\n this.touchTimeout = null;\n this._swipeHelper = null;\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element);\n this._addEventListeners();\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle();\n }\n }\n\n // Getters\n static get Default() {\n return Default$b;\n }\n static get DefaultType() {\n return DefaultType$b;\n }\n static get NAME() {\n return NAME$c;\n }\n\n // Public\n next() {\n this._slide(ORDER_NEXT);\n }\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next();\n }\n }\n prev() {\n this._slide(ORDER_PREV);\n }\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element);\n }\n this._clearInterval();\n }\n cycle() {\n this._clearInterval();\n this._updateInterval();\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval);\n }\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return;\n }\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle());\n return;\n }\n this.cycle();\n }\n to(index) {\n const items = this._getItems();\n if (index > items.length - 1 || index < 0) {\n return;\n }\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index));\n return;\n }\n const activeIndex = this._getItemIndex(this._getActive());\n if (activeIndex === index) {\n return;\n }\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV;\n this._slide(order, items[index]);\n }\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose();\n }\n super.dispose();\n }\n\n // Private\n _configAfterMerge(config) {\n config.defaultInterval = config.interval;\n return config;\n }\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN$1, event => this._keydown(event));\n }\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER$1, () => this.pause());\n EventHandler.on(this._element, EVENT_MOUSELEAVE$1, () => this._maybeEnableCycle());\n }\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners();\n }\n }\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault());\n }\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return;\n }\n\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause();\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout);\n }\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval);\n };\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n };\n this._swipeHelper = new Swipe(this._element, swipeConfig);\n }\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return;\n }\n const direction = KEY_TO_DIRECTION[event.key];\n if (direction) {\n event.preventDefault();\n this._slide(this._directionToOrder(direction));\n }\n }\n _getItemIndex(element) {\n return this._getItems().indexOf(element);\n }\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return;\n }\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement);\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE$2);\n activeIndicator.removeAttribute('aria-current');\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement);\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE$2);\n newActiveIndicator.setAttribute('aria-current', 'true');\n }\n }\n _updateInterval() {\n const element = this._activeElement || this._getActive();\n if (!element) {\n return;\n }\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10);\n this._config.interval = elementInterval || this._config.defaultInterval;\n }\n _slide(order, element = null) {\n if (this._isSliding) {\n return;\n }\n const activeElement = this._getActive();\n const isNext = order === ORDER_NEXT;\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap);\n if (nextElement === activeElement) {\n return;\n }\n const nextElementIndex = this._getItemIndex(nextElement);\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n });\n };\n const slideEvent = triggerEvent(EVENT_SLIDE);\n if (slideEvent.defaultPrevented) {\n return;\n }\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // TODO: change tests that use empty divs to avoid this check\n return;\n }\n const isCycling = Boolean(this._interval);\n this.pause();\n this._isSliding = true;\n this._setActiveIndicatorElement(nextElementIndex);\n this._activeElement = nextElement;\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END;\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV;\n nextElement.classList.add(orderClassName);\n reflow(nextElement);\n activeElement.classList.add(directionalClassName);\n nextElement.classList.add(directionalClassName);\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName);\n nextElement.classList.add(CLASS_NAME_ACTIVE$2);\n activeElement.classList.remove(CLASS_NAME_ACTIVE$2, orderClassName, directionalClassName);\n this._isSliding = false;\n triggerEvent(EVENT_SLID);\n };\n this._queueCallback(completeCallBack, activeElement, this._isAnimated());\n if (isCycling) {\n this.cycle();\n }\n }\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE);\n }\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element);\n }\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element);\n }\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval);\n this._interval = null;\n }\n }\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT;\n }\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV;\n }\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT;\n }\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT;\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config);\n if (typeof config === 'number') {\n data.to(config);\n return;\n }\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n }\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$5, SELECTOR_DATA_SLIDE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this);\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return;\n }\n event.preventDefault();\n const carousel = Carousel.getOrCreateInstance(target);\n const slideIndex = this.getAttribute('data-bs-slide-to');\n if (slideIndex) {\n carousel.to(slideIndex);\n carousel._maybeEnableCycle();\n return;\n }\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next();\n carousel._maybeEnableCycle();\n return;\n }\n carousel.prev();\n carousel._maybeEnableCycle();\n});\nEventHandler.on(window, EVENT_LOAD_DATA_API$3, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE);\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel);\n }\n});\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$b = 'collapse';\nconst DATA_KEY$7 = 'bs.collapse';\nconst EVENT_KEY$7 = `.${DATA_KEY$7}`;\nconst DATA_API_KEY$4 = '.data-api';\nconst EVENT_SHOW$6 = `show${EVENT_KEY$7}`;\nconst EVENT_SHOWN$6 = `shown${EVENT_KEY$7}`;\nconst EVENT_HIDE$6 = `hide${EVENT_KEY$7}`;\nconst EVENT_HIDDEN$6 = `hidden${EVENT_KEY$7}`;\nconst EVENT_CLICK_DATA_API$4 = `click${EVENT_KEY$7}${DATA_API_KEY$4}`;\nconst CLASS_NAME_SHOW$7 = 'show';\nconst CLASS_NAME_COLLAPSE = 'collapse';\nconst CLASS_NAME_COLLAPSING = 'collapsing';\nconst CLASS_NAME_COLLAPSED = 'collapsed';\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`;\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal';\nconst WIDTH = 'width';\nconst HEIGHT = 'height';\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing';\nconst SELECTOR_DATA_TOGGLE$4 = '[data-bs-toggle=\"collapse\"]';\nconst Default$a = {\n parent: null,\n toggle: true\n};\nconst DefaultType$a = {\n parent: '(null|element)',\n toggle: 'boolean'\n};\n\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._isTransitioning = false;\n this._triggerArray = [];\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE$4);\n for (const elem of toggleList) {\n const selector = SelectorEngine.getSelectorFromElement(elem);\n const filterElement = SelectorEngine.find(selector).filter(foundElement => foundElement === this._element);\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem);\n }\n }\n this._initializeChildren();\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown());\n }\n if (this._config.toggle) {\n this.toggle();\n }\n }\n\n // Getters\n static get Default() {\n return Default$a;\n }\n static get DefaultType() {\n return DefaultType$a;\n }\n static get NAME() {\n return NAME$b;\n }\n\n // Public\n toggle() {\n if (this._isShown()) {\n this.hide();\n } else {\n this.show();\n }\n }\n show() {\n if (this._isTransitioning || this._isShown()) {\n return;\n }\n let activeChildren = [];\n\n // find active children\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES).filter(element => element !== this._element).map(element => Collapse.getOrCreateInstance(element, {\n toggle: false\n }));\n }\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return;\n }\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW$6);\n if (startEvent.defaultPrevented) {\n return;\n }\n for (const activeInstance of activeChildren) {\n activeInstance.hide();\n }\n const dimension = this._getDimension();\n this._element.classList.remove(CLASS_NAME_COLLAPSE);\n this._element.classList.add(CLASS_NAME_COLLAPSING);\n this._element.style[dimension] = 0;\n this._addAriaAndCollapsedClass(this._triggerArray, true);\n this._isTransitioning = true;\n const complete = () => {\n this._isTransitioning = false;\n this._element.classList.remove(CLASS_NAME_COLLAPSING);\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7);\n this._element.style[dimension] = '';\n EventHandler.trigger(this._element, EVENT_SHOWN$6);\n };\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);\n const scrollSize = `scroll${capitalizedDimension}`;\n this._queueCallback(complete, this._element, true);\n this._element.style[dimension] = `${this._element[scrollSize]}px`;\n }\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return;\n }\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE$6);\n if (startEvent.defaultPrevented) {\n return;\n }\n const dimension = this._getDimension();\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`;\n reflow(this._element);\n this._element.classList.add(CLASS_NAME_COLLAPSING);\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7);\n for (const trigger of this._triggerArray) {\n const element = SelectorEngine.getElementFromSelector(trigger);\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false);\n }\n }\n this._isTransitioning = true;\n const complete = () => {\n this._isTransitioning = false;\n this._element.classList.remove(CLASS_NAME_COLLAPSING);\n this._element.classList.add(CLASS_NAME_COLLAPSE);\n EventHandler.trigger(this._element, EVENT_HIDDEN$6);\n };\n this._element.style[dimension] = '';\n this._queueCallback(complete, this._element, true);\n }\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW$7);\n }\n\n // Private\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle); // Coerce string values\n config.parent = getElement(config.parent);\n return config;\n }\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT;\n }\n _initializeChildren() {\n if (!this._config.parent) {\n return;\n }\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE$4);\n for (const element of children) {\n const selected = SelectorEngine.getElementFromSelector(element);\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected));\n }\n }\n }\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent);\n // remove children if greater depth\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element));\n }\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return;\n }\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen);\n element.setAttribute('aria-expanded', isOpen);\n }\n }\n\n // Static\n static jQueryInterface(config) {\n const _config = {};\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false;\n }\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config);\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n }\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$4, SELECTOR_DATA_TOGGLE$4, function (event) {\n // preventDefault only for elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || event.delegateTarget && event.delegateTarget.tagName === 'A') {\n event.preventDefault();\n }\n for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\n Collapse.getOrCreateInstance(element, {\n toggle: false\n }).toggle();\n }\n});\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$a = 'dropdown';\nconst DATA_KEY$6 = 'bs.dropdown';\nconst EVENT_KEY$6 = `.${DATA_KEY$6}`;\nconst DATA_API_KEY$3 = '.data-api';\nconst ESCAPE_KEY$2 = 'Escape';\nconst TAB_KEY$1 = 'Tab';\nconst ARROW_UP_KEY$1 = 'ArrowUp';\nconst ARROW_DOWN_KEY$1 = 'ArrowDown';\nconst RIGHT_MOUSE_BUTTON = 2; // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE$5 = `hide${EVENT_KEY$6}`;\nconst EVENT_HIDDEN$5 = `hidden${EVENT_KEY$6}`;\nconst EVENT_SHOW$5 = `show${EVENT_KEY$6}`;\nconst EVENT_SHOWN$5 = `shown${EVENT_KEY$6}`;\nconst EVENT_CLICK_DATA_API$3 = `click${EVENT_KEY$6}${DATA_API_KEY$3}`;\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY$6}${DATA_API_KEY$3}`;\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY$6}${DATA_API_KEY$3}`;\nconst CLASS_NAME_SHOW$6 = 'show';\nconst CLASS_NAME_DROPUP = 'dropup';\nconst CLASS_NAME_DROPEND = 'dropend';\nconst CLASS_NAME_DROPSTART = 'dropstart';\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center';\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center';\nconst SELECTOR_DATA_TOGGLE$3 = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)';\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE$3}.${CLASS_NAME_SHOW$6}`;\nconst SELECTOR_MENU = '.dropdown-menu';\nconst SELECTOR_NAVBAR = '.navbar';\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav';\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)';\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start';\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end';\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start';\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end';\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start';\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start';\nconst PLACEMENT_TOPCENTER = 'top';\nconst PLACEMENT_BOTTOMCENTER = 'bottom';\nconst Default$9 = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n};\nconst DefaultType$9 = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n};\n\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._popper = null;\n this._parent = this._element.parentNode; // dropdown wrapper\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] || SelectorEngine.prev(this._element, SELECTOR_MENU)[0] || SelectorEngine.findOne(SELECTOR_MENU, this._parent);\n this._inNavbar = this._detectNavbar();\n }\n\n // Getters\n static get Default() {\n return Default$9;\n }\n static get DefaultType() {\n return DefaultType$9;\n }\n static get NAME() {\n return NAME$a;\n }\n\n // Public\n toggle() {\n return this._isShown() ? this.hide() : this.show();\n }\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return;\n }\n const relatedTarget = {\n relatedTarget: this._element\n };\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$5, relatedTarget);\n if (showEvent.defaultPrevented) {\n return;\n }\n this._createPopper();\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop);\n }\n }\n this._element.focus();\n this._element.setAttribute('aria-expanded', true);\n this._menu.classList.add(CLASS_NAME_SHOW$6);\n this._element.classList.add(CLASS_NAME_SHOW$6);\n EventHandler.trigger(this._element, EVENT_SHOWN$5, relatedTarget);\n }\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return;\n }\n const relatedTarget = {\n relatedTarget: this._element\n };\n this._completeHide(relatedTarget);\n }\n dispose() {\n if (this._popper) {\n this._popper.destroy();\n }\n super.dispose();\n }\n update() {\n this._inNavbar = this._detectNavbar();\n if (this._popper) {\n this._popper.update();\n }\n }\n\n // Private\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$5, relatedTarget);\n if (hideEvent.defaultPrevented) {\n return;\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop);\n }\n }\n if (this._popper) {\n this._popper.destroy();\n }\n this._menu.classList.remove(CLASS_NAME_SHOW$6);\n this._element.classList.remove(CLASS_NAME_SHOW$6);\n this._element.setAttribute('aria-expanded', 'false');\n Manipulator.removeDataAttribute(this._menu, 'popper');\n EventHandler.trigger(this._element, EVENT_HIDDEN$5, relatedTarget);\n }\n _getConfig(config) {\n config = super._getConfig(config);\n if (typeof config.reference === 'object' && !isElement(config.reference) && typeof config.reference.getBoundingClientRect !== 'function') {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME$a.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`);\n }\n return config;\n }\n _createPopper() {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org)');\n }\n let referenceElement = this._element;\n if (this._config.reference === 'parent') {\n referenceElement = this._parent;\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference);\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference;\n }\n const popperConfig = this._getPopperConfig();\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig);\n }\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW$6);\n }\n _getPlacement() {\n const parentDropdown = this._parent;\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT;\n }\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT;\n }\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER;\n }\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER;\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end';\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP;\n }\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM;\n }\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null;\n }\n _getOffset() {\n const {\n offset\n } = this._config;\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10));\n }\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element);\n }\n return offset;\n }\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n }, {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n };\n\n // Disable Popper if we have a static display or Dropdown is in Navbar\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static'); // TODO: v6 remove\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }];\n }\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n };\n }\n _selectMenuItem({\n key,\n target\n }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element));\n if (!items.length) {\n return;\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY$1, !items.includes(target)).focus();\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n });\n }\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY$1) {\n return;\n }\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN);\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle);\n if (!context || context._config.autoClose === false) {\n continue;\n }\n const composedPath = event.composedPath();\n const isMenuTarget = composedPath.includes(context._menu);\n if (composedPath.includes(context._element) || context._config.autoClose === 'inside' && !isMenuTarget || context._config.autoClose === 'outside' && isMenuTarget) {\n continue;\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && (event.type === 'keyup' && event.key === TAB_KEY$1 || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue;\n }\n const relatedTarget = {\n relatedTarget: context._element\n };\n if (event.type === 'click') {\n relatedTarget.clickEvent = event;\n }\n context._completeHide(relatedTarget);\n }\n }\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n\n const isInput = /input|textarea/i.test(event.target.tagName);\n const isEscapeEvent = event.key === ESCAPE_KEY$2;\n const isUpOrDownEvent = [ARROW_UP_KEY$1, ARROW_DOWN_KEY$1].includes(event.key);\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return;\n }\n if (isInput && !isEscapeEvent) {\n return;\n }\n event.preventDefault();\n\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE$3) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.next(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.findOne(SELECTOR_DATA_TOGGLE$3, event.delegateTarget.parentNode);\n const instance = Dropdown.getOrCreateInstance(getToggleButton);\n if (isUpOrDownEvent) {\n event.stopPropagation();\n instance.show();\n instance._selectMenuItem(event);\n return;\n }\n if (instance._isShown()) {\n // else is escape and we check if it is shown\n event.stopPropagation();\n instance.hide();\n getToggleButton.focus();\n }\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE$3, Dropdown.dataApiKeydownHandler);\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler);\nEventHandler.on(document, EVENT_CLICK_DATA_API$3, Dropdown.clearMenus);\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus);\nEventHandler.on(document, EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$3, function (event) {\n event.preventDefault();\n Dropdown.getOrCreateInstance(this).toggle();\n});\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$9 = 'backdrop';\nconst CLASS_NAME_FADE$4 = 'fade';\nconst CLASS_NAME_SHOW$5 = 'show';\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME$9}`;\nconst Default$8 = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true,\n // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n};\nconst DefaultType$8 = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n};\n\n/**\n * Class definition\n */\n\nclass Backdrop extends Config {\n constructor(config) {\n super();\n this._config = this._getConfig(config);\n this._isAppended = false;\n this._element = null;\n }\n\n // Getters\n static get Default() {\n return Default$8;\n }\n static get DefaultType() {\n return DefaultType$8;\n }\n static get NAME() {\n return NAME$9;\n }\n\n // Public\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback);\n return;\n }\n this._append();\n const element = this._getElement();\n if (this._config.isAnimated) {\n reflow(element);\n }\n element.classList.add(CLASS_NAME_SHOW$5);\n this._emulateAnimation(() => {\n execute(callback);\n });\n }\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback);\n return;\n }\n this._getElement().classList.remove(CLASS_NAME_SHOW$5);\n this._emulateAnimation(() => {\n this.dispose();\n execute(callback);\n });\n }\n dispose() {\n if (!this._isAppended) {\n return;\n }\n EventHandler.off(this._element, EVENT_MOUSEDOWN);\n this._element.remove();\n this._isAppended = false;\n }\n\n // Private\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div');\n backdrop.className = this._config.className;\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE$4);\n }\n this._element = backdrop;\n }\n return this._element;\n }\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement);\n return config;\n }\n _append() {\n if (this._isAppended) {\n return;\n }\n const element = this._getElement();\n this._config.rootElement.append(element);\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback);\n });\n this._isAppended = true;\n }\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated);\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$8 = 'focustrap';\nconst DATA_KEY$5 = 'bs.focustrap';\nconst EVENT_KEY$5 = `.${DATA_KEY$5}`;\nconst EVENT_FOCUSIN$2 = `focusin${EVENT_KEY$5}`;\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$5}`;\nconst TAB_KEY = 'Tab';\nconst TAB_NAV_FORWARD = 'forward';\nconst TAB_NAV_BACKWARD = 'backward';\nconst Default$7 = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n};\nconst DefaultType$7 = {\n autofocus: 'boolean',\n trapElement: 'element'\n};\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super();\n this._config = this._getConfig(config);\n this._isActive = false;\n this._lastTabNavDirection = null;\n }\n\n // Getters\n static get Default() {\n return Default$7;\n }\n static get DefaultType() {\n return DefaultType$7;\n }\n static get NAME() {\n return NAME$8;\n }\n\n // Public\n activate() {\n if (this._isActive) {\n return;\n }\n if (this._config.autofocus) {\n this._config.trapElement.focus();\n }\n EventHandler.off(document, EVENT_KEY$5); // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN$2, event => this._handleFocusin(event));\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event));\n this._isActive = true;\n }\n deactivate() {\n if (!this._isActive) {\n return;\n }\n this._isActive = false;\n EventHandler.off(document, EVENT_KEY$5);\n }\n\n // Private\n _handleFocusin(event) {\n const {\n trapElement\n } = this._config;\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return;\n }\n const elements = SelectorEngine.focusableChildren(trapElement);\n if (elements.length === 0) {\n trapElement.focus();\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus();\n } else {\n elements[0].focus();\n }\n }\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return;\n }\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD;\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';\nconst SELECTOR_STICKY_CONTENT = '.sticky-top';\nconst PROPERTY_PADDING = 'padding-right';\nconst PROPERTY_MARGIN = 'margin-right';\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body;\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth;\n return Math.abs(window.innerWidth - documentWidth);\n }\n hide() {\n const width = this.getWidth();\n this._disableOverFlow();\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width);\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width);\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width);\n }\n reset() {\n this._resetElementAttributes(this._element, 'overflow');\n this._resetElementAttributes(this._element, PROPERTY_PADDING);\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING);\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN);\n }\n isOverflowing() {\n return this.getWidth() > 0;\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow');\n this._element.style.overflow = 'hidden';\n }\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth();\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return;\n }\n this._saveInitialAttribute(element, styleProperty);\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty);\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`);\n };\n this._applyManipulationCallback(selector, manipulationCallBack);\n }\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty);\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue);\n }\n }\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty);\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty);\n return;\n }\n Manipulator.removeDataAttribute(element, styleProperty);\n element.style.setProperty(styleProperty, value);\n };\n this._applyManipulationCallback(selector, manipulationCallBack);\n }\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector);\n return;\n }\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel);\n }\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$7 = 'modal';\nconst DATA_KEY$4 = 'bs.modal';\nconst EVENT_KEY$4 = `.${DATA_KEY$4}`;\nconst DATA_API_KEY$2 = '.data-api';\nconst ESCAPE_KEY$1 = 'Escape';\nconst EVENT_HIDE$4 = `hide${EVENT_KEY$4}`;\nconst EVENT_HIDE_PREVENTED$1 = `hidePrevented${EVENT_KEY$4}`;\nconst EVENT_HIDDEN$4 = `hidden${EVENT_KEY$4}`;\nconst EVENT_SHOW$4 = `show${EVENT_KEY$4}`;\nconst EVENT_SHOWN$4 = `shown${EVENT_KEY$4}`;\nconst EVENT_RESIZE$1 = `resize${EVENT_KEY$4}`;\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY$4}`;\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY$4}`;\nconst EVENT_KEYDOWN_DISMISS$1 = `keydown.dismiss${EVENT_KEY$4}`;\nconst EVENT_CLICK_DATA_API$2 = `click${EVENT_KEY$4}${DATA_API_KEY$2}`;\nconst CLASS_NAME_OPEN = 'modal-open';\nconst CLASS_NAME_FADE$3 = 'fade';\nconst CLASS_NAME_SHOW$4 = 'show';\nconst CLASS_NAME_STATIC = 'modal-static';\nconst OPEN_SELECTOR$1 = '.modal.show';\nconst SELECTOR_DIALOG = '.modal-dialog';\nconst SELECTOR_MODAL_BODY = '.modal-body';\nconst SELECTOR_DATA_TOGGLE$2 = '[data-bs-toggle=\"modal\"]';\nconst Default$6 = {\n backdrop: true,\n focus: true,\n keyboard: true\n};\nconst DefaultType$6 = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n};\n\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element);\n this._backdrop = this._initializeBackDrop();\n this._focustrap = this._initializeFocusTrap();\n this._isShown = false;\n this._isTransitioning = false;\n this._scrollBar = new ScrollBarHelper();\n this._addEventListeners();\n }\n\n // Getters\n static get Default() {\n return Default$6;\n }\n static get DefaultType() {\n return DefaultType$6;\n }\n static get NAME() {\n return NAME$7;\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget);\n }\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return;\n }\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$4, {\n relatedTarget\n });\n if (showEvent.defaultPrevented) {\n return;\n }\n this._isShown = true;\n this._isTransitioning = true;\n this._scrollBar.hide();\n document.body.classList.add(CLASS_NAME_OPEN);\n this._adjustDialog();\n this._backdrop.show(() => this._showElement(relatedTarget));\n }\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return;\n }\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$4);\n if (hideEvent.defaultPrevented) {\n return;\n }\n this._isShown = false;\n this._isTransitioning = true;\n this._focustrap.deactivate();\n this._element.classList.remove(CLASS_NAME_SHOW$4);\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated());\n }\n dispose() {\n EventHandler.off(window, EVENT_KEY$4);\n EventHandler.off(this._dialog, EVENT_KEY$4);\n this._backdrop.dispose();\n this._focustrap.deactivate();\n super.dispose();\n }\n handleUpdate() {\n this._adjustDialog();\n }\n\n // Private\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop),\n // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n });\n }\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n });\n }\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element);\n }\n this._element.style.display = 'block';\n this._element.removeAttribute('aria-hidden');\n this._element.setAttribute('aria-modal', true);\n this._element.setAttribute('role', 'dialog');\n this._element.scrollTop = 0;\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog);\n if (modalBody) {\n modalBody.scrollTop = 0;\n }\n reflow(this._element);\n this._element.classList.add(CLASS_NAME_SHOW$4);\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate();\n }\n this._isTransitioning = false;\n EventHandler.trigger(this._element, EVENT_SHOWN$4, {\n relatedTarget\n });\n };\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated());\n }\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS$1, event => {\n if (event.key !== ESCAPE_KEY$1) {\n return;\n }\n if (this._config.keyboard) {\n this.hide();\n return;\n }\n this._triggerBackdropTransition();\n });\n EventHandler.on(window, EVENT_RESIZE$1, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog();\n }\n });\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return;\n }\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition();\n return;\n }\n if (this._config.backdrop) {\n this.hide();\n }\n });\n });\n }\n _hideModal() {\n this._element.style.display = 'none';\n this._element.setAttribute('aria-hidden', true);\n this._element.removeAttribute('aria-modal');\n this._element.removeAttribute('role');\n this._isTransitioning = false;\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN);\n this._resetAdjustments();\n this._scrollBar.reset();\n EventHandler.trigger(this._element, EVENT_HIDDEN$4);\n });\n }\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE$3);\n }\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED$1);\n if (hideEvent.defaultPrevented) {\n return;\n }\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n const initialOverflowY = this._element.style.overflowY;\n // return if the following background transition hasn't yet completed\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return;\n }\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden';\n }\n this._element.classList.add(CLASS_NAME_STATIC);\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC);\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY;\n }, this._dialog);\n }, this._dialog);\n this._element.focus();\n }\n\n /**\n * The following methods are used to handle overflowing modals\n */\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n const scrollbarWidth = this._scrollBar.getWidth();\n const isBodyOverflowing = scrollbarWidth > 0;\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight';\n this._element.style[property] = `${scrollbarWidth}px`;\n }\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft';\n this._element.style[property] = `${scrollbarWidth}px`;\n }\n }\n _resetAdjustments() {\n this._element.style.paddingLeft = '';\n this._element.style.paddingRight = '';\n }\n\n // Static\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config](relatedTarget);\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$2, SELECTOR_DATA_TOGGLE$2, function (event) {\n const target = SelectorEngine.getElementFromSelector(this);\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault();\n }\n EventHandler.one(target, EVENT_SHOW$4, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return;\n }\n EventHandler.one(target, EVENT_HIDDEN$4, () => {\n if (isVisible(this)) {\n this.focus();\n }\n });\n });\n\n // avoid conflict when clicking modal toggler while another one is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR$1);\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide();\n }\n const data = Modal.getOrCreateInstance(target);\n data.toggle(this);\n});\nenableDismissTrigger(Modal);\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$6 = 'offcanvas';\nconst DATA_KEY$3 = 'bs.offcanvas';\nconst EVENT_KEY$3 = `.${DATA_KEY$3}`;\nconst DATA_API_KEY$1 = '.data-api';\nconst EVENT_LOAD_DATA_API$2 = `load${EVENT_KEY$3}${DATA_API_KEY$1}`;\nconst ESCAPE_KEY = 'Escape';\nconst CLASS_NAME_SHOW$3 = 'show';\nconst CLASS_NAME_SHOWING$1 = 'showing';\nconst CLASS_NAME_HIDING = 'hiding';\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop';\nconst OPEN_SELECTOR = '.offcanvas.show';\nconst EVENT_SHOW$3 = `show${EVENT_KEY$3}`;\nconst EVENT_SHOWN$3 = `shown${EVENT_KEY$3}`;\nconst EVENT_HIDE$3 = `hide${EVENT_KEY$3}`;\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY$3}`;\nconst EVENT_HIDDEN$3 = `hidden${EVENT_KEY$3}`;\nconst EVENT_RESIZE = `resize${EVENT_KEY$3}`;\nconst EVENT_CLICK_DATA_API$1 = `click${EVENT_KEY$3}${DATA_API_KEY$1}`;\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY$3}`;\nconst SELECTOR_DATA_TOGGLE$1 = '[data-bs-toggle=\"offcanvas\"]';\nconst Default$5 = {\n backdrop: true,\n keyboard: true,\n scroll: false\n};\nconst DefaultType$5 = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n};\n\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._isShown = false;\n this._backdrop = this._initializeBackDrop();\n this._focustrap = this._initializeFocusTrap();\n this._addEventListeners();\n }\n\n // Getters\n static get Default() {\n return Default$5;\n }\n static get DefaultType() {\n return DefaultType$5;\n }\n static get NAME() {\n return NAME$6;\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget);\n }\n show(relatedTarget) {\n if (this._isShown) {\n return;\n }\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$3, {\n relatedTarget\n });\n if (showEvent.defaultPrevented) {\n return;\n }\n this._isShown = true;\n this._backdrop.show();\n if (!this._config.scroll) {\n new ScrollBarHelper().hide();\n }\n this._element.setAttribute('aria-modal', true);\n this._element.setAttribute('role', 'dialog');\n this._element.classList.add(CLASS_NAME_SHOWING$1);\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate();\n }\n this._element.classList.add(CLASS_NAME_SHOW$3);\n this._element.classList.remove(CLASS_NAME_SHOWING$1);\n EventHandler.trigger(this._element, EVENT_SHOWN$3, {\n relatedTarget\n });\n };\n this._queueCallback(completeCallBack, this._element, true);\n }\n hide() {\n if (!this._isShown) {\n return;\n }\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$3);\n if (hideEvent.defaultPrevented) {\n return;\n }\n this._focustrap.deactivate();\n this._element.blur();\n this._isShown = false;\n this._element.classList.add(CLASS_NAME_HIDING);\n this._backdrop.hide();\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW$3, CLASS_NAME_HIDING);\n this._element.removeAttribute('aria-modal');\n this._element.removeAttribute('role');\n if (!this._config.scroll) {\n new ScrollBarHelper().reset();\n }\n EventHandler.trigger(this._element, EVENT_HIDDEN$3);\n };\n this._queueCallback(completeCallback, this._element, true);\n }\n dispose() {\n this._backdrop.dispose();\n this._focustrap.deactivate();\n super.dispose();\n }\n\n // Private\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);\n return;\n }\n this.hide();\n };\n\n // 'static' option will be translated to true, and booleans will keep their value\n const isVisible = Boolean(this._config.backdrop);\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n });\n }\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n });\n }\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return;\n }\n if (this._config.keyboard) {\n this.hide();\n return;\n }\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);\n });\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config](this);\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$1, SELECTOR_DATA_TOGGLE$1, function (event) {\n const target = SelectorEngine.getElementFromSelector(this);\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault();\n }\n if (isDisabled(this)) {\n return;\n }\n EventHandler.one(target, EVENT_HIDDEN$3, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus();\n }\n });\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR);\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide();\n }\n const data = Offcanvas.getOrCreateInstance(target);\n data.toggle(this);\n});\nEventHandler.on(window, EVENT_LOAD_DATA_API$2, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show();\n }\n});\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide();\n }\n }\n});\nenableDismissTrigger(Offcanvas);\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n// js-docs-start allow-list\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i;\nconst DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n dd: [],\n div: [],\n dl: [],\n dt: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n};\n// js-docs-end allow-list\n\nconst uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);\n\n/**\n * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation\n * contexts.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38\n */\n// eslint-disable-next-line unicorn/better-regex\nconst SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i;\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase();\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue));\n }\n return true;\n }\n\n // Check if a regular expression validates the attribute.\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName));\n};\nfunction sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml;\n }\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml);\n }\n const domParser = new window.DOMParser();\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'));\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase();\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove();\n continue;\n }\n const attributeList = [].concat(...element.attributes);\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []);\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName);\n }\n }\n }\n return createdDocument.body.innerHTML;\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$5 = 'TemplateFactory';\nconst Default$4 = {\n allowList: DefaultAllowlist,\n content: {},\n // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '
'\n};\nconst DefaultType$4 = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n};\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n};\n\n/**\n * Class definition\n */\n\nclass TemplateFactory extends Config {\n constructor(config) {\n super();\n this._config = this._getConfig(config);\n }\n\n // Getters\n static get Default() {\n return Default$4;\n }\n static get DefaultType() {\n return DefaultType$4;\n }\n static get NAME() {\n return NAME$5;\n }\n\n // Public\n getContent() {\n return Object.values(this._config.content).map(config => this._resolvePossibleFunction(config)).filter(Boolean);\n }\n hasContent() {\n return this.getContent().length > 0;\n }\n changeContent(content) {\n this._checkContent(content);\n this._config.content = {\n ...this._config.content,\n ...content\n };\n return this;\n }\n toHtml() {\n const templateWrapper = document.createElement('div');\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template);\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector);\n }\n const template = templateWrapper.children[0];\n const extraClass = this._resolvePossibleFunction(this._config.extraClass);\n if (extraClass) {\n template.classList.add(...extraClass.split(' '));\n }\n return template;\n }\n\n // Private\n _typeCheckConfig(config) {\n super._typeCheckConfig(config);\n this._checkContent(config.content);\n }\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({\n selector,\n entry: content\n }, DefaultContentType);\n }\n }\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template);\n if (!templateElement) {\n return;\n }\n content = this._resolvePossibleFunction(content);\n if (!content) {\n templateElement.remove();\n return;\n }\n if (isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement);\n return;\n }\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content);\n return;\n }\n templateElement.textContent = content;\n }\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg;\n }\n _resolvePossibleFunction(arg) {\n return execute(arg, [this]);\n }\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = '';\n templateElement.append(element);\n return;\n }\n templateElement.textContent = element.textContent;\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$4 = 'tooltip';\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']);\nconst CLASS_NAME_FADE$2 = 'fade';\nconst CLASS_NAME_MODAL = 'modal';\nconst CLASS_NAME_SHOW$2 = 'show';\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner';\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`;\nconst EVENT_MODAL_HIDE = 'hide.bs.modal';\nconst TRIGGER_HOVER = 'hover';\nconst TRIGGER_FOCUS = 'focus';\nconst TRIGGER_CLICK = 'click';\nconst TRIGGER_MANUAL = 'manual';\nconst EVENT_HIDE$2 = 'hide';\nconst EVENT_HIDDEN$2 = 'hidden';\nconst EVENT_SHOW$2 = 'show';\nconst EVENT_SHOWN$2 = 'shown';\nconst EVENT_INSERTED = 'inserted';\nconst EVENT_CLICK$1 = 'click';\nconst EVENT_FOCUSIN$1 = 'focusin';\nconst EVENT_FOCUSOUT$1 = 'focusout';\nconst EVENT_MOUSEENTER = 'mouseenter';\nconst EVENT_MOUSELEAVE = 'mouseleave';\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n};\nconst Default$3 = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 6],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '
' + '
' + '
' + '
',\n title: '',\n trigger: 'hover focus'\n};\nconst DefaultType$3 = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n};\n\n/**\n * Class definition\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org)');\n }\n super(element, config);\n\n // Private\n this._isEnabled = true;\n this._timeout = 0;\n this._isHovered = null;\n this._activeTrigger = {};\n this._popper = null;\n this._templateFactory = null;\n this._newContent = null;\n\n // Protected\n this.tip = null;\n this._setListeners();\n if (!this._config.selector) {\n this._fixTitle();\n }\n }\n\n // Getters\n static get Default() {\n return Default$3;\n }\n static get DefaultType() {\n return DefaultType$3;\n }\n static get NAME() {\n return NAME$4;\n }\n\n // Public\n enable() {\n this._isEnabled = true;\n }\n disable() {\n this._isEnabled = false;\n }\n toggleEnabled() {\n this._isEnabled = !this._isEnabled;\n }\n toggle() {\n if (!this._isEnabled) {\n return;\n }\n this._activeTrigger.click = !this._activeTrigger.click;\n if (this._isShown()) {\n this._leave();\n return;\n }\n this._enter();\n }\n dispose() {\n clearTimeout(this._timeout);\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler);\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'));\n }\n this._disposePopper();\n super.dispose();\n }\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements');\n }\n if (!(this._isWithContent() && this._isEnabled)) {\n return;\n }\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW$2));\n const shadowRoot = findShadowRoot(this._element);\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element);\n if (showEvent.defaultPrevented || !isInTheDom) {\n return;\n }\n\n // TODO: v6 remove this or make it optional\n this._disposePopper();\n const tip = this._getTipElement();\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'));\n const {\n container\n } = this._config;\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip);\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED));\n }\n this._popper = this._createPopper(tip);\n tip.classList.add(CLASS_NAME_SHOW$2);\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop);\n }\n }\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN$2));\n if (this._isHovered === false) {\n this._leave();\n }\n this._isHovered = false;\n };\n this._queueCallback(complete, this.tip, this._isAnimated());\n }\n hide() {\n if (!this._isShown()) {\n return;\n }\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE$2));\n if (hideEvent.defaultPrevented) {\n return;\n }\n const tip = this._getTipElement();\n tip.classList.remove(CLASS_NAME_SHOW$2);\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop);\n }\n }\n this._activeTrigger[TRIGGER_CLICK] = false;\n this._activeTrigger[TRIGGER_FOCUS] = false;\n this._activeTrigger[TRIGGER_HOVER] = false;\n this._isHovered = null; // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return;\n }\n if (!this._isHovered) {\n this._disposePopper();\n }\n this._element.removeAttribute('aria-describedby');\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN$2));\n };\n this._queueCallback(complete, this.tip, this._isAnimated());\n }\n update() {\n if (this._popper) {\n this._popper.update();\n }\n }\n\n // Protected\n _isWithContent() {\n return Boolean(this._getTitle());\n }\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate());\n }\n return this.tip;\n }\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml();\n\n // TODO: remove this check in v6\n if (!tip) {\n return null;\n }\n tip.classList.remove(CLASS_NAME_FADE$2, CLASS_NAME_SHOW$2);\n // TODO: v6 the following can be achieved with CSS only\n tip.classList.add(`bs-${this.constructor.NAME}-auto`);\n const tipId = getUID(this.constructor.NAME).toString();\n tip.setAttribute('id', tipId);\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE$2);\n }\n return tip;\n }\n setContent(content) {\n this._newContent = content;\n if (this._isShown()) {\n this._disposePopper();\n this.show();\n }\n }\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content);\n } else {\n this._templateFactory = new TemplateFactory({\n ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n });\n }\n return this._templateFactory;\n }\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n };\n }\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title');\n }\n\n // Private\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig());\n }\n _isAnimated() {\n return this._config.animation || this.tip && this.tip.classList.contains(CLASS_NAME_FADE$2);\n }\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW$2);\n }\n _createPopper(tip) {\n const placement = execute(this._config.placement, [this, tip, this._element]);\n const attachment = AttachmentMap[placement.toUpperCase()];\n return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment));\n }\n _getOffset() {\n const {\n offset\n } = this._config;\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10));\n }\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element);\n }\n return offset;\n }\n _resolvePossibleFunction(arg) {\n return execute(arg, [this._element]);\n }\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [{\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n }, {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }, {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n }, {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n }, {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement);\n }\n }]\n };\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n };\n }\n _setListeners() {\n const triggers = this._config.trigger.split(' ');\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK$1), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event);\n context.toggle();\n });\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSEENTER) : this.constructor.eventName(EVENT_FOCUSIN$1);\n const eventOut = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSELEAVE) : this.constructor.eventName(EVENT_FOCUSOUT$1);\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event);\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true;\n context._enter();\n });\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event);\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._element.contains(event.relatedTarget);\n context._leave();\n });\n }\n }\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide();\n }\n };\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler);\n }\n _fixTitle() {\n const title = this._element.getAttribute('title');\n if (!title) {\n return;\n }\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title);\n }\n this._element.setAttribute('data-bs-original-title', title); // DO NOT USE IT. Is only for backwards compatibility\n this._element.removeAttribute('title');\n }\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true;\n return;\n }\n this._isHovered = true;\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show();\n }\n }, this._config.delay.show);\n }\n _leave() {\n if (this._isWithActiveTrigger()) {\n return;\n }\n this._isHovered = false;\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide();\n }\n }, this._config.delay.hide);\n }\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout);\n this._timeout = setTimeout(handler, timeout);\n }\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true);\n }\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element);\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute];\n }\n }\n config = {\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n };\n config = this._mergeConfigObj(config);\n config = this._configAfterMerge(config);\n this._typeCheckConfig(config);\n return config;\n }\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container);\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n };\n }\n if (typeof config.title === 'number') {\n config.title = config.title.toString();\n }\n if (typeof config.content === 'number') {\n config.content = config.content.toString();\n }\n return config;\n }\n _getDelegateConfig() {\n const config = {};\n for (const [key, value] of Object.entries(this._config)) {\n if (this.constructor.Default[key] !== value) {\n config[key] = value;\n }\n }\n config.selector = false;\n config.trigger = 'manual';\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config;\n }\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy();\n this._popper = null;\n }\n if (this.tip) {\n this.tip.remove();\n this.tip = null;\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n });\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tooltip);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$3 = 'popover';\nconst SELECTOR_TITLE = '.popover-header';\nconst SELECTOR_CONTENT = '.popover-body';\nconst Default$2 = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '
' + '
' + '

' + '
' + '
',\n trigger: 'click'\n};\nconst DefaultType$2 = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n};\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default$2;\n }\n static get DefaultType() {\n return DefaultType$2;\n }\n static get NAME() {\n return NAME$3;\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent();\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n };\n }\n _getContent() {\n return this._resolvePossibleFunction(this._config.content);\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n });\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$2 = 'scrollspy';\nconst DATA_KEY$2 = 'bs.scrollspy';\nconst EVENT_KEY$2 = `.${DATA_KEY$2}`;\nconst DATA_API_KEY = '.data-api';\nconst EVENT_ACTIVATE = `activate${EVENT_KEY$2}`;\nconst EVENT_CLICK = `click${EVENT_KEY$2}`;\nconst EVENT_LOAD_DATA_API$1 = `load${EVENT_KEY$2}${DATA_API_KEY}`;\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';\nconst CLASS_NAME_ACTIVE$1 = 'active';\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]';\nconst SELECTOR_TARGET_LINKS = '[href]';\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';\nconst SELECTOR_NAV_LINKS = '.nav-link';\nconst SELECTOR_NAV_ITEMS = '.nav-item';\nconst SELECTOR_LIST_ITEMS = '.list-group-item';\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`;\nconst SELECTOR_DROPDOWN = '.dropdown';\nconst SELECTOR_DROPDOWN_TOGGLE$1 = '.dropdown-toggle';\nconst Default$1 = {\n offset: null,\n // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n};\nconst DefaultType$1 = {\n offset: '(number|null)',\n // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n};\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n\n // this._element is the observablesContainer and config.target the menu links wrapper\n this._targetLinks = new Map();\n this._observableSections = new Map();\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element;\n this._activeTarget = null;\n this._observer = null;\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n };\n this.refresh(); // initialize\n }\n\n // Getters\n static get Default() {\n return Default$1;\n }\n static get DefaultType() {\n return DefaultType$1;\n }\n static get NAME() {\n return NAME$2;\n }\n\n // Public\n refresh() {\n this._initializeTargetsAndObservables();\n this._maybeEnableSmoothScroll();\n if (this._observer) {\n this._observer.disconnect();\n } else {\n this._observer = this._getNewObserver();\n }\n for (const section of this._observableSections.values()) {\n this._observer.observe(section);\n }\n }\n dispose() {\n this._observer.disconnect();\n super.dispose();\n }\n\n // Private\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body;\n\n // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin;\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value));\n }\n return config;\n }\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return;\n }\n\n // unregister any previous listeners\n EventHandler.off(this._config.target, EVENT_CLICK);\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash);\n if (observableSection) {\n event.preventDefault();\n const root = this._rootElement || window;\n const height = observableSection.offsetTop - this._element.offsetTop;\n if (root.scrollTo) {\n root.scrollTo({\n top: height,\n behavior: 'smooth'\n });\n return;\n }\n\n // Chrome 60 doesn't support `scrollTo`\n root.scrollTop = height;\n }\n });\n }\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n };\n return new IntersectionObserver(entries => this._observerCallback(entries), options);\n }\n\n // The logic of selection\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`);\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop;\n this._process(targetElement(entry));\n };\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop;\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop;\n this._previousScrollData.parentScrollTop = parentScrollTop;\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null;\n this._clearActiveClass(targetElement(entry));\n continue;\n }\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop;\n // if we are scrolling down, pick the bigger offsetTop\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry);\n // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n if (!parentScrollTop) {\n return;\n }\n continue;\n }\n\n // if we are scrolling up, pick the smallest offsetTop\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry);\n }\n }\n }\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map();\n this._observableSections = new Map();\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target);\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue;\n }\n const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element);\n\n // ensure that the observableSection exists & is visible\n if (isVisible(observableSection)) {\n this._targetLinks.set(decodeURI(anchor.hash), anchor);\n this._observableSections.set(anchor.hash, observableSection);\n }\n }\n }\n _process(target) {\n if (this._activeTarget === target) {\n return;\n }\n this._clearActiveClass(this._config.target);\n this._activeTarget = target;\n target.classList.add(CLASS_NAME_ACTIVE$1);\n this._activateParents(target);\n EventHandler.trigger(this._element, EVENT_ACTIVATE, {\n relatedTarget: target\n });\n }\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE$1, target.closest(SELECTOR_DROPDOWN)).classList.add(CLASS_NAME_ACTIVE$1);\n return;\n }\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both